├── .github
└── workflows
│ ├── build.yml
│ └── golangcli-lint.yml
├── .gitignore
├── .golangci.yml
├── Makefile
├── app
├── ante.go
├── app.go
├── encoding.go
├── export.go
├── genesis.go
├── ica_sim_helper.go
├── keepers
│ ├── keepers.go
│ └── keys.go
├── modules.go
├── params
│ ├── amino.go
│ ├── doc.go
│ ├── encoding.go
│ ├── params.go
│ ├── proto.go
│ └── weights.go
├── simulation_test.go
├── test_helpers.go
├── upgrades
│ ├── types.go
│ ├── v2
│ │ ├── constants.go
│ │ └── upgrades.go
│ ├── v3
│ │ ├── constants.go
│ │ └── upgrades.go
│ ├── v301
│ │ ├── constants.go
│ │ └── upgrades.go
│ └── v303
│ │ ├── constants.go
│ │ └── upgrades.go
└── wasm_config.go
├── cmd
├── mund-manager
│ ├── lib
│ │ ├── args.go
│ │ ├── process.go
│ │ ├── scanner.go
│ │ └── upgrade.go
│ └── main.go
└── mund
│ ├── cmd
│ ├── config.go
│ ├── genaccounts.go
│ └── root.go
│ ├── genwasm.go
│ └── main.go
├── config.yml
├── docs
├── docs.go
├── static
│ └── openapi.yml
└── template
│ └── index.tpl
├── go.mod
├── go.sum
├── internal
├── ante
│ └── min_commission.go
├── statesync
│ └── snapshotter.go
└── wasm
│ ├── distribution.go
│ ├── encoder.go
│ └── registry.go
├── mupgrade.sh
├── proto
├── claim
│ └── v1beta1
│ │ ├── claim_record.proto
│ │ ├── genesis.proto
│ │ ├── params.proto
│ │ ├── query.proto
│ │ └── tx.proto
└── ibank
│ ├── genesis.proto
│ ├── params.proto
│ ├── query.proto
│ ├── transaction.proto
│ └── tx.proto
├── readme.md
├── testutil
└── nullify
│ └── nullify.go
├── upgrade.md
└── x
├── claim
├── abci.go
├── client
│ └── cli
│ │ ├── query.go
│ │ ├── tx.go
│ │ ├── tx_claim_for.go
│ │ └── tx_update_merkle_root.go
├── handler.go
├── keeper
│ ├── claim.go
│ ├── genesis.go
│ ├── grpc_query.go
│ ├── grpc_query_merkle.go
│ ├── hooks.go
│ ├── keeper.go
│ ├── merkle.go
│ ├── msg_server.go
│ ├── msg_server_claim_for.go
│ ├── msg_server_update_merkle_root.go
│ └── params.go
├── module.go
├── module_simulation.go
├── simulation
│ ├── decoder.go
│ ├── decoder_test.go
│ ├── genesis.go
│ ├── genesis_test.go
│ ├── operations.go
│ ├── params.go
│ └── params_test.go
└── types
│ ├── claim_record.pb.go
│ ├── codec.go
│ ├── errors.go
│ ├── events.go
│ ├── expected_keepers.go
│ ├── genesis.go
│ ├── genesis.pb.go
│ ├── genesis_test.go
│ ├── keys.go
│ ├── message_claim_for.go
│ ├── message_update_merkle_root.go
│ ├── params.go
│ ├── params.pb.go
│ ├── query.pb.go
│ ├── query.pb.gw.go
│ ├── tx.pb.go
│ ├── tx_test.go
│ └── types.go
└── ibank
├── README.md
├── abci.go
├── client
└── cli
│ ├── query.go
│ ├── query_params.go
│ ├── query_show_incoming.go
│ ├── query_show_outgoing.go
│ ├── query_transaction.go
│ ├── tx.go
│ ├── tx_receive.go
│ └── tx_send.go
├── genesis.go
├── keeper
├── grpc_query.go
├── grpc_query_params.go
├── grpc_query_show_incoming.go
├── grpc_query_show_outgoing.go
├── grpc_query_transaction.go
├── keeper.go
├── keeper_test.go
├── msg_server.go
├── msg_server_receive.go
├── msg_server_send.go
├── params.go
└── transaction.go
├── module.go
├── module_simulation.go
├── simulation
├── decoder.go
├── decoder_test.go
├── genesis.go
├── genesis_test.go
├── helpers.go
├── operations.go
└── params.go
└── types
├── codec.go
├── errors.go
├── events.go
├── expected_keepers.go
├── genesis.go
├── genesis.pb.go
├── genesis_test.go
├── keys.go
├── message_receive.go
├── message_send.go
├── params.go
├── params.pb.go
├── query.pb.go
├── query.pb.gw.go
├── transaction.pb.go
├── tx.pb.go
└── types.go
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Compile MUN
2 |
3 | on:
4 | pull_request:
5 | push:
6 | branches:
7 | - main
8 | - master
9 | workflow_dispatch:
10 |
11 | jobs:
12 | build:
13 | runs-on: ubuntu-latest
14 | name: build
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Setup go
18 | uses: actions/setup-go@v3
19 | with:
20 | go-version: 1.19.0
21 | - run: make build
22 |
23 | test:
24 | runs-on: ubuntu-latest
25 | name: test
26 | steps:
27 | - name: Install Go
28 | uses: actions/setup-go@v3
29 | with:
30 | go-version: 1.19.0
31 | - name: Checkout code
32 | uses: actions/checkout@v3
33 | - name: Test
34 | run: go test ./...
35 |
--------------------------------------------------------------------------------
/.github/workflows/golangcli-lint.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: golangci-lint
3 | on:
4 | push:
5 | tags:
6 | - v*
7 | branches:
8 | - master
9 | - main
10 | pull_request:
11 | paths:
12 | - '**.go'
13 |
14 | permissions:
15 | contents: read
16 | # Optional: allow read access to pull request. Use with `only-new-issues` option.
17 | # pull-requests: read
18 |
19 | concurrency:
20 | group: ${{ github.workflow }}-${{ github.ref }}
21 | cancel-in-progress: true
22 |
23 | jobs:
24 | golangci:
25 | name: lint
26 | runs-on: ubuntu-latest
27 | steps:
28 | - uses: actions/setup-go@v3
29 | with:
30 | go-version: 1.19.0
31 | - uses: actions/checkout@v3
32 |
33 | - name: golangci-lint-mund
34 | uses: golangci/golangci-lint-action@v3
35 | with:
36 | version: latest
37 | args: --timeout 10m
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vue/
2 | ts-client/
3 | release/
4 | build/
5 | .idea/
6 | .vscode/
7 | .DS_Store
8 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | tests: false
3 | timeout: 5m
4 |
5 | linters:
6 | disable-all: true
7 | # Enable specific linter
8 | # https://golangci-lint.run/usage/linters/#enabled-by-default-linters
9 | enable:
10 | - asciicheck
11 | - bidichk
12 | # - depguard
13 | - durationcheck
14 | - errcheck
15 | - errname
16 | - exportloopref
17 | - forcetypeassert
18 | - goconst
19 | - gofmt
20 | - goimports
21 | - goheader
22 | - gomodguard
23 | - goprintffuncname
24 | - gosimple
25 | - govet
26 | - importas
27 | - ineffassign
28 | - makezero
29 | - misspell
30 | - nakedret
31 | - nilnil
32 | - paralleltest
33 | - promlinter
34 | - staticcheck
35 | - stylecheck
36 | - tenv
37 | - testpackage
38 | - typecheck
39 | - unconvert
40 | - unused
41 | - whitespace
42 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | VERSION := 3.0.3
2 | COMMIT := $(shell git log -1 --format='%H')
3 | GOPATH ?= $(shell go env GOPATH)
4 | BINDIR ?= $(GOPATH)/bin
5 | CURRENT_DIR = $(shell pwd)
6 | APP = ./app
7 |
8 | ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=mun \
9 | -X github.com/cosmos/cosmos-sdk/version.ServerName=mund \
10 | -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
11 | -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT)
12 |
13 | BUILD_FLAGS := -ldflags '$(ldflags)'
14 | DOCKER := $(shell which docker)
15 | DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
16 | PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git)
17 |
18 | all: install
19 |
20 | install: go.sum
21 | go install -mod=readonly $(BUILD_FLAGS) ./cmd/mund-manager
22 | go install -mod=readonly $(BUILD_FLAGS) ./cmd/mund
23 |
24 | build: go.sum clean
25 | go build -mod=mod $(BUILD_FLAGS) -o build/mund-manager ./cmd/mund-manager
26 | go build -mod=mod $(BUILD_FLAGS) -o build/mund ./cmd/mund
27 |
28 | build-linux:
29 | GOOS=linux GOARCH=amd64 $(MAKE) build
30 |
31 | go.sum: go.mod
32 | @echo "--> Ensure dependencies have not been modified"
33 | GO111MODULE=on go mod verify
34 |
35 | # look into .golangci.yml for enabling / disabling linters
36 | lint:
37 | @echo "--> Running linter"
38 | @golangci-lint run
39 | @go mod verify
40 |
41 | # devnet
42 |
43 | devnet: clean install devnet-prepare devnet-start
44 |
45 | devnet-prepare:
46 | ./scripts/prepare-devnet.sh
47 |
48 | devnet-start:
49 | DAEMON_NAME=diversifid DAEMON_HOME=~/.diversifid DAEMON_ALLOW_DOWNLOAD_BINARIES=true DAEMON_RESTART_AFTER_UPGRADE=true \
50 | diversifid start --pruning="nothing" --inv-check-period 5
51 |
52 | # Clean up the build directory
53 | clean:
54 | rm -rf build/
55 |
56 |
57 | # Localnet
58 |
59 | # Build nodes using Docker
60 | build-docker:
61 | $(MAKE) -C networks/local
62 |
63 | # Run a 4-node testnet locally
64 | localnet-start: build-linux localnet-stop
65 | @if ! [ -f build/node0/diversifid/config/genesis.json ]; then docker run --rm -v $(CURDIR)/build:/diversifid:Z lottery/core testnet --v 4 -o . --starting-ip-address 192.168.10.2 --keyring-backend=test --chain-id test ; fi
66 | ./scripts/import-localnet-seeds.sh
67 | docker-compose up
68 |
69 | # Stop testnet
70 | localnet-stop:
71 | docker-compose down
72 |
73 | localnet: clean build-linux build-docker localnet-start
74 |
75 | ###############################################################################
76 | ### Tests & Simulation ###
77 | ###############################################################################
78 |
79 | runsim:
80 | go install github.com/cosmos/tools/cmd/runsim@latest
81 |
82 | PACKAGES_SIM=$(shell go list ./... | grep '/app')
83 |
84 | test-sim-suite:
85 | @VERSION=$(VERSION) go test -mod=readonly $(PACKAGES_SIM)
86 |
87 | test-sim-app:
88 | @VERSION=$(VERSION) go test -mod=readonly -run ^TestFullAppSimulation ./app -Enabled=true -v -NumBlocks=10 -BlockSize=200 -Commit=true -Period=0
89 |
90 | test-sim-full-app: runsim
91 | @echo "Running short multi-seed application simulation. This may take awhile!"
92 | @$(BINDIR)/runsim -Jobs=4 -SimAppPkg=$(APP) -ExitOnFail 50 10 TestFullAppSimulation
93 |
94 | test-sim-multi-seed-long: runsim
95 | @echo "Running long multi-seed application simulation. This may take awhile!"
96 | @cd ${CURRENT_DIR}/simapp && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 500 50 TestFullAppSimulation
97 |
98 | test-sim-nondeterminism:
99 | @echo "Running non-determinism test..."
100 | go test -mod=readonly -run ^TestAppStateDeterminism ./app -Enabled=true -NumBlocks=10 -BlockSize=200 -Commit=true -Period=0 -v -timeout 24h
101 |
102 | test-sim-import-export: runsim
103 | @echo "Running application import/export simulation. This may take several minutes..."
104 | @cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppImportExport
105 |
106 | test-sim-after-import: runsim
107 | @echo "Running application simulation-after-import. This may take several minutes..."
108 | @cd ${CURRENT_DIR}/app && $(BINDIR)/runsim -Jobs=4 -SimAppPkg=. -ExitOnFail 50 5 TestAppSimulationAfterImport
109 |
110 | test-sim-bench:
111 | @VERSION=$(VERSION) go test -benchmem -run ^BenchmarkFullAppSimulation -bench ^BenchmarkFullAppSimulation -cpuprofile cpu.out $(PACKAGES_SIM)
112 |
113 |
114 | ###############################################################################
115 | ### Protobuf ###
116 | ###############################################################################
117 |
118 | protoVer=v0.3
119 | protoImageName=tendermintdev/sdk-proto-gen:$(protoVer)
120 | containerProtoGen=$(PROJECT_NAME)-proto-gen-$(protoVer)
121 | containerProtoGenAny=$(PROJECT_NAME)-proto-gen-any-$(protoVer)
122 | containerProtoGenSwagger=$(PROJECT_NAME)-proto-gen-swagger-$(protoVer)
123 | containerProtoFmt=$(PROJECT_NAME)-proto-fmt-$(protoVer)
124 |
125 | proto-all: proto-format proto-lint proto-gen
126 |
127 | proto-gen:
128 | docker run --rm -v $(CURDIR):/workspace --workdir /workspace bharvest/liquidity-proto-gen sh ./scripts/protocgen.sh
129 | go mod tidy
130 |
131 | # This generates the SDK's custom wrapper for google.protobuf.Any. It should only be run manually when needed
132 | proto-gen-js:
133 | @echo "Generating Protobuf Typescript"
134 | bash ./scripts/protocgen-js.sh
135 |
136 | proto-swagger-gen:
137 | @echo "Generating Protobuf Swagger"
138 | @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoGenSwagger}$$"; then docker start -a $(containerProtoGenSwagger); else docker run --name $(containerProtoGenSwagger) -v $(CURDIR):/workspace --workdir /workspace $(protoImageName) \
139 | sh ./scripts/protoc-swagger-gen.sh; fi
140 |
141 | proto-format:
142 | @echo "Formatting Protobuf files"
143 | @if docker ps -a --format '{{.Names}}' | grep -Eq "^${containerProtoFmt}$$"; then docker start -a $(containerProtoFmt); else docker run --name $(containerProtoFmt) -v $(CURDIR):/workspace --workdir /workspace tendermintdev/docker-build-proto \
144 | find ./ -not -path "./third_party/*" -name "*.proto" -exec clang-format -i {} \; ; fi
145 |
146 | proto-lint:
147 | @$(DOCKER_BUF) lint --error-format=json
148 |
149 | proto-check-breaking:
150 | @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=master
151 |
152 | # Create log files
153 | log-files:
154 | sudo mkdir -p /var/log/mund && sudo touch /var/log/mund/mund.log && sudo touch /var/log/mund/mund_error.log
155 |
--------------------------------------------------------------------------------
/app/ante.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
8 | "github.com/cosmos/cosmos-sdk/x/authz"
9 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
10 | ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante"
11 | ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper"
12 |
13 | wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
14 | wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types"
15 | )
16 |
17 | // HandlerOptions extends the SDK's AnteHandler options by requiring the IBC
18 | // channel keeper.
19 | type HandlerOptions struct {
20 | ante.HandlerOptions
21 |
22 | IBCKeeper *ibckeeper.Keeper
23 | TxCounterStoreKey sdk.StoreKey
24 | WasmConfig wasmTypes.WasmConfig
25 | Cdc codec.BinaryCodec
26 | }
27 |
28 | type MinCommissionDecorator struct {
29 | cdc codec.BinaryCodec
30 | }
31 |
32 | func NewMinCommissionDecorator(cdc codec.BinaryCodec) MinCommissionDecorator {
33 | return MinCommissionDecorator{cdc}
34 | }
35 |
36 | func (min MinCommissionDecorator) AnteHandle(
37 | ctx sdk.Context, tx sdk.Tx,
38 | simulate bool, next sdk.AnteHandler,
39 | ) (newCtx sdk.Context, err error) {
40 | msgs := tx.GetMsgs()
41 | minCommissionRate := sdk.NewDecWithPrec(0, 2)
42 |
43 | validMsg := func(m sdk.Msg) error {
44 | switch msg := m.(type) {
45 | case *stakingtypes.MsgCreateValidator:
46 | // prevent new validators joining the set with
47 | // commission set below 5%
48 | c := msg.Commission
49 | if c.Rate.LT(minCommissionRate) {
50 | return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can't be lower than 5%")
51 | }
52 | case *stakingtypes.MsgEditValidator:
53 | // if commission rate is nil, it means only
54 | // other fields are affected - skip
55 | if msg.CommissionRate == nil {
56 | break
57 | }
58 | if msg.CommissionRate.LT(minCommissionRate) {
59 | return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can't be lower than 5%")
60 | }
61 | }
62 |
63 | return nil
64 | }
65 |
66 | validAuthz := func(execMsg *authz.MsgExec) error {
67 | for _, v := range execMsg.Msgs {
68 | var innerMsg sdk.Msg
69 | err := min.cdc.UnpackAny(v, &innerMsg)
70 | if err != nil {
71 | return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "cannot unmarshal authz exec msgs")
72 | }
73 |
74 | err = validMsg(innerMsg)
75 | if err != nil {
76 | return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid inner MSG!!!")
77 | }
78 | }
79 |
80 | return nil
81 | }
82 |
83 | for _, m := range msgs {
84 | if msg, ok := m.(*authz.MsgExec); ok {
85 | if err := validAuthz(msg); err != nil {
86 | // return ctx, err
87 | return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid Authz MSG!!!")
88 | }
89 | continue
90 | }
91 |
92 | // validate normal msgs
93 | err = validMsg(m)
94 | if err != nil {
95 | return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid normal MSG!!!")
96 | }
97 | }
98 |
99 | return next(ctx, tx, simulate)
100 | }
101 |
102 | // NewAnteHandler returns an AnteHandler that checks and increments sequence
103 | // numbers, checks signatures & account numbers, and deducts fees from the first
104 | // signer.
105 | func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
106 | if options.AccountKeeper == nil {
107 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
108 | }
109 |
110 | if options.BankKeeper == nil {
111 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
112 | }
113 |
114 | if options.SignModeHandler == nil {
115 | return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
116 | }
117 |
118 | sigGasConsumer := options.SigGasConsumer
119 | if sigGasConsumer == nil {
120 | sigGasConsumer = ante.DefaultSigVerificationGasConsumer
121 | }
122 |
123 | anteDecorators := []sdk.AnteDecorator{
124 | ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
125 | NewMinCommissionDecorator(options.Cdc),
126 | wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit),
127 | wasmkeeper.NewCountTXDecorator(options.TxCounterStoreKey),
128 | ante.NewRejectExtensionOptionsDecorator(),
129 | ante.NewMempoolFeeDecorator(),
130 | ante.NewValidateBasicDecorator(),
131 | ante.NewTxTimeoutHeightDecorator(),
132 | ante.NewValidateMemoDecorator(options.AccountKeeper),
133 | ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
134 | ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
135 | // SetPubKeyDecorator must be called before all signature verification decorators
136 | ante.NewSetPubKeyDecorator(options.AccountKeeper),
137 | ante.NewValidateSigCountDecorator(options.AccountKeeper),
138 | ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
139 | ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
140 | ante.NewIncrementSequenceDecorator(options.AccountKeeper),
141 | ibcante.NewAnteDecorator(options.IBCKeeper),
142 | }
143 |
144 | return sdk.ChainAnteDecorators(anteDecorators...), nil
145 | }
146 |
--------------------------------------------------------------------------------
/app/encoding.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "mun/app/params"
5 |
6 | "github.com/cosmos/cosmos-sdk/std"
7 | )
8 |
9 | func MakeEncodingConfig() params.EncodingConfig {
10 | encodingConfig := params.MakeEncodingConfig()
11 | std.RegisterLegacyAminoCodec(encodingConfig.Amino)
12 | std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
13 | ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino)
14 | ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry)
15 | return encodingConfig
16 | }
17 |
--------------------------------------------------------------------------------
/app/export.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | "log"
6 |
7 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
8 |
9 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
12 | "github.com/cosmos/cosmos-sdk/x/staking"
13 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
14 | )
15 |
16 | // ExportAppStateAndValidators exports the state of the application for a genesis
17 | // file.
18 | func (app *App) ExportAppStateAndValidators(
19 | forZeroHeight bool, jailAllowedAddrs []string,
20 | ) (servertypes.ExportedApp, error) {
21 | // as if they could withdraw from the start of the next block
22 | ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()})
23 |
24 | // We export at last height + 1, because that's the height at which
25 | // Tendermint will start InitChain.
26 | height := app.LastBlockHeight() + 1
27 | if forZeroHeight {
28 | height = 0
29 | app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
30 | }
31 |
32 | genState := app.mm.ExportGenesis(ctx, app.appCodec)
33 | appState, err := json.MarshalIndent(genState, "", " ")
34 | if err != nil {
35 | return servertypes.ExportedApp{}, err
36 | }
37 |
38 | validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
39 | if err != nil {
40 | return servertypes.ExportedApp{}, err
41 | }
42 | return servertypes.ExportedApp{
43 | AppState: appState,
44 | Validators: validators,
45 | Height: height,
46 | ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
47 | }, nil
48 | }
49 |
50 | // prepare for fresh start at zero height
51 | // NOTE zero height genesis is a temporary feature which will be deprecated
52 | //
53 | // in favour of export at a block height
54 | func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
55 | applyAllowedAddrs := false
56 |
57 | // check if there is a allowed address list
58 | if len(jailAllowedAddrs) > 0 {
59 | applyAllowedAddrs = true
60 | }
61 |
62 | allowedAddrsMap := make(map[string]bool)
63 |
64 | for _, addr := range jailAllowedAddrs {
65 | _, err := sdk.ValAddressFromBech32(addr)
66 | if err != nil {
67 | log.Fatal(err)
68 | }
69 | allowedAddrsMap[addr] = true
70 | }
71 |
72 | /* Just to be safe, assert the invariants on current state. */
73 | app.CrisisKeeper.AssertInvariants(ctx)
74 |
75 | /* Handle fee distribution state. */
76 |
77 | // withdraw all validator commission
78 | app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
79 | _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
80 | return false
81 | })
82 |
83 | // withdraw all delegator rewards
84 | dels := app.StakingKeeper.GetAllDelegations(ctx)
85 | for _, delegation := range dels {
86 | _, err := app.DistrKeeper.WithdrawDelegationRewards(ctx, delegation.GetDelegatorAddr(), delegation.GetValidatorAddr())
87 | if err != nil {
88 | panic(err)
89 | }
90 | }
91 |
92 | // clear validator slash events
93 | app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
94 |
95 | // clear validator historical rewards
96 | app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
97 |
98 | // set context height to zero
99 | height := ctx.BlockHeight()
100 | ctx = ctx.WithBlockHeight(0)
101 |
102 | // reinitialize all validators
103 | app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
104 | // donate any unwithdrawn outstanding reward fraction tokens to the community pool
105 | scraps := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, val.GetOperator())
106 | feePool := app.DistrKeeper.GetFeePool(ctx)
107 | feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
108 | app.DistrKeeper.SetFeePool(ctx, feePool)
109 |
110 | app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
111 | return false
112 | })
113 |
114 | // reinitialize all delegations
115 | for _, del := range dels {
116 | app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr())
117 | app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.GetDelegatorAddr(), del.GetValidatorAddr())
118 | }
119 |
120 | // reset context height
121 | ctx = ctx.WithBlockHeight(height)
122 |
123 | /* Handle staking state. */
124 |
125 | // iterate through redelegations, reset creation height
126 | app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
127 | for i := range red.Entries {
128 | red.Entries[i].CreationHeight = 0
129 | }
130 | app.StakingKeeper.SetRedelegation(ctx, red)
131 | return false
132 | })
133 |
134 | // iterate through unbonding delegations, reset creation height
135 | app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
136 | for i := range ubd.Entries {
137 | ubd.Entries[i].CreationHeight = 0
138 | }
139 | app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
140 | return false
141 | })
142 |
143 | // Iterate through validators by power descending, reset bond heights, and
144 | // update bond intra-tx counters.
145 | store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey))
146 | iter := sdk.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
147 | counter := int16(0)
148 |
149 | for ; iter.Valid(); iter.Next() {
150 | addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
151 | validator, found := app.StakingKeeper.GetValidator(ctx, addr)
152 | if !found {
153 | panic("expected validator, not found")
154 | }
155 |
156 | validator.UnbondingHeight = 0
157 | if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
158 | validator.Jailed = true
159 | }
160 |
161 | app.StakingKeeper.SetValidator(ctx, validator)
162 | counter++
163 | }
164 |
165 | iter.Close()
166 |
167 | if _, err := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx); err != nil {
168 | panic(err)
169 | }
170 |
171 | /* Handle slashing state. */
172 |
173 | // reset start height on signing infos
174 | app.SlashingKeeper.IterateValidatorSigningInfos(
175 | ctx,
176 | func(addr sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) {
177 | info.StartHeight = 0
178 | app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
179 | return false
180 | },
181 | )
182 | }
183 |
--------------------------------------------------------------------------------
/app/genesis.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec"
7 | )
8 |
9 | // The genesis state of the blockchain is represented here as a map of raw json
10 | // messages key'd by a identifier string.
11 | // The identifier is used to determine which module genesis information belongs
12 | // to so it may be appropriately routed during init chain.
13 | // Within this application default genesis information is retrieved from
14 | // the ModuleBasicManager which populates json from each BasicModule
15 | // object provided to it during init.
16 | type GenesisState map[string]json.RawMessage
17 |
18 | // NewDefaultGenesisState generates the default state for the application.
19 | func NewDefaultGenesisState(cdc codec.JSONCodec) GenesisState {
20 | return ModuleBasics.DefaultGenesis(cdc)
21 | }
22 |
--------------------------------------------------------------------------------
/app/ica_sim_helper.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "math/rand"
7 |
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | "github.com/cosmos/cosmos-sdk/types/module"
11 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
12 | ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts"
13 | icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types"
14 | )
15 |
16 | type ICAHostSimModule struct {
17 | ica.AppModule
18 | ica.AppModuleBasic
19 | cdc codec.Codec
20 | }
21 |
22 | var (
23 | _ module.AppModule = ICAHostSimModule{}
24 | _ module.AppModuleBasic = ICAHostSimModule{}
25 | _ module.AppModuleSimulation = ICAHostSimModule{}
26 | )
27 |
28 | func NewICAHostSimModule(baseModule ica.AppModule, cdc codec.Codec) ICAHostSimModule {
29 | return ICAHostSimModule{
30 | cdc: cdc,
31 | AppModule: baseModule,
32 | AppModuleBasic: baseModule.AppModuleBasic,
33 | }
34 | }
35 |
36 | // ICAHostSimModuleSimulation functions
37 | // This thing does the bare minimum to avoid simulation panic-ing for missing state data.
38 |
39 | // GenerateGenesisState creates a randomized GenState of the ica module.
40 | func (i ICAHostSimModule) GenerateGenesisState(simState *module.SimulationState) {
41 | genesis := icatypes.DefaultGenesis()
42 |
43 | bz, err := json.MarshalIndent(&genesis, "", " ")
44 | if err != nil {
45 | panic(err)
46 | }
47 | fmt.Printf("Selected randomly generated %s parameters:\n%s\n", icatypes.ModuleName, bz)
48 | simState.GenState[icatypes.ModuleName] = simState.Cdc.MustMarshalJSON(genesis)
49 | }
50 |
51 | // ProposalContents returns all the ica content functions used to
52 | // simulate governance proposals.
53 | func (ICAHostSimModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
54 | return nil
55 | }
56 |
57 | // RandomizedParams creates randomized ica param changes for the simulator.
58 | func (ICAHostSimModule) RandomizedParams(*rand.Rand) []simtypes.ParamChange {
59 | return nil
60 | }
61 |
62 | // RegisterStoreDecoder registers a decoder for ica module's types
63 | func (ICAHostSimModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
64 | }
65 |
66 | // WeightedOperations returns the all the gov module operations with their respective weights.
67 | func (ICAHostSimModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation {
68 | return nil
69 | }
70 |
--------------------------------------------------------------------------------
/app/keepers/keys.go:
--------------------------------------------------------------------------------
1 | package keepers
2 |
3 | import (
4 | "github.com/CosmWasm/wasmd/x/wasm"
5 | "github.com/cosmos/cosmos-sdk/x/authz"
6 | "github.com/cosmos/cosmos-sdk/x/feegrant"
7 | packetforwardtypes "github.com/strangelove-ventures/packet-forward-middleware/v4/router/types"
8 |
9 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
12 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
13 | capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
14 | distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
15 | evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
16 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
17 | minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
18 | paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
19 | slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
20 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
21 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
22 | icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types"
23 | icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types"
24 | ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types"
25 | ibcfeetypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types"
26 | ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host"
27 |
28 | claimmoduletypes "mun/x/claim/types"
29 |
30 | ibankmoduletypes "mun/x/ibank/types"
31 | )
32 |
33 | func newKVStoreKeys() map[string]*storetypes.KVStoreKey {
34 | return sdk.NewKVStoreKeys(
35 | authtypes.StoreKey, authz.ModuleName, banktypes.StoreKey, stakingtypes.StoreKey,
36 | minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
37 | govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
38 | evidencetypes.StoreKey, ibctransfertypes.StoreKey, icahosttypes.StoreKey, capabilitytypes.StoreKey,
39 | ibcfeetypes.StoreKey, packetforwardtypes.StoreKey, icacontrollertypes.StoreKey,
40 | wasm.StoreKey, claimmoduletypes.StoreKey, ibankmoduletypes.StoreKey,
41 | // this line is used by starport scaffolding # stargate/app/storeKey
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/app/params/amino.go:
--------------------------------------------------------------------------------
1 | //go:build test_amino
2 | // +build test_amino
3 |
4 | package params
5 |
6 | import (
7 | "github.com/cosmos/cosmos-sdk/codec"
8 | "github.com/cosmos/cosmos-sdk/codec/types"
9 | "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
10 | )
11 |
12 | // MakeTestEncodingConfig creates an EncodingConfig for an amino based test configuration.
13 | // This function should be used only internally (in the SDK).
14 | // App user shouldn't create new codecs - use the app.AppCodec instead.
15 | // [DEPRECATED]
16 | func MakeTestEncodingConfig() EncodingConfig {
17 | cdc := codec.NewLegacyAmino()
18 | interfaceRegistry := types.NewInterfaceRegistry()
19 | marshaler := codec.NewAminoCodec(cdc)
20 |
21 | return EncodingConfig{
22 | InterfaceRegistry: interfaceRegistry,
23 | Marshaler: marshaler,
24 | TxConfig: legacytx.StdTxConfig{Cdc: cdc},
25 | Amino: cdc,
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/params/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package params defines the simulation parameters in the simapp.
3 |
4 | It contains the default weights used for each transaction used on the module's
5 | simulation. These weights define the chance for a transaction to be simulated at
6 | any gived operation.
7 |
8 | You can repace the default values for the weights by providing a params.json
9 | file with the weights defined for each of the transaction operations:
10 |
11 | {
12 | "op_weight_msg_send": 60,
13 | "op_weight_msg_delegate": 100,
14 | }
15 |
16 | In the example above, the `MsgSend` has 60% chance to be simulated, while the
17 | `MsgDelegate` will always be simulated.
18 | */
19 | package params
20 |
--------------------------------------------------------------------------------
/app/params/encoding.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/client"
5 | "github.com/cosmos/cosmos-sdk/codec"
6 | "github.com/cosmos/cosmos-sdk/codec/types"
7 | )
8 |
9 | // EncodingConfig specifies the concrete encoding types to use for a given app.
10 | // This is provided for compatibility between protobuf and amino implementations.
11 | type EncodingConfig struct {
12 | InterfaceRegistry types.InterfaceRegistry
13 | // NOTE: this field will be renamed to Codec
14 | Marshaler codec.Codec
15 | TxConfig client.TxConfig
16 | Amino *codec.LegacyAmino
17 | }
18 |
--------------------------------------------------------------------------------
/app/params/params.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Simulation parameter constants
4 | const (
5 | StakePerAccount = "stake_per_account"
6 | InitiallyBondedValidators = "initially_bonded_validators"
7 | )
8 |
--------------------------------------------------------------------------------
/app/params/proto.go:
--------------------------------------------------------------------------------
1 | //go:build !test_amino
2 | // +build !test_amino
3 |
4 | package params
5 |
6 | import (
7 | "github.com/cosmos/cosmos-sdk/codec"
8 | "github.com/cosmos/cosmos-sdk/codec/types"
9 | "github.com/cosmos/cosmos-sdk/x/auth/tx"
10 | )
11 |
12 | func MakeEncodingConfig() EncodingConfig {
13 | cdc := codec.NewLegacyAmino()
14 | interfaceRegistry := types.NewInterfaceRegistry()
15 | marshaler := codec.NewProtoCodec(interfaceRegistry)
16 |
17 | return EncodingConfig{
18 | InterfaceRegistry: interfaceRegistry,
19 | Marshaler: marshaler,
20 | TxConfig: tx.NewTxConfig(marshaler, tx.DefaultSignModes),
21 | Amino: cdc,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/params/weights.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Default simulation operation weights for messages and gov proposals.
4 | const (
5 | DefaultWeightMsgCreateFixedAmountPlan int = 10
6 | DefaultWeightMsgCreateRatioPlan int = 10
7 | DefaultWeightMsgStake int = 85
8 | DefaultWeightMsgUnstake int = 20
9 | DefaultWeightMsgHarvest int = 30
10 | DefaultWeightMsgRemovePlan int = 10
11 |
12 | DefaultWeightMsgCreatePair int = 10
13 | DefaultWeightMsgCreatePool int = 15
14 | DefaultWeightMsgCreateRangedPool int = 20
15 | DefaultWeightMsgDeposit int = 20
16 | DefaultWeightMsgWithdraw int = 20
17 | DefaultWeightMsgLimitOrder int = 80
18 | DefaultWeightMsgMarketOrder int = 60
19 | DefaultWeightMsgCancelOrder int = 20
20 | DefaultWeightMsgCancelAllOrders int = 20
21 |
22 | DefaultWeightAddPublicPlanProposal int = 5
23 | DefaultWeightUpdatePublicPlanProposal int = 5
24 | DefaultWeightDeletePublicPlanProposal int = 5
25 |
26 | DefaultWeightMsgLiquidStake int = 80
27 | DefaultWeightMsgLiquidUnstake int = 30
28 |
29 | DefaultWeightAddWhitelistValidatorsProposal int = 50
30 | DefaultWeightUpdateWhitelistValidatorsProposal int = 5
31 | DefaultWeightDeleteWhitelistValidatorsProposal int = 5
32 | DefaultWeightCompleteRedelegationUnbonding int = 30
33 | DefaultWeightTallyWithLiquidStaking int = 30
34 |
35 | DefaultWeightMsgClaim int = 50
36 | )
37 |
--------------------------------------------------------------------------------
/app/test_helpers.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec"
7 | "github.com/cosmos/cosmos-sdk/simapp"
8 | abci "github.com/tendermint/tendermint/abci/types"
9 | "github.com/tendermint/tendermint/libs/log"
10 | dbm "github.com/tendermint/tm-db"
11 | )
12 |
13 | var defaultGenesisBz []byte
14 |
15 | func getDefaultGenesisStateBytes(cdc codec.JSONCodec) []byte {
16 | if len(defaultGenesisBz) == 0 {
17 | genesisState := NewDefaultGenesisState(cdc)
18 | stateBytes, err := json.MarshalIndent(genesisState, "", " ")
19 | if err != nil {
20 | panic(err)
21 | }
22 | defaultGenesisBz = stateBytes
23 | }
24 | return defaultGenesisBz
25 | }
26 |
27 | func Setup() *App {
28 | db := dbm.NewMemDB()
29 | encConfig := MakeEncodingConfig()
30 | app := NewMunApp(
31 | log.NewNopLogger(),
32 | db,
33 | nil,
34 | true,
35 | map[int64]bool{},
36 | DefaultNodeHome,
37 | 0,
38 | encConfig,
39 | simapp.EmptyAppOptions{},
40 | )
41 |
42 | stateBytes := getDefaultGenesisStateBytes(encConfig.Marshaler)
43 | app.InitChain(abci.RequestInitChain{
44 | Validators: []abci.ValidatorUpdate{},
45 | ConsensusParams: simapp.DefaultConsensusParams,
46 | AppStateBytes: stateBytes,
47 | })
48 |
49 | return app
50 | }
51 |
--------------------------------------------------------------------------------
/app/upgrades/types.go:
--------------------------------------------------------------------------------
1 | package upgrade
2 |
3 | import (
4 | "mun/app/keepers"
5 |
6 | store "github.com/cosmos/cosmos-sdk/store/types"
7 | "github.com/cosmos/cosmos-sdk/types/module"
8 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
9 | )
10 |
11 | // Upgrade defines a struct containing necessary fields that a SoftwareUpgradeProposal
12 | // must have written, in order for the state migration to go smoothly.
13 | // An upgrade must implement this struct, and then set it in the app.go.
14 | // The app.go will then define the handler.
15 | type UpgradeMun struct {
16 | // Upgrade version name, for the upgrade handler, e.g. `mun_v2`
17 | UpgradeName string
18 |
19 | // CreateUpgradeHandler defines the function that creates an upgrade handler
20 | CreateUpgradeHandler func(*module.Manager, module.Configurator, *keepers.AppKeepers) upgradetypes.UpgradeHandler
21 |
22 | // Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed.
23 | StoreUpgrades store.StoreUpgrades
24 | }
25 |
--------------------------------------------------------------------------------
/app/upgrades/v2/constants.go:
--------------------------------------------------------------------------------
1 | package v2
2 |
3 | import (
4 | // "mun/app/upgrades"
5 | upgrade "mun/app/upgrades"
6 |
7 | store "github.com/cosmos/cosmos-sdk/store/types"
8 | )
9 |
10 | const (
11 | // UpgradeName defines the on-chain upgrade name.
12 | UpgradeName = "mun-upgrade-v2"
13 | )
14 |
15 | var Upgrade = upgrade.UpgradeMun{
16 | UpgradeName: UpgradeName,
17 | CreateUpgradeHandler: CreateUpgradeHandler,
18 | StoreUpgrades: store.StoreUpgrades{
19 | Added: []string{},
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/app/upgrades/v2/upgrades.go:
--------------------------------------------------------------------------------
1 | package v2
2 |
3 | import (
4 | "mun/app/keepers"
5 | "time"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/cosmos/cosmos-sdk/types/module"
9 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
10 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
11 | )
12 |
13 | func CreateUpgradeHandler(
14 | mm *module.Manager,
15 | configurator module.Configurator,
16 | keepers *keepers.AppKeepers,
17 | ) upgradetypes.UpgradeHandler {
18 | return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
19 | ctx.Logger().Info("start to run module migrations...")
20 |
21 | unbondingTime, _ := time.ParseDuration("1814400s")
22 | stakingParams := stakingtypes.Params{
23 | UnbondingTime: unbondingTime,
24 | MaxValidators: 150,
25 | MaxEntries: 7,
26 | HistoricalEntries: 10000,
27 | BondDenom: "utmun",
28 | }
29 |
30 | keepers.StakingKeeper.SetParams(ctx, stakingParams)
31 | return mm.RunMigrations(ctx, configurator, vm)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/upgrades/v3/constants.go:
--------------------------------------------------------------------------------
1 | package v3
2 |
3 | import (
4 | // "mun/app/upgrades"
5 | upgrade "mun/app/upgrades"
6 |
7 | store "github.com/cosmos/cosmos-sdk/store/types"
8 | )
9 |
10 | const (
11 | // UpgradeName defines the on-chain upgrade name.
12 | UpgradeName = "mun-upgrade-v3"
13 | )
14 |
15 | var Upgrade = upgrade.UpgradeMun{
16 | UpgradeName: UpgradeName,
17 | CreateUpgradeHandler: CreateUpgradeHandler,
18 | StoreUpgrades: store.StoreUpgrades{
19 | Added: []string{},
20 | },
21 | }
22 |
--------------------------------------------------------------------------------
/app/upgrades/v3/upgrades.go:
--------------------------------------------------------------------------------
1 | package v3
2 |
3 | import (
4 | "mun/app/keepers"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/cosmos/cosmos-sdk/types/module"
8 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
9 | )
10 |
11 | func CreateUpgradeHandler(
12 | mm *module.Manager,
13 | configurator module.Configurator,
14 | keepers *keepers.AppKeepers,
15 | ) upgradetypes.UpgradeHandler {
16 | return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
17 | return mm.RunMigrations(ctx, configurator, vm)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/upgrades/v301/constants.go:
--------------------------------------------------------------------------------
1 | package v301
2 |
3 | import (
4 | upgrade "mun/app/upgrades"
5 | ibankmoduletypes "mun/x/ibank/types"
6 |
7 | store "github.com/cosmos/cosmos-sdk/store/types"
8 | icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types"
9 | ibcfeetypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types"
10 | packetforwardtypes "github.com/strangelove-ventures/packet-forward-middleware/v4/router/types"
11 | )
12 |
13 | const (
14 | // UpgradeName defines the on-chain upgrade name.
15 | UpgradeName = "mun-upgrade-v3.0.1"
16 | monitoringpStoreKey = "monitoringp"
17 | )
18 |
19 | var Upgrade = upgrade.UpgradeMun{
20 | UpgradeName: UpgradeName,
21 | CreateUpgradeHandler: CreateUpgradeHandler,
22 | StoreUpgrades: store.StoreUpgrades{
23 | Added: []string{packetforwardtypes.ModuleName, icacontrollertypes.SubModuleName, ibcfeetypes.SubModuleName, ibankmoduletypes.ModuleName},
24 | Deleted: []string{monitoringpStoreKey},
25 | },
26 | }
27 |
--------------------------------------------------------------------------------
/app/upgrades/v301/upgrades.go:
--------------------------------------------------------------------------------
1 | package v301
2 |
3 | import (
4 | "mun/app/keepers"
5 |
6 | "github.com/CosmWasm/wasmd/x/wasm"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/cosmos/cosmos-sdk/types/module"
9 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
10 | icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types"
11 | )
12 |
13 | func CreateUpgradeHandler(
14 | mm *module.Manager,
15 | configurator module.Configurator,
16 | keepers *keepers.AppKeepers,
17 | ) upgradetypes.UpgradeHandler {
18 | return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
19 | fromVm[wasm.ModuleName] = 1
20 |
21 | sb, ok := keepers.ParamsKeeper.GetSubspace(icacontrollertypes.SubModuleName)
22 | if !ok {
23 | panic("ica controller sub space does not exist")
24 | }
25 |
26 | sb.Set(ctx, icacontrollertypes.KeyControllerEnabled, true)
27 | defaultParams := icacontrollertypes.DefaultParams()
28 | sb.SetParamSet(ctx, &defaultParams)
29 |
30 | return mm.RunMigrations(ctx, configurator, fromVm)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/upgrades/v303/constants.go:
--------------------------------------------------------------------------------
1 | package v303
2 |
3 | import (
4 | upgrade "mun/app/upgrades"
5 |
6 | store "github.com/cosmos/cosmos-sdk/store/types"
7 | )
8 |
9 | const (
10 | // UpgradeName defines the on-chain upgrade name.
11 | UpgradeName = "mun-upgrade-v3.0.3"
12 | allocStoreKey = "alloc"
13 | )
14 |
15 | var Upgrade = upgrade.UpgradeMun{
16 | UpgradeName: UpgradeName,
17 | CreateUpgradeHandler: CreateUpgradeHandler,
18 | StoreUpgrades: store.StoreUpgrades{
19 | Added: []string{},
20 | Deleted: []string{allocStoreKey},
21 | },
22 | }
23 |
--------------------------------------------------------------------------------
/app/upgrades/v303/upgrades.go:
--------------------------------------------------------------------------------
1 | package v303
2 |
3 | import (
4 | "mun/app/keepers"
5 |
6 | ibanktypes "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/types/module"
10 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
11 | )
12 |
13 | const (
14 | MerkleRoot = "4567efe1ffef2087b5ab30112753e7088bb509ce1955e79744ff44db4ab8790d"
15 | )
16 |
17 | func CreateUpgradeHandler(
18 | mm *module.Manager,
19 | configurator module.Configurator,
20 | keepers *keepers.AppKeepers,
21 | ) upgradetypes.UpgradeHandler {
22 | return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) {
23 | keepers.ClaimKeeper.SetMerkleRoot(ctx, MerkleRoot)
24 | keepers.IbankKeeper.SetParams(ctx, ibanktypes.DefaultParams())
25 |
26 | return mm.RunMigrations(ctx, configurator, fromVm)
27 | }
28 | }
29 |
30 | func ManualUpgrade(ctx sdk.Context, keepers *keepers.AppKeepers) {
31 | keepers.ClaimKeeper.SetMerkleRoot(ctx, MerkleRoot)
32 | keepers.IbankKeeper.SetParams(ctx, ibanktypes.DefaultParams())
33 | }
34 |
--------------------------------------------------------------------------------
/app/wasm_config.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
5 | )
6 |
7 | const (
8 | // DefaultMunInstanceCost is initially set the same as in wasmd
9 | DefaultMunInstanceCost uint64 = 60_000
10 | // DefaultMunCompileCost set to a large number for testing
11 | DefaultMunCompileCost uint64 = 100
12 | )
13 |
14 | // MunGasRegisterConfig is defaults plus a custom compile amount
15 | func MunGasRegisterConfig() wasmkeeper.WasmGasRegisterConfig {
16 | gasConfig := wasmkeeper.DefaultGasRegisterConfig()
17 | gasConfig.InstanceCost = DefaultMunInstanceCost
18 | gasConfig.CompileCost = DefaultMunCompileCost
19 |
20 | return gasConfig
21 | }
22 |
23 | func NewMunWasmGasRegister() wasmkeeper.WasmGasRegister {
24 | return wasmkeeper.NewWasmGasRegister(MunGasRegisterConfig())
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/mund-manager/lib/args.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "bufio"
5 | "errors"
6 | "fmt"
7 | "net/url"
8 | "os"
9 | "path/filepath"
10 | "strconv"
11 | )
12 |
13 | const (
14 | rootName = "upgrade_manager"
15 | genesisDir = "genesis"
16 | upgradesDir = "upgrades"
17 | currentLink = "current"
18 | )
19 |
20 | // Config is the information passed in to control the daemon
21 | type Config struct {
22 | Home string
23 | Name string
24 | AllowDownloadBinaries bool
25 | RestartAfterUpgrade bool
26 | LogBufferSize int
27 | }
28 |
29 | // Root returns the root directory where all info lives
30 | func (cfg *Config) Root() string {
31 | return filepath.Join(cfg.Home, rootName)
32 | }
33 |
34 | // GenesisBin is the path to the genesis binary - must be in place to start manager
35 | func (cfg *Config) GenesisBin() string {
36 | return filepath.Join(cfg.Root(), genesisDir, "bin", cfg.Name)
37 | }
38 |
39 | // UpgradeBin is the path to the binary for the named upgrade
40 | func (cfg *Config) UpgradeBin(upgradeName string) string {
41 | return filepath.Join(cfg.UpgradeDir(upgradeName), "bin", cfg.Name)
42 | }
43 |
44 | // UpgradeDir is the directory named upgrade
45 | func (cfg *Config) UpgradeDir(upgradeName string) string {
46 | safeName := url.PathEscape(upgradeName)
47 | return filepath.Join(cfg.Root(), upgradesDir, safeName)
48 | }
49 |
50 | // Symlink to genesis
51 | func (cfg *Config) SymLinkToGenesis() (string, error) {
52 | genesis := filepath.Join(cfg.Root(), genesisDir)
53 | link := filepath.Join(cfg.Root(), currentLink)
54 |
55 | if err := os.Symlink(genesis, link); err != nil {
56 | return "", err
57 | }
58 | // and return the genesis binary
59 | return cfg.GenesisBin(), nil
60 | }
61 |
62 | // CurrentBin is the path to the currently selected binary (genesis if no link is set)
63 | // This will resolve the symlink to the underlying directory to make it easier to debug
64 | func (cfg *Config) CurrentBin() (string, error) {
65 | cur := filepath.Join(cfg.Root(), currentLink)
66 | // if nothing here, fallback to genesis
67 | info, err := os.Lstat(cur)
68 | if err != nil {
69 | //Create symlink to the genesis
70 | return cfg.SymLinkToGenesis()
71 | }
72 | // if it is there, ensure it is a symlink
73 | if info.Mode()&os.ModeSymlink == 0 {
74 | //Create symlink to the genesis
75 | return cfg.SymLinkToGenesis()
76 | }
77 |
78 | // resolve it
79 | dest, err := os.Readlink(cur)
80 | if err != nil {
81 | //Create symlink to the genesis
82 | return cfg.SymLinkToGenesis()
83 | }
84 |
85 | // and return the binary
86 | return filepath.Join(dest, "bin", cfg.Name), nil
87 | }
88 |
89 | // GetConfigFromEnv will read the environmental variables into a config
90 | // and then validate it is reasonable
91 | func GetConfigFromEnv() (*Config, error) {
92 | cfg := &Config{
93 | Home: os.Getenv("DAEMON_HOME"),
94 | Name: os.Getenv("DAEMON_NAME"),
95 | }
96 |
97 | if os.Getenv("DAEMON_ALLOW_DOWNLOAD_BINARIES") == "true" {
98 | cfg.AllowDownloadBinaries = true
99 | }
100 |
101 | if os.Getenv("DAEMON_RESTART_AFTER_UPGRADE") == "true" {
102 | cfg.RestartAfterUpgrade = true
103 | }
104 |
105 | logBufferSizeStr := os.Getenv("DAEMON_LOG_BUFFER_SIZE")
106 | if logBufferSizeStr != "" {
107 | logBufferSize, err := strconv.Atoi(logBufferSizeStr)
108 | if err != nil {
109 | return nil, err
110 | }
111 | cfg.LogBufferSize = logBufferSize * 1024
112 | } else {
113 | cfg.LogBufferSize = bufio.MaxScanTokenSize
114 | }
115 |
116 | if err := cfg.validate(); err != nil {
117 | return nil, err
118 | }
119 |
120 | return cfg, nil
121 | }
122 |
123 | // validate returns an error if this config is invalid.
124 | // it enforces Home/cosmovisor is a valid directory and exists,
125 | // and that Name is set
126 | func (cfg *Config) validate() error {
127 | if cfg.Name == "" {
128 | return errors.New("DAEMON_NAME is not set")
129 | }
130 |
131 | if cfg.Home == "" {
132 | return errors.New("DAEMON_HOME is not set")
133 | }
134 |
135 | if !filepath.IsAbs(cfg.Home) {
136 | return errors.New("DAEMON_HOME must be an absolute path")
137 | }
138 |
139 | // ensure the root directory exists
140 | info, err := os.Stat(cfg.Root())
141 | if err != nil {
142 | return fmt.Errorf("cannot stat home dir: %w", err)
143 | }
144 |
145 | if !info.IsDir() {
146 | return fmt.Errorf("%s is not a directory", info.Name())
147 | }
148 |
149 | return nil
150 | }
151 |
--------------------------------------------------------------------------------
/cmd/mund-manager/lib/process.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "io"
7 | "log"
8 | "os"
9 | "os/exec"
10 | "os/signal"
11 | "strings"
12 | "sync"
13 | "syscall"
14 | )
15 |
16 | // LaunchProcess runs a subprocess and returns when the subprocess exits,
17 | // either when it dies, or *after* a successful upgrade.
18 | func LaunchProcess(cfg *Config, args []string, stdout, stderr io.Writer) (bool, error) {
19 | bin, err := cfg.CurrentBin()
20 | if err != nil {
21 | return false, fmt.Errorf("error creating symlink to genesis: %w", err)
22 | }
23 |
24 | if err := EnsureBinary(bin); err != nil {
25 | return false, fmt.Errorf("current binary invalid: %w", err)
26 | }
27 |
28 | cmd := exec.Command(bin, args...)
29 | outpipe, err := cmd.StdoutPipe()
30 | if err != nil {
31 | return false, err
32 | }
33 |
34 | errpipe, err := cmd.StderrPipe()
35 | if err != nil {
36 | return false, err
37 | }
38 |
39 | scanOut := bufio.NewScanner(io.TeeReader(outpipe, stdout))
40 | scanErr := bufio.NewScanner(io.TeeReader(errpipe, stderr))
41 | // set scanner's buffer size to cfg.LogBufferSize, and ensure larger than bufio.MaxScanTokenSize otherwise fallback to bufio.MaxScanTokenSize
42 | var maxCapacity int
43 | if cfg.LogBufferSize < bufio.MaxScanTokenSize {
44 | maxCapacity = bufio.MaxScanTokenSize
45 | } else {
46 | maxCapacity = cfg.LogBufferSize
47 | }
48 | bufOut := make([]byte, maxCapacity)
49 | bufErr := make([]byte, maxCapacity)
50 | scanOut.Buffer(bufOut, maxCapacity)
51 | scanErr.Buffer(bufErr, maxCapacity)
52 |
53 | if err := cmd.Start(); err != nil {
54 | return false, fmt.Errorf("launching process %s %s: %w", bin, strings.Join(args, " "), err)
55 | }
56 |
57 | sigs := make(chan os.Signal, 1)
58 | signal.Notify(sigs, syscall.SIGQUIT, syscall.SIGTERM)
59 | go func() {
60 | sig := <-sigs
61 | if err := cmd.Process.Signal(sig); err != nil {
62 | log.Fatal(err)
63 | }
64 | }()
65 |
66 | // three ways to exit - command ends, find regexp in scanOut, find regexp in scanErr
67 | upgradeInfo, err := WaitForUpgradeOrExit(cmd, scanOut, scanErr)
68 | if err != nil {
69 | return false, err
70 | }
71 |
72 | if upgradeInfo != nil {
73 | return true, DoUpgrade(cfg, upgradeInfo)
74 | }
75 |
76 | return false, nil
77 | }
78 |
79 | // WaitResult is used to wrap feedback on cmd state with some mutex logic.
80 | // This is needed as multiple go-routines can affect this - two read pipes that can trigger upgrade
81 | // As well as the command, which can fail
82 | type WaitResult struct {
83 | // both err and info may be updated from several go-routines
84 | // access is wrapped by mutex and should only be done through methods
85 | err error
86 | info *UpgradeInfo
87 | mutex sync.Mutex
88 | }
89 |
90 | // AsResult reads the data protected by mutex to avoid race conditions
91 | func (u *WaitResult) AsResult() (*UpgradeInfo, error) {
92 | u.mutex.Lock()
93 | defer u.mutex.Unlock()
94 | return u.info, u.err
95 | }
96 |
97 | // SetError will set with the first error using a mutex
98 | // don't set it once info is set, that means we chose to kill the process
99 | func (u *WaitResult) SetError(myErr error) {
100 | u.mutex.Lock()
101 | defer u.mutex.Unlock()
102 | if u.info == nil && myErr != nil {
103 | u.err = myErr
104 | }
105 | }
106 |
107 | // SetUpgrade sets first non-nil upgrade info, ensure error is then nil
108 | // pass in a command to shutdown on successful upgrade
109 | func (u *WaitResult) SetUpgrade(up *UpgradeInfo) {
110 | u.mutex.Lock()
111 | defer u.mutex.Unlock()
112 | if u.info == nil && up != nil {
113 | u.info = up
114 | u.err = nil
115 | }
116 | }
117 |
118 | // WaitForUpgradeOrExit listens to both output streams of the process, as well as the process state itself
119 | // When it returns, the process is finished and all streams have closed.
120 | //
121 | // It returns (info, nil) if an upgrade should be initiated (and we killed the process)
122 | // It returns (nil, err) if the process died by itself, or there was an issue reading the pipes
123 | // It returns (nil, nil) if the process exited normally without triggering an upgrade. This is very unlikely
124 | // to happened with "start" but may happened with short-lived commands like `gaiad export ...`
125 | func WaitForUpgradeOrExit(cmd *exec.Cmd, scanOut, scanErr *bufio.Scanner) (*UpgradeInfo, error) {
126 | var res WaitResult
127 |
128 | waitScan := func(scan *bufio.Scanner) {
129 | upgrade, err := WaitForUpdate(scan)
130 | if err != nil {
131 | res.SetError(err)
132 | } else if upgrade != nil {
133 | res.SetUpgrade(upgrade)
134 | // now we need to kill the process
135 | _ = cmd.Process.Kill()
136 | }
137 | }
138 |
139 | // wait for the scanners, which can trigger upgrade and kill cmd
140 | go waitScan(scanOut)
141 | go waitScan(scanErr)
142 |
143 | // if the command exits normally (eg. short command like `gaiad version`), just return (nil, nil)
144 | // we often get broken read pipes if it runs too fast.
145 | // if we had upgrade info, we would have killed it, and thus got a non-nil error code
146 | err := cmd.Wait()
147 | if err == nil {
148 | return nil, nil // nolint: nilnil
149 | }
150 | // this will set the error code if it wasn't killed due to upgrade
151 | res.SetError(err)
152 | return res.AsResult()
153 | }
154 |
--------------------------------------------------------------------------------
/cmd/mund-manager/lib/scanner.go:
--------------------------------------------------------------------------------
1 | package lib
2 |
3 | import (
4 | "bufio"
5 | "regexp"
6 | )
7 |
8 | // Trim off whitespace around the info - match least greedy, grab as much space on both sides
9 | // Defined here: https://github.com/cosmos/cosmos-sdk/blob/release/v0.38.2/x/upgrade/abci.go#L38
10 | //
11 | // fmt.Sprintf("UPGRADE \"%s\" NEEDED at %s: %s", plan.Name, plan.DueAt(), plan.Info)
12 | //
13 | // DueAt defined here: https://github.com/cosmos/cosmos-sdk/blob/release/v0.38.2/x/upgrade/internal/types/plan.go#L73-L78
14 | //
15 | // if !p.Time.IsZero() {
16 | // return fmt.Sprintf("time: %s", p.Time.UTC().Format(time.RFC3339))
17 | // }
18 | // return fmt.Sprintf("height: %d", p.Height)
19 | var upgradeRegex = regexp.MustCompile(`UPGRADE "(.*)" NEEDED at ((height): (\d+)|(time): (\S+)):\s+(\S*)`)
20 |
21 | // UpgradeInfo is the details from the regexp
22 | type UpgradeInfo struct {
23 | Name string
24 | Info string
25 | }
26 |
27 | // WaitForUpdate will listen to the scanner until a line matches upgradeRegexp.
28 | // It returns (info, nil) on a matching line
29 | // It returns (nil, err) if the input stream errored
30 | // It returns (nil, nil) if the input closed without ever matching the regexp
31 | func WaitForUpdate(scanner *bufio.Scanner) (*UpgradeInfo, error) {
32 | for scanner.Scan() {
33 | line := scanner.Text()
34 | if upgradeRegex.MatchString(line) {
35 | subs := upgradeRegex.FindStringSubmatch(line)
36 | info := UpgradeInfo{
37 | Name: subs[1],
38 | Info: subs[7],
39 | }
40 | return &info, nil
41 | }
42 | }
43 | return nil, scanner.Err()
44 | }
45 |
--------------------------------------------------------------------------------
/cmd/mund-manager/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "mun/cmd/mund-manager/lib"
8 | )
9 |
10 | func main() {
11 | if err := Run(os.Args[1:]); err != nil {
12 | fmt.Fprintf(os.Stderr, "%+v\n", err)
13 | os.Exit(1)
14 | }
15 | }
16 |
17 | // Run is the main loop, but returns an error
18 | func Run(args []string) error {
19 | cfg, err := lib.GetConfigFromEnv()
20 | if err != nil {
21 | return err
22 | }
23 |
24 | doUpgrade, err := lib.LaunchProcess(cfg, args, os.Stdout, os.Stderr)
25 | // if RestartAfterUpgrade, we launch after a successful upgrade (only condition LaunchProcess returns nil)
26 | for cfg.RestartAfterUpgrade && err == nil && doUpgrade {
27 | doUpgrade, err = lib.LaunchProcess(cfg, args, os.Stdout, os.Stderr)
28 | }
29 | return err
30 | }
31 |
--------------------------------------------------------------------------------
/cmd/mund/cmd/config.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "mun/app"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | func initSDKConfig() {
10 | // Set prefixes
11 | accountPubKeyPrefix := app.AccountAddressPrefix + "pub"
12 | validatorAddressPrefix := app.AccountAddressPrefix + "valoper"
13 | validatorPubKeyPrefix := app.AccountAddressPrefix + "valoperpub"
14 | consNodeAddressPrefix := app.AccountAddressPrefix + "valcons"
15 | consNodePubKeyPrefix := app.AccountAddressPrefix + "valconspub"
16 |
17 | // Set and seal config
18 | config := sdk.GetConfig()
19 | config.SetBech32PrefixForAccount(app.AccountAddressPrefix, accountPubKeyPrefix)
20 | config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix)
21 | config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix)
22 | config.Seal()
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/mund/genwasm.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/client"
5 | "github.com/spf13/cobra"
6 | )
7 |
8 | func AddGenesisWasmMsgCmd(defaultNodeHome string) *cobra.Command {
9 | txCmd := &cobra.Command{
10 | Use: "add-wasm-genesis-message",
11 | Short: "Wasm genesis subcommands",
12 | DisableFlagParsing: true,
13 | SuggestionsMinimumDistance: 2,
14 | RunE: client.ValidateCmd,
15 | }
16 | // genesisIO := wasmcli.NewDefaultGenesisIO()
17 | // txCmd.AddCommand(
18 | // wasmcli.GenesisStoreCodeCmd(defaultNodeHome, genesisIO),
19 | // wasmcli.GenesisInstantiateContractCmd(defaultNodeHome, genesisIO),
20 | // wasmcli.GenesisExecuteContractCmd(defaultNodeHome, genesisIO),
21 | // wasmcli.GenesisListContractsCmd(defaultNodeHome, genesisIO),
22 | // wasmcli.GenesisListCodesCmd(defaultNodeHome, genesisIO),
23 | // )
24 |
25 | return txCmd
26 | }
27 |
--------------------------------------------------------------------------------
/cmd/mund/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 |
6 | "mun/app"
7 |
8 | "mun/cmd/mund/cmd"
9 |
10 | "github.com/cosmos/cosmos-sdk/server"
11 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
12 | )
13 |
14 | func main() {
15 | // cmdOptions := GetWasmCmdOptions()
16 | rootCmd, _ := cmd.NewRootCmd()
17 | if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil {
18 | switch e := err.(type) {
19 | case server.ErrorCode:
20 | os.Exit(e.Code)
21 |
22 | default:
23 | os.Exit(1)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/config.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | build:
3 | main: ./cmd/mund
4 | proto:
5 | path: ""
6 | third_party_paths: []
7 | accounts:
8 | - name: alice
9 | coins:
10 | - 2000000000utmun
11 | mnemonic: alarm robust diet dinosaur honey pencil dial wall scene strategy hint
12 | predict bleak physical ancient creek insane limb boring scan eager erode behave
13 | vehicle
14 | - name: bob
15 | coins:
16 | - 10000utmun
17 | mnemonic: economy ticket horror harbor draw educate vehicle fly hen crystal album
18 | exist mechanic creek ugly economy say category lunar much sound during inmate
19 | coyote
20 | - name: tom
21 | coins:
22 | - 1000000000000utmun
23 | mnemonic: orphan cradle clarify priority jeans light hold country bright flight
24 | tail position various bunker later scale nose edge suggest fit direct lock immense
25 | tumble
26 | - name: jerry
27 | coins:
28 | - 100000000000000utmun
29 | mnemonic: degree tissue code business hair agree fruit print bargain tissue fuel
30 | small neutral word prefer glimpse fiscal mention lawn royal balance tray jazz
31 | faculty
32 | faucet:
33 | name: bob
34 | coins:
35 | - 100000utmun
36 | host: 0.0.0.0:4500
37 | client:
38 | typescript:
39 | path: ts-client
40 | vuex:
41 | path: vue/src/store
42 | composables:
43 | path: vue/src/composables
44 | hooks:
45 | path: react/src/hooks
46 | openapi:
47 | path: docs/static/openapi.yml
48 | genesis:
49 | app_state:
50 | staking:
51 | params:
52 | bond_denom: utmun
53 | validators:
54 | - name: alice
55 | bonded: 100000000utmun
56 | - name: bob
57 | bonded: 1000000000utmun
58 |
--------------------------------------------------------------------------------
/docs/docs.go:
--------------------------------------------------------------------------------
1 | package docs
2 |
3 | import (
4 | "embed"
5 | httptemplate "html/template"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | apiFile = "/static/openapi.yml"
13 | indexFile = "template/index.tpl"
14 | )
15 |
16 | //go:embed static
17 | var Static embed.FS
18 |
19 | //go:embed template
20 | var template embed.FS
21 |
22 | func RegisterOpenAPIService(appName string, rtr *mux.Router) {
23 | rtr.Handle(apiFile, http.FileServer(http.FS(Static)))
24 | rtr.HandleFunc("/", handler(appName))
25 | }
26 |
27 | // handler returns an http handler that servers OpenAPI console for an OpenAPI spec at specURL.
28 | func handler(title string) http.HandlerFunc {
29 | t, _ := httptemplate.ParseFS(template, indexFile)
30 |
31 | return func(w http.ResponseWriter, req *http.Request) {
32 | _ = t.Execute(w, struct {
33 | Title string
34 | URL string
35 | }{
36 | title,
37 | apiFile,
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/template/index.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ .Title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/internal/ante/min_commission.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 |
8 | "github.com/cosmos/cosmos-sdk/x/authz"
9 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
10 | )
11 |
12 | type MinCommissionDecorator struct {
13 | codec codec.BinaryCodec
14 | }
15 |
16 | func NewMinCommissionDecorator(codec codec.BinaryCodec) MinCommissionDecorator {
17 | return MinCommissionDecorator{
18 | codec,
19 | }
20 | }
21 |
22 | func checkCommission(m sdk.Msg) error {
23 | switch msg := m.(type) {
24 | case *stakingtypes.MsgCreateValidator:
25 | c := msg.Commission
26 | if c.Rate.LT(sdk.NewDecWithPrec(5, 2)) {
27 | return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can not be lower than 5%")
28 | }
29 | case *stakingtypes.MsgEditValidator:
30 | // if commission rate is nil, it means only other fields are being update and we must skip this validation
31 | if msg.CommissionRate == nil {
32 | return nil
33 | }
34 | if msg.CommissionRate.LT(sdk.NewDecWithPrec(5, 2)) {
35 | return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can not be lower than 5%")
36 | }
37 | default:
38 | return nil
39 | }
40 | return nil
41 | }
42 |
43 | func (dec MinCommissionDecorator) Validate(m sdk.Msg) error {
44 | err := checkCommission(m)
45 | if err != nil {
46 | return err
47 | }
48 | if msg, ok := m.(*authz.MsgExec); ok {
49 | for _, v := range msg.Msgs {
50 | var wrappedMsg sdk.Msg
51 | err := dec.codec.UnpackAny(v, &wrappedMsg)
52 | if err != nil {
53 | return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "error decoding authz messages")
54 | }
55 | err = checkCommission(wrappedMsg)
56 | if err != nil {
57 | return err
58 | }
59 | }
60 | }
61 | return nil
62 | }
63 |
64 | func (dec MinCommissionDecorator) AnteHandle(
65 | ctx sdk.Context, tx sdk.Tx,
66 | simulate bool, next sdk.AnteHandler,
67 | ) (newCtx sdk.Context, err error) {
68 | msgs := tx.GetMsgs()
69 | for _, m := range msgs {
70 | err := dec.Validate(m)
71 | if err != nil {
72 | return ctx, err
73 | }
74 | }
75 | return next(ctx, tx, simulate)
76 | }
77 |
--------------------------------------------------------------------------------
/internal/statesync/snapshotter.go:
--------------------------------------------------------------------------------
1 | package statesync
2 |
3 | import (
4 | "io"
5 |
6 | snapshot "github.com/cosmos/cosmos-sdk/snapshots/types"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
9 | protoio "github.com/gogo/protobuf/io"
10 | abci "github.com/tendermint/tendermint/abci/types"
11 | "github.com/tendermint/tendermint/libs/log"
12 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
13 | )
14 |
15 | const (
16 | SnapshotName = "sg_version_snapshotter"
17 | SnapshotFormat = 0xFF
18 | )
19 |
20 | var _ snapshot.ExtensionSnapshotter = &VersionSnapshotter{}
21 |
22 | type ConsensusParamsGetter interface {
23 | GetConsensusParams(ctx sdk.Context) *abci.ConsensusParams
24 | }
25 |
26 | type ProtocolVersionSetter interface {
27 | SetProtocolVersion(uint64)
28 | }
29 |
30 | type VersionSnapshotter struct {
31 | consensusParamGetter ConsensusParamsGetter
32 | versionSetter ProtocolVersionSetter
33 | ms sdk.MultiStore
34 | }
35 |
36 | func NewVersionSnapshotter(ms sdk.MultiStore, cpg ConsensusParamsGetter, vs ProtocolVersionSetter) *VersionSnapshotter {
37 | return &VersionSnapshotter{
38 | consensusParamGetter: cpg,
39 | versionSetter: vs,
40 | ms: ms,
41 | }
42 | }
43 |
44 | func (vs *VersionSnapshotter) SnapshotName() string {
45 | return SnapshotName
46 | }
47 |
48 | // Snapshot writes snapshot items into the protobuf writer.
49 | func (vs *VersionSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) error {
50 | cms, err := vs.ms.CacheMultiStoreWithVersion(int64(height))
51 | if err != nil {
52 | return err
53 | }
54 | ctx := sdk.NewContext(cms, tmproto.Header{}, false, log.NewNopLogger())
55 | params := vs.consensusParamGetter.GetConsensusParams(ctx)
56 | // default to 1 for stargaze
57 | appVersion := uint64(1)
58 | if params != nil && params.Version != nil && params.Version.GetAppVersion() > 0 {
59 | appVersion = params.Version.GetAppVersion()
60 | }
61 | bz := sdk.Uint64ToBigEndian(appVersion)
62 | return snapshot.WriteExtensionItem(protoWriter, bz)
63 | }
64 |
65 | // Restore restores a state snapshot from the protobuf items read from the reader.
66 | func (vs *VersionSnapshotter) Restore(height uint64, format uint32, protoReader protoio.Reader) (snapshot.SnapshotItem, error) {
67 | if format == SnapshotFormat {
68 | var item snapshot.SnapshotItem
69 | for {
70 | item = snapshot.SnapshotItem{}
71 | err := protoReader.ReadMsg(&item)
72 | if err == io.EOF {
73 | break
74 | } else if err != nil {
75 | return snapshot.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message")
76 | }
77 | payload := item.GetExtensionPayload()
78 | if payload == nil {
79 | break
80 | }
81 | appVersion := sdk.BigEndianToUint64(payload.Payload)
82 | vs.versionSetter.SetProtocolVersion(appVersion)
83 | }
84 | return item, nil
85 | }
86 | return snapshot.SnapshotItem{}, snapshot.ErrUnknownFormat
87 | }
88 |
89 | func (vs *VersionSnapshotter) SnapshotFormat() uint32 {
90 | return SnapshotFormat
91 | }
92 |
93 | func (vs *VersionSnapshotter) SupportedFormats() []uint32 {
94 | return []uint32{SnapshotFormat}
95 | }
96 |
--------------------------------------------------------------------------------
/internal/wasm/distribution.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
8 | wasmvmtypes "github.com/CosmWasm/wasmvm/types"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
11 | distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
12 | )
13 |
14 | const (
15 | DistributionRoute = "distribution"
16 | )
17 |
18 | var _ Encoder = CustomDistributionEncoder
19 |
20 | type FundCommunityPool struct {
21 | Amount wasmvmtypes.Coins `json:"amount"`
22 | }
23 |
24 | func (fcp FundCommunityPool) Encode(contract sdk.AccAddress) ([]sdk.Msg, error) {
25 | amount, err := wasmkeeper.ConvertWasmCoinsToSdkCoins(fcp.Amount)
26 |
27 | if err != nil {
28 | return nil, err
29 | }
30 | msg := distributiontypes.NewMsgFundCommunityPool(amount, contract)
31 | return []sdk.Msg{msg}, nil
32 | }
33 |
34 | type DistributionMsg struct {
35 | FundCommunityPool *FundCommunityPool `json:"fund_community_pool,omitempty"`
36 | }
37 |
38 | func CustomDistributionEncoder(contract sdk.AccAddress, data json.RawMessage, version string) ([]sdk.Msg, error) {
39 | msg := &DistributionMsg{}
40 | err := json.Unmarshal(data, msg)
41 | if err != nil {
42 | return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
43 | }
44 | if msg.FundCommunityPool != nil {
45 | return msg.FundCommunityPool.Encode(contract)
46 | }
47 | return nil, fmt.Errorf("wasm: invalid custom distribution message")
48 | }
49 |
--------------------------------------------------------------------------------
/internal/wasm/encoder.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/CosmWasm/wasmd/x/wasm"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
9 | )
10 |
11 | // Encoder describes behavior for Stargaze smart contract message encoding.
12 | // The contract address must ALWAYS be set as the Msg signer.
13 | type Encoder func(contract sdk.AccAddress, data json.RawMessage, version string) ([]sdk.Msg, error)
14 |
15 | // MessageEncoders provides stargaze custom encoder for contracts
16 | func MessageEncoders(registry *EncoderRegistry) *wasm.MessageEncoders {
17 | return &wasm.MessageEncoders{
18 | Custom: customEncoders(registry),
19 | }
20 | }
21 |
22 | type MessageEncodeRequest struct {
23 | Route string `json:"route"`
24 | MsgData json.RawMessage `json:"msg_data"`
25 | Version string `json:"version"`
26 | }
27 |
28 | func customEncoders(registry *EncoderRegistry) wasm.CustomEncoder {
29 | return func(sender sdk.AccAddress, m json.RawMessage) ([]sdk.Msg, error) {
30 | encodeRequest := &MessageEncodeRequest{}
31 | err := json.Unmarshal(m, encodeRequest)
32 | if err != nil {
33 | return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
34 | }
35 | encode, exists := registry.encoders[encodeRequest.Route]
36 | if !exists {
37 | return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "encoder not found for route: %s", encodeRequest.Route)
38 | }
39 |
40 | msgs, err := encode(sender, encodeRequest.MsgData, encodeRequest.Version)
41 | if err != nil {
42 | return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
43 | }
44 | for _, msg := range msgs {
45 | if err := msg.ValidateBasic(); err != nil {
46 | return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
47 | }
48 | }
49 | return msgs, nil
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/internal/wasm/registry.go:
--------------------------------------------------------------------------------
1 | package wasm
2 |
3 | import "fmt"
4 |
5 | type EncoderRegistry struct {
6 | encoders map[string]Encoder
7 | }
8 |
9 | // NewEncoderRegistry creates a new registry for message encoders.
10 | func NewEncoderRegistry() *EncoderRegistry {
11 | return &EncoderRegistry{
12 | encoders: make(map[string]Encoder),
13 | }
14 | }
15 |
16 | // RegisterEncoder adds a message encoder for the given route.
17 | func (qr *EncoderRegistry) RegisterEncoder(route string, encoder Encoder) {
18 | if _, exists := qr.encoders[route]; exists {
19 | panic(fmt.Sprintf("wasm: encoder already registered for route: %s", route))
20 | }
21 | qr.encoders[route] = encoder
22 | }
23 |
--------------------------------------------------------------------------------
/mupgrade.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo "=============================================================================="
4 | echo "=============Fetching latest version============="
5 | sudo rm -rf $HOME/mun
6 | cd $HOME && git clone https://github.com/munblockchain/mun.git
7 | echo "=============Compiling binary============="
8 | cd $HOME/mun && make install
9 | mund version
10 | sudo rm -rf /var/log/mund/
11 | cd $HOME/mun && make log-files
12 | echo "=============Preparing binary upgrades============="
13 | mkdir -p $HOME/.mun/upgrade_manager/upgrades/mun-upgrade-v3.0.3/bin
14 | cp $HOME/go/bin/mund $HOME/.mun/upgrade_manager/upgrades/mun-upgrade-v3.0.3/bin/
15 | echo "=============Upgrading service configration============="
16 | sudo sed -i 's/=on/=true/g' /etc/systemd/system/mund.service
17 | sudo sed -i 's/=true-/=on-/g' /etc/systemd/system/mund.service
18 | echo "=============Daemon reloading============="
19 | sudo systemctl daemon-reload
20 | sudo systemctl restart mund.service
21 | echo "=============Done! Please wait until it reaches to upgrade block============="
22 |
--------------------------------------------------------------------------------
/proto/claim/v1beta1/claim_record.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.claim.v1beta1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "cosmos/base/v1beta1/coin.proto";
6 |
7 | option go_package = "mun/x/claim/types";
8 |
9 | enum Action {
10 | option (gogoproto.goproto_enum_prefix) = false;
11 |
12 | ActionInitialClaim = 0;
13 | ActionDelegateStake = 1;
14 | ActionVote = 2;
15 | ActionSwap = 3;
16 | }
17 |
18 | message ClaimRecord {
19 | // address of claim user
20 | string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
21 |
22 | // total initial claimable amount for the user
23 | repeated cosmos.base.v1beta1.Coin initial_claimable_amount = 2 [
24 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
25 | (gogoproto.nullable) = false,
26 | (gogoproto.moretags) = "yaml:\"initial_claimable_amount\""
27 | ];
28 |
29 | // true if action is completed
30 | // index of bool in array refers to action enum #
31 | repeated bool action_completed = 3 [
32 | (gogoproto.moretags) = "yaml:\"action_completed\"",
33 | (gogoproto.nullable) = false
34 | ];
35 |
36 | // true if action is ready to claim
37 | // index of bool in array refers to action enum #
38 | repeated bool action_ready = 4 [
39 | (gogoproto.moretags) = "yaml:\"action_ready\"",
40 | (gogoproto.nullable) = false
41 | ];
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/proto/claim/v1beta1/genesis.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.claim.v1beta1;
3 |
4 | // this line is used by starport scaffolding # genesis/proto/import
5 | import "gogoproto/gogo.proto";
6 | import "cosmos/base/v1beta1/coin.proto";
7 | import "claim/v1beta1/claim_record.proto";
8 | import "claim/v1beta1/params.proto";
9 |
10 | option go_package = "mun/x/claim/types";
11 |
12 | // GenesisState defines the claim module's genesis state.
13 | message GenesisState {
14 | // this line is used by starport scaffolding # genesis/proto/state
15 | // balance of the claim module's account
16 | cosmos.base.v1beta1.Coin module_account_balance = 1 [
17 | (gogoproto.moretags) = "yaml:\"module_account_balance\"",
18 | (gogoproto.nullable) = false
19 | ];
20 |
21 | // params defines all the parameters of the module.
22 | Params params = 2 [
23 | (gogoproto.moretags) = "yaml:\"params\"",
24 | (gogoproto.nullable) = false
25 | ];
26 |
27 | // list of claim records, one for every airdrop recipient
28 | repeated ClaimRecord claim_records = 3 [
29 | (gogoproto.moretags) = "yaml:\"claim_records\"",
30 | (gogoproto.nullable) = false
31 | ];
32 |
33 | string merkle_root = 4;
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/proto/claim/v1beta1/params.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.claim.v1beta1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "google/protobuf/duration.proto";
6 | import "google/protobuf/timestamp.proto";
7 | import "claim/v1beta1/claim_record.proto";
8 |
9 | option go_package = "mun/x/claim/types";
10 |
11 | message ClaimAuthorization {
12 | string contract_address = 1
13 | [ (gogoproto.moretags) = "yaml:\"contract_address\"" ];
14 | Action action = 2 [ (gogoproto.moretags) = "yaml:\"action\"" ];
15 | }
16 |
17 | // Params defines the claim module's parameters.
18 | message Params {
19 | option (gogoproto.goproto_stringer) = false;
20 | bool airdrop_enabled = 1;
21 |
22 | google.protobuf.Timestamp airdrop_start_time = 2 [
23 | (gogoproto.stdtime) = true,
24 | (gogoproto.nullable) = false,
25 | (gogoproto.moretags) = "yaml:\"airdrop_start_time\""
26 | ];
27 | google.protobuf.Duration duration_until_decay = 3 [
28 | (gogoproto.nullable) = false,
29 | (gogoproto.stdduration) = true,
30 | (gogoproto.jsontag) = "duration_until_decay,omitempty",
31 | (gogoproto.moretags) = "yaml:\"duration_until_decay\""
32 | ];
33 | google.protobuf.Duration duration_of_decay = 4 [
34 | (gogoproto.nullable) = false,
35 | (gogoproto.stdduration) = true,
36 | (gogoproto.jsontag) = "duration_of_decay,omitempty",
37 | (gogoproto.moretags) = "yaml:\"duration_of_decay\""
38 | ];
39 |
40 | // denom of claimable asset
41 | string claim_denom = 5;
42 |
43 | // list of contracts and their allowed claim actions
44 | // repeated ClaimAuthorization allowed_claimers = 6 [
45 | // (gogoproto.nullable) = false,
46 | // (gogoproto.jsontag) = "allowed_claimers",
47 | // (gogoproto.moretags) = "yaml:\"allowed_claimers\""
48 | // ];
49 | reserved 6;
50 | }
51 |
--------------------------------------------------------------------------------
/proto/claim/v1beta1/query.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.claim.v1beta1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "google/api/annotations.proto";
6 | import "cosmos/base/v1beta1/coin.proto";
7 | import "claim/v1beta1/claim_record.proto";
8 | import "claim/v1beta1/params.proto";
9 | // this line is used by starport scaffolding # 1
10 |
11 | option go_package = "mun/x/claim/types";
12 |
13 | // Query defines the gRPC querier service.
14 | service Query {
15 | // this line is used by starport scaffolding # 2
16 | rpc ModuleAccountBalance(QueryModuleAccountBalanceRequest)
17 | returns (QueryModuleAccountBalanceResponse) {
18 | option (google.api.http).get =
19 | "/mun/claim/v1beta1/module_account_balance";
20 | }
21 | rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
22 | option (google.api.http).get = "/mun/claim/v1beta1/params";
23 | }
24 | rpc ClaimRecord(QueryClaimRecordRequest) returns (QueryClaimRecordResponse) {
25 | option (google.api.http).get =
26 | "/mun/claim/v1beta1/claim_record/{address}";
27 | }
28 | rpc ClaimableForAction(QueryClaimableForActionRequest) returns (QueryClaimableForActionResponse) {
29 | option (google.api.http).get = "/mun/claim/v1beta1/claimable_for_action/{address}/{action}";
30 | }
31 | rpc TotalClaimable(QueryTotalClaimableRequest) returns (QueryTotalClaimableResponse) {
32 | option (google.api.http).get = "/mun/claim/v1beta1/total_claimable/{address}";
33 | }
34 |
35 | rpc MerkleRoot(QueryMerkleRootRequest) returns (QueryMerkleRootResponse) {
36 | option (google.api.http).get = "/mun/claim/v1beta1/merkle_root";
37 | }
38 |
39 | rpc Whitelisted(QueryWhitelistedRequest) returns (QueryWhitelistedResponse) {
40 | option (google.api.http).get = "/mun/claim/v1beta1/verify/{address}/{proof}";
41 | }
42 | }
43 | // this line is used by starport scaffolding # 3
44 |
45 | // QueryParamsRequest is the request type for the Query/Params RPC method.
46 | message QueryModuleAccountBalanceRequest {}
47 |
48 | // QueryParamsResponse is the response type for the Query/Params RPC method.
49 | message QueryModuleAccountBalanceResponse {
50 | // params defines the parameters of the module.
51 | repeated cosmos.base.v1beta1.Coin moduleAccountBalance = 1 [
52 | (gogoproto.moretags) = "yaml:\"coins\"",
53 | (gogoproto.nullable) = false,
54 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
55 | ];
56 | }
57 |
58 | // QueryParamsRequest is the request type for the Query/Params RPC method.
59 | message QueryParamsRequest {}
60 |
61 | // QueryParamsResponse is the response type for the Query/Params RPC method.
62 | message QueryParamsResponse {
63 | // params defines the parameters of the module.
64 | Params params = 1 [ (gogoproto.nullable) = false ];
65 | }
66 |
67 | message QueryClaimRecordRequest {
68 | string address = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ];
69 | }
70 |
71 | message QueryClaimRecordResponse {
72 | ClaimRecord claim_record = 1 [
73 | (gogoproto.moretags) = "yaml:\"claim_record\"",
74 | (gogoproto.nullable) = false
75 | ];
76 | }
77 |
78 | message QueryClaimableForActionRequest {
79 | string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
80 | Action action = 2 [ (gogoproto.moretags) = "yaml:\"action\"" ];
81 | }
82 |
83 | message QueryClaimableForActionResponse {
84 | repeated cosmos.base.v1beta1.Coin coins = 1 [
85 | (gogoproto.moretags) = "yaml:\"coins\"",
86 | (gogoproto.nullable) = false,
87 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
88 | ];
89 | }
90 |
91 | message QueryTotalClaimableRequest {
92 | string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
93 | }
94 |
95 | message QueryTotalClaimableResponse {
96 | repeated cosmos.base.v1beta1.Coin coins = 1 [
97 | (gogoproto.moretags) = "yaml:\"coins\"",
98 | (gogoproto.nullable) = false,
99 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
100 | ];
101 | }
102 |
103 | message QueryMerkleRootRequest {
104 | }
105 |
106 | message QueryMerkleRootResponse {
107 | string merkle_root = 1;
108 | }
109 |
110 | message QueryWhitelistedRequest {
111 | string address = 1;
112 | string proof = 2;
113 | }
114 |
115 | message QueryWhitelistedResponse {
116 | bool whitelisted = 1;
117 | }
--------------------------------------------------------------------------------
/proto/claim/v1beta1/tx.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.claim.v1beta1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "cosmos/base/v1beta1/coin.proto";
6 | import "claim/v1beta1/claim_record.proto";
7 |
8 | // this line is used by starport scaffolding # proto/tx/import
9 |
10 | option go_package = "mun/x/claim/types";
11 |
12 | // Msg defines the Msg service.
13 | service Msg {
14 | // rpc InitialClaim(MsgInitialClaim) returns (MsgInitialClaimResponse);
15 | rpc ClaimFor(MsgClaimFor) returns (MsgClaimForResponse);
16 | rpc UpdateMerkleRoot(MsgUpdateMerkleRoot) returns (MsgUpdateMerkleRootResponse);
17 | // this line is used by starport scaffolding # proto/tx/rpc
18 | }
19 |
20 | message MsgClaimFor {
21 | string sender = 1;
22 | Action action = 2;
23 | string proof = 3;
24 | }
25 |
26 | message MsgClaimForResponse {
27 | string address = 1;
28 | // total initial claimable amount for the user
29 | repeated cosmos.base.v1beta1.Coin claimed_amount = 2 [
30 | (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
31 | (gogoproto.nullable) = false,
32 | (gogoproto.moretags) = "yaml:\"claimed_amount\""
33 | ];
34 | }
35 |
36 | message MsgUpdateMerkleRoot {
37 | string sender = 1;
38 | string root_value = 2;
39 | }
40 |
41 | message MsgUpdateMerkleRootResponse {}
--------------------------------------------------------------------------------
/proto/ibank/genesis.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.ibank;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "ibank/params.proto";
6 | import "ibank/transaction.proto";
7 | // this line is used by starport scaffolding # genesis/proto/import
8 |
9 | option go_package = "mun/x/ibank/types";
10 |
11 | // GenesisState defines the ibank module's genesis state.
12 | message GenesisState {
13 | Params params = 1 [(gogoproto.nullable) = false];
14 | repeated Transaction transactionList = 2 [(gogoproto.nullable) = false];
15 | uint64 transactionCount = 3;
16 | uint64 transactionChaser = 4;
17 | // this line is used by starport scaffolding # genesis/proto/state
18 | }
19 |
--------------------------------------------------------------------------------
/proto/ibank/params.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.ibank;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "google/protobuf/duration.proto";
6 |
7 | option go_package = "mun/x/ibank/types";
8 |
9 | // Params defines the parameters for the module.
10 | message Params {
11 | option (gogoproto.goproto_stringer) = false;
12 |
13 | google.protobuf.Duration duration_of_expiration = 1 [
14 | (gogoproto.nullable) = false,
15 | (gogoproto.stdduration) = true,
16 | (gogoproto.jsontag) = "duration_of_expiration,omitempty",
17 | (gogoproto.moretags) = "yaml:\"duration_of_expiration\""
18 | ];
19 | }
20 |
--------------------------------------------------------------------------------
/proto/ibank/query.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.ibank;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "google/api/annotations.proto";
6 | import "cosmos/base/query/v1beta1/pagination.proto";
7 | import "ibank/params.proto";
8 | import "ibank/transaction.proto";
9 | // this line is used by starport scaffolding # 1
10 |
11 | option go_package = "mun/x/ibank/types";
12 |
13 | // Query defines the gRPC querier service.
14 | service Query {
15 | // Parameters queries the parameters of the module.
16 | rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
17 | option (google.api.http).get = "/mun/ibank/params";
18 | }
19 | // Queries a Transaction by id.
20 | rpc Transaction(QueryGetTransactionRequest) returns (QueryGetTransactionResponse) {
21 | option (google.api.http).get = "/mun/ibank/transaction/{id}";
22 | }
23 |
24 | // Queries a list of Transaction items.
25 | rpc TransactionAll(QueryAllTransactionRequest) returns (QueryAllTransactionResponse) {
26 | option (google.api.http).get = "/mun/ibank/transaction_all/{address}";
27 | }
28 |
29 | // Queries a list of ShowIncoming items.
30 | rpc Incoming(QueryIncomingRequest) returns (QueryIncomingResponse) {
31 | option (google.api.http).get = "/mun/ibank/incoming/{receiver}/{pending}";
32 | }
33 |
34 | // Queries a list of ShowOutgoing items.
35 | rpc Outgoing(QueryOutgoingRequest) returns (QueryOutgoingResponse) {
36 | option (google.api.http).get = "/mun/ibank/outgoing/{sender}/{pending}";
37 | }
38 |
39 | // this line is used by starport scaffolding # 2
40 | }
41 |
42 | // QueryParamsRequest is request type for the Query/Params RPC method.
43 | message QueryParamsRequest {}
44 |
45 | // QueryParamsResponse is response type for the Query/Params RPC method.
46 | message QueryParamsResponse {
47 | // params holds all the parameters of this module.
48 | Params params = 1 [(gogoproto.nullable) = false];
49 | }
50 |
51 | message QueryGetTransactionRequest {
52 | uint64 id = 1;
53 | }
54 |
55 | message QueryGetTransactionResponse {
56 | Transaction transaction = 1 [(gogoproto.nullable) = false];
57 | }
58 |
59 | message QueryAllTransactionRequest {
60 | string address = 1;
61 | cosmos.base.query.v1beta1.PageRequest pagination = 2;
62 | }
63 |
64 | message QueryAllTransactionResponse {
65 | repeated TransactionWrapper transactions = 1 [(gogoproto.nullable) = false];
66 | cosmos.base.query.v1beta1.PageResponse pagination = 2;
67 | }
68 |
69 | message QueryIncomingRequest {
70 | string receiver = 1;
71 | bool pending = 2;
72 | cosmos.base.query.v1beta1.PageRequest pagination = 3;
73 | }
74 |
75 | message QueryIncomingResponse {
76 | repeated TransactionWrapper transactions = 1 [(gogoproto.nullable) = false];
77 | cosmos.base.query.v1beta1.PageResponse pagination = 2;
78 | }
79 |
80 | message TransactionWrapper {
81 | Transaction transaction = 1 [(gogoproto.nullable) = false];
82 | uint32 time_left = 2;
83 | }
84 |
85 | message QueryOutgoingRequest {
86 | string sender = 1;
87 | bool pending = 2;
88 | cosmos.base.query.v1beta1.PageRequest pagination = 3;
89 | }
90 |
91 | message QueryOutgoingResponse {
92 | repeated TransactionWrapper transactions = 1 [(gogoproto.nullable) = false];
93 | cosmos.base.query.v1beta1.PageResponse pagination = 2;
94 | }
95 |
96 | // this line is used by starport scaffolding # 3
97 |
--------------------------------------------------------------------------------
/proto/ibank/transaction.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.ibank;
3 |
4 | option go_package = "mun/x/ibank/types";
5 | import "gogoproto/gogo.proto";
6 | import "cosmos/base/v1beta1/coin.proto";
7 | import "google/protobuf/timestamp.proto";
8 |
9 | enum TxnStatus {
10 | TXN_PENDING = 0;
11 | TXN_SENT = 1;
12 | TXN_EXPIRED = 2;
13 | TXN_DECLINED = 3;
14 | }
15 |
16 | message Transaction {
17 | uint64 id = 1;
18 | string sender = 2;
19 | google.protobuf.Timestamp sent_at = 3 [
20 | (gogoproto.stdtime) = true,
21 | (gogoproto.nullable) = false
22 | ];
23 |
24 | string receiver = 4;
25 | // If sent_at is equal to received_at, transaction have not been performed
26 | google.protobuf.Timestamp received_at = 5 [
27 | (gogoproto.stdtime) = true,
28 | (gogoproto.nullable) = false
29 | ];
30 | repeated cosmos.base.v1beta1.Coin coins = 6 [(gogoproto.nullable) = false];
31 | TxnStatus status = 7;
32 |
33 | // hash value of 6 word password
34 | string password = 8;
35 | int32 retry = 9;
36 | }
37 |
--------------------------------------------------------------------------------
/proto/ibank/tx.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package mun.ibank;
3 |
4 | // this line is used by starport scaffolding # proto/tx/import
5 | import "cosmos/base/v1beta1/coin.proto";
6 | import "gogoproto/gogo.proto";
7 |
8 | option go_package = "mun/x/ibank/types";
9 |
10 | // Msg defines the Msg service.
11 | service Msg {
12 | rpc Send(MsgSend) returns (MsgSendResponse);
13 | rpc Receive(MsgReceive) returns (MsgReceiveResponse);
14 | // this line is used by starport scaffolding # proto/tx/rpc
15 | }
16 |
17 | message MsgSend {
18 | string from_address = 1;
19 | string to_address = 2;
20 | cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
21 | string password_hash = 4;
22 | }
23 |
24 | message MsgSendResponse {
25 | }
26 |
27 | message MsgReceive {
28 | string receiver = 1;
29 | int64 transaction_id = 2;
30 | string password = 3;
31 | }
32 |
33 | message MsgReceiveResponse {
34 | }
35 |
36 | // this line is used by starport scaffolding # proto/tx/message
37 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # How to join Munchain network
2 | ## Infrastructure
3 | ```
4 | **Recommended configuration:**
5 | - Number of CPUs: 4
6 | - Memory: 16GB
7 | - OS: Ubuntu 22.04 LTS
8 | - Allow all incoming connections from TCP port 26656 and 26657
9 | - Static IP address
10 | - The recommended configuration from AWS is the equivalent of a t2.large machine with 500 GB HD
11 | ```
12 |
13 | ## Installing prerequisites
14 | ```
15 | sudo apt update
16 | sudo apt upgrade -y
17 | sudo apt install build-essential jq -y
18 | ```
19 |
20 | ## Install Golang:
21 |
22 | ## Install go version 1.20 https://golang.org/doc/install
23 | ```
24 | wget -q -O - https://raw.githubusercontent.com/canha/golang-tools-install-script/master/goinstall.sh | bash -s -- --version 1.20
25 | source ~/.profile
26 | ```
27 |
28 | ## To verify that Golang installed
29 | ```
30 | go version
31 | ```
32 | // Should return go version go1.20 linux/amd64
33 |
34 | ## Clone repository
35 | ```
36 | git clone https://github.com/munblockchain/mun
37 | cd mun
38 | ```
39 |
40 | ## Install the executables
41 |
42 | ```
43 | sudo rm -rf ~/.mun
44 | go mod tidy
45 | make install
46 |
47 | clear
48 |
49 | mkdir -p ~/.mun/upgrade_manager/upgrades
50 | mkdir -p ~/.mun/upgrade_manager/genesis/bin
51 | ```
52 |
53 | ## Symlink genesis binary to upgrade
54 | ```
55 | cp $(which mund) ~/.mun/upgrade_manager/genesis/bin
56 | sudo cp $(which mund-manager) /usr/bin
57 | ```
58 |
59 | ## Initialize the validator with a moniker name(Example moniker: solid-moon-rock)
60 | ```
61 | mund init [moniker_name] --chain-id testmun-3
62 | ```
63 |
64 | ## Add a new wallet address, store seeds and buy TMUN to it.
65 | ```
66 | mund keys add [wallet_name] --keyring-backend test
67 | ```
68 |
69 | ## Fetch genesis.json from genesis node
70 | curl http://31.14.40.191/data/genesis_3093970.json --output ~/.mun/config/genesis.json
71 |
72 | ## Update seed in config.toml to make p2p connection
73 | ```
74 | nano ~/.mun/config/config.toml
75 | seeds = "74bea3fc80aa128c9a757873f2348baa23e9921a@157.245.77.89:26656"
76 | ```
77 | ## Join our Discord and ask for the validator role to get access to more seeds!
78 |
79 | ## Create the service file "/etc/systemd/system/mund.service" with the following content
80 | ```
81 | sudo nano /etc/systemd/system/mund.service
82 | ```
83 |
84 | ## Paste following content(*Please make sure to use correct name of user, group and DAEMON_HOME path at the below.)
85 | ```
86 | [Unit]
87 | Description=mund
88 | Requires=network-online.target
89 | After=network-online.target
90 |
91 | [Service]
92 | Restart=on-failure
93 | RestartSec=3
94 | User=root
95 | Group=root
96 | Environment=DAEMON_NAME=mund
97 | Environment=DAEMON_HOME=/root/.mun
98 | Environment=DAEMON_ALLOW_DOWNLOAD_BINARIES=on
99 | Environment=DAEMON_RESTART_AFTER_UPGRADE=on
100 | PermissionsStartOnly=true
101 | ExecStart=/usr/bin/mund-manager start --pruning="nothing" --rpc.laddr "tcp://0.0.0.0:26657"
102 | StandardOutput=file:/var/log/mund/mund.log
103 | StandardError=file:/var/log/mund/mund_error.log
104 | ExecReload=/bin/kill -HUP $MAINPID
105 | KillSignal=SIGTERM
106 | LimitNOFILE=4096
107 |
108 | [Install]
109 | WantedBy=multi-user.target
110 | ```
111 | **Tips**
112 | - How to get user and group name
113 | ```
114 | whoami
115 | ```
116 | - How to get DAEMON_HOME path
117 | ```
118 | cd ~/.mun
119 | pwd
120 | ```
121 |
122 | ## Create log files and starts running the node
123 | ```
124 | make log-files
125 |
126 | sudo systemctl enable mund
127 | sudo systemctl start mund
128 | ```
129 |
130 | ## Verify node is running properly
131 | ```
132 | mund status
133 | ```
134 |
135 | ## After buying TMUN, stake it to become a validator.
136 | **Tips**
137 |
138 | You should wait until the node gets fully synchronized with other nodes. You can cross check with the genesis node by visiting https://node1.mun.money/status and check the latest block height. You can also check your node status through this link http://[Your_Node_IP]:26657/status.
139 |
140 |
141 | **A transaction to become a validator by staking TMUN**
142 |
143 | ```
144 | mund tx staking create-validator --from [wallet_name] --moniker [moniker_name] --pubkey $(mund tendermint show-validator) --chain-id testmun-3 --keyring-backend test --amount 2000000000000000utmun --commission-max-change-rate 0.01 --commission-max-rate 0.2 --commission-rate 0.1 --min-self-delegation 1 --fees 20000utmun -y
145 | ```
146 |
--------------------------------------------------------------------------------
/testutil/nullify/nullify.go:
--------------------------------------------------------------------------------
1 | // Package nullify provides methods to init nil values structs for test assertion.
2 | package nullify
3 |
4 | import (
5 | "reflect"
6 | "unsafe"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | var (
12 | coinType = reflect.TypeOf(sdk.Coin{})
13 | coinsType = reflect.TypeOf(sdk.Coins{})
14 | )
15 |
16 | // Fill analyze all struct fields and slices with
17 | // reflection and initialize the nil and empty slices,
18 | // structs, and pointers.
19 | func Fill(x interface{}) interface{} {
20 | v := reflect.Indirect(reflect.ValueOf(x))
21 | switch v.Kind() {
22 | case reflect.Slice:
23 | for i := 0; i < v.Len(); i++ {
24 | obj := v.Index(i)
25 | objPt := reflect.NewAt(obj.Type(), unsafe.Pointer(obj.UnsafeAddr())).Interface()
26 | objPt = Fill(objPt)
27 | obj.Set(reflect.ValueOf(objPt))
28 | }
29 | case reflect.Struct:
30 | for i := 0; i < v.NumField(); i++ {
31 | f := reflect.Indirect(v.Field(i))
32 | if !f.CanSet() {
33 | continue
34 | }
35 | switch f.Kind() {
36 | case reflect.Slice:
37 | f.Set(reflect.MakeSlice(f.Type(), 0, 0))
38 | case reflect.Struct:
39 | switch f.Type() {
40 | case coinType:
41 | coin := reflect.New(coinType).Interface()
42 | s := reflect.ValueOf(coin).Elem()
43 | f.Set(s)
44 | case coinsType:
45 | coins := reflect.New(coinsType).Interface()
46 | s := reflect.ValueOf(coins).Elem()
47 | f.Set(s)
48 | default:
49 | objPt := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Interface()
50 | s := Fill(objPt)
51 | f.Set(reflect.ValueOf(s))
52 | }
53 | }
54 | }
55 | }
56 | return reflect.Indirect(v).Interface()
57 | }
58 |
--------------------------------------------------------------------------------
/upgrade.md:
--------------------------------------------------------------------------------
1 | # How to upgrade to mun-upgrade-v3
2 | ## 1. Vote 'yes' to upgrade proposal
3 | ```
4 | mund tx gov vote [proposal_id] yes --from [wallet_name] --chain-id testmun --keyring-backend test -y
5 | ```
6 |
7 | ## 2. Upgrade binary
8 | ```
9 | wget -O update.sh https://raw.githubusercontent.com/munblockchain/mun/main/mupgrade.sh && chmod +x update.sh && sh update.sh
10 | ```
11 |
12 | ## 3. Done, It will be upgraded when Munchain reaches to the upgrade block height.
13 |
--------------------------------------------------------------------------------
/x/claim/abci.go:
--------------------------------------------------------------------------------
1 | package claim
2 |
3 | import (
4 | "mun/x/claim/keeper"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // EndBlocker called every block, process inflation, update validator set.
10 | func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
11 | params := k.GetParams(ctx)
12 | if !params.IsAirdropEnabled(ctx.BlockTime()) {
13 | return
14 | }
15 | // End Airdrop
16 | goneTime := ctx.BlockTime().Sub(params.AirdropStartTime)
17 | if goneTime > params.DurationUntilDecay+params.DurationOfDecay {
18 | // airdrop time passed
19 | err := k.EndAirdrop(ctx)
20 | if err != nil {
21 | panic(err)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/x/claim/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/spf13/cobra"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | // "github.com/cosmos/cosmos-sdk/client/flags"
11 | "mun/x/claim/types"
12 | )
13 |
14 | var DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds())
15 |
16 | // GetTxCmd returns the transaction commands for this module
17 | func GetTxCmd() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: types.ModuleName,
20 | Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
21 | DisableFlagParsing: true,
22 | SuggestionsMinimumDistance: 2,
23 | RunE: client.ValidateCmd,
24 | }
25 |
26 | cmd.AddCommand(CmdClaimFor())
27 | cmd.AddCommand(CmdUpdateMerkleRoot())
28 | // this line is used by starport scaffolding # 1
29 |
30 | return cmd
31 | }
32 |
--------------------------------------------------------------------------------
/x/claim/client/cli/tx_claim_for.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "github.com/spf13/cobra"
7 |
8 | "mun/x/claim/types"
9 |
10 | "github.com/cosmos/cosmos-sdk/client"
11 | "github.com/cosmos/cosmos-sdk/client/flags"
12 | "github.com/cosmos/cosmos-sdk/client/tx"
13 | )
14 |
15 | var _ = strconv.Itoa(0)
16 |
17 | func CmdClaimFor() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: "claim-for [action=0:InitialClaim,1:Staking,2:Voting]",
20 | Short: "Claim For Action",
21 | Args: cobra.ExactArgs(1),
22 | RunE: func(cmd *cobra.Command, args []string) (err error) {
23 | clientCtx, err := client.GetClientTxContext(cmd)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | action, err := strconv.ParseInt(args[0], 10, 64)
29 | if err != nil {
30 | return err
31 | }
32 |
33 | var typeAction types.Action
34 | var proof string
35 | switch action {
36 | case 1:
37 | typeAction = types.ActionDelegateStake
38 | case 2:
39 | typeAction = types.ActionVote
40 | default:
41 | typeAction = types.ActionInitialClaim
42 | proof = cmd.Flags().Lookup("proof").Value.String()
43 | }
44 |
45 | msg := types.NewMsgClaimFor(
46 | clientCtx.GetFromAddress().String(),
47 | typeAction,
48 | proof,
49 | )
50 |
51 | if err := msg.ValidateBasic(); err != nil {
52 | return err
53 | }
54 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
55 | },
56 | }
57 | cmd.Flags().String("proof", "", "Proof for initial claim")
58 |
59 | flags.AddTxFlagsToCmd(cmd)
60 |
61 | return cmd
62 | }
63 |
--------------------------------------------------------------------------------
/x/claim/client/cli/tx_update_merkle_root.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "github.com/spf13/cobra"
7 |
8 | "mun/x/claim/types"
9 |
10 | "github.com/cosmos/cosmos-sdk/client"
11 | "github.com/cosmos/cosmos-sdk/client/flags"
12 | "github.com/cosmos/cosmos-sdk/client/tx"
13 | )
14 |
15 | var _ = strconv.Itoa(0)
16 |
17 | func CmdUpdateMerkleRoot() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: "update-merkle-root [hash]",
20 | Short: "Update merkle root for initial airdrop",
21 | Args: cobra.ExactArgs(1),
22 | RunE: func(cmd *cobra.Command, args []string) (err error) {
23 | clientCtx, err := client.GetClientTxContext(cmd)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | msg := types.NewMsgUpdateMerkleRoot(
29 | clientCtx.GetFromAddress().String(),
30 | args[0],
31 | )
32 |
33 | if err := msg.ValidateBasic(); err != nil {
34 | return err
35 | }
36 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
37 | },
38 | }
39 |
40 | flags.AddTxFlagsToCmd(cmd)
41 |
42 | return cmd
43 | }
44 |
--------------------------------------------------------------------------------
/x/claim/handler.go:
--------------------------------------------------------------------------------
1 | package claim
2 |
3 | import (
4 | "fmt"
5 |
6 | "mun/x/claim/keeper"
7 | "mun/x/claim/types"
8 |
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
11 | )
12 |
13 | // NewHandler ...
14 | func NewHandler(k keeper.Keeper) sdk.Handler {
15 | // this line is used by starport scaffolding # handler/msgServer
16 | msgServer := keeper.NewMsgServerImpl(k)
17 | // this line is used by starport scaffolding # handler/msgServer
18 |
19 | return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
20 | ctx = ctx.WithEventManager(sdk.NewEventManager())
21 | switch msg := msg.(type) {
22 | case *types.MsgUpdateMerkleRoot:
23 | res, err := msgServer.UpdateMerkleRoot(sdk.WrapSDKContext(ctx), msg)
24 | return sdk.WrapServiceResult(ctx, res, err)
25 | case *types.MsgClaimFor:
26 | res, err := msgServer.ClaimFor(sdk.WrapSDKContext(ctx), msg)
27 | return sdk.WrapServiceResult(ctx, res, err)
28 | // this line is used by starport scaffolding # 1
29 | default:
30 | errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg)
31 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/x/claim/keeper/genesis.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "time"
5 |
6 | "mun/x/claim/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | abci "github.com/tendermint/tendermint/abci/types"
10 | )
11 |
12 | func (k Keeper) InitGenesis(ctx sdk.Context, data types.GenesisState) []abci.ValidatorUpdate {
13 | k.CreateModuleAccount(ctx, data.ModuleAccountBalance)
14 | if data.Params.AirdropEnabled && data.Params.AirdropStartTime.Equal(time.Time{}) {
15 | data.Params.AirdropStartTime = ctx.BlockTime()
16 | }
17 | err := k.SetClaimRecords(ctx, data.ClaimRecords)
18 | if err != nil {
19 | panic(err)
20 | }
21 | k.SetMerkleRoot(ctx, data.MerkleRoot)
22 | k.SetParams(ctx, data.Params)
23 | return nil
24 | }
25 |
26 | func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
27 | genesis := types.DefaultGenesis()
28 |
29 | // this line is used by starport scaffolding # genesis/module/export
30 | params := k.GetParams(ctx)
31 | genesis.ModuleAccountBalance = k.GetModuleAccountBalance(ctx)
32 | genesis.Params = params
33 | genesis.ClaimRecords = k.ClaimRecords(ctx)
34 | genesis.MerkleRoot = k.GetMerkleRoot(ctx)
35 | return genesis
36 | }
37 |
--------------------------------------------------------------------------------
/x/claim/keeper/grpc_query.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/claim/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "google.golang.org/grpc/codes"
10 | "google.golang.org/grpc/status"
11 | )
12 |
13 | var _ types.QueryServer = Keeper{}
14 |
15 | // Params returns params of the mint module.
16 | func (k Keeper) ModuleAccountBalance(c context.Context, _ *types.QueryModuleAccountBalanceRequest) (*types.QueryModuleAccountBalanceResponse, error) {
17 | ctx := sdk.UnwrapSDKContext(c)
18 | moduleAccBal := sdk.NewCoins(k.GetModuleAccountBalance(ctx))
19 |
20 | return &types.QueryModuleAccountBalanceResponse{ModuleAccountBalance: moduleAccBal}, nil
21 | }
22 |
23 | // Params returns params of the mint module.
24 | func (k Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
25 | ctx := sdk.UnwrapSDKContext(c)
26 | params := k.GetParams(ctx)
27 |
28 | return &types.QueryParamsResponse{Params: params}, nil
29 | }
30 |
31 | // Claimable returns claimable amount per user
32 | func (k Keeper) ClaimRecord(
33 | goCtx context.Context,
34 | req *types.QueryClaimRecordRequest,
35 | ) (*types.QueryClaimRecordResponse, error) {
36 | if req == nil {
37 | return nil, status.Error(codes.InvalidArgument, "empty request")
38 | }
39 |
40 | ctx := sdk.UnwrapSDKContext(goCtx)
41 |
42 | addr, err := sdk.AccAddressFromBech32(req.Address)
43 | if err != nil {
44 | return nil, err
45 | }
46 |
47 | claimRecord, err := k.GetClaimRecord(ctx, addr)
48 | return &types.QueryClaimRecordResponse{ClaimRecord: claimRecord}, err
49 | }
50 |
51 | // Activities returns activities
52 | func (k Keeper) ClaimableForAction(
53 | goCtx context.Context,
54 | req *types.QueryClaimableForActionRequest,
55 | ) (*types.QueryClaimableForActionResponse, error) {
56 | if req == nil {
57 | return nil, status.Error(codes.InvalidArgument, "empty request")
58 | }
59 |
60 | ctx := sdk.UnwrapSDKContext(goCtx)
61 | addr, err := sdk.AccAddressFromBech32(req.Address)
62 | if err != nil {
63 | return nil, err
64 | }
65 |
66 | coins, err := k.GetClaimableAmountForAction(ctx, addr, req.Action)
67 |
68 | return &types.QueryClaimableForActionResponse{
69 | Coins: coins,
70 | }, err
71 | }
72 |
73 | // Activities returns activities
74 | func (k Keeper) TotalClaimable(
75 | goCtx context.Context,
76 | req *types.QueryTotalClaimableRequest,
77 | ) (*types.QueryTotalClaimableResponse, error) {
78 | if req == nil {
79 | return nil, status.Error(codes.InvalidArgument, "empty request")
80 | }
81 |
82 | ctx := sdk.UnwrapSDKContext(goCtx)
83 | addr, err := sdk.AccAddressFromBech32(req.Address)
84 | if err != nil {
85 | return nil, err
86 | }
87 |
88 | coins, err := k.GetUserTotalClaimable(ctx, addr)
89 |
90 | return &types.QueryTotalClaimableResponse{
91 | Coins: coins,
92 | }, err
93 | }
94 |
--------------------------------------------------------------------------------
/x/claim/keeper/grpc_query_merkle.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 | "mun/x/claim/types"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "google.golang.org/grpc/codes"
9 | "google.golang.org/grpc/status"
10 | )
11 |
12 | func (k Keeper) MerkleRoot(
13 | goCtx context.Context,
14 | req *types.QueryMerkleRootRequest,
15 | ) (*types.QueryMerkleRootResponse, error) {
16 | if req == nil {
17 | return nil, status.Error(codes.InvalidArgument, "empty request")
18 | }
19 |
20 | ctx := sdk.UnwrapSDKContext(goCtx)
21 | return &types.QueryMerkleRootResponse{
22 | MerkleRoot: k.GetMerkleRoot(ctx),
23 | }, nil
24 | }
25 |
26 | func (k Keeper) Whitelisted(goCtx context.Context,
27 | req *types.QueryWhitelistedRequest,
28 | ) (*types.QueryWhitelistedResponse, error) {
29 | ctx := sdk.UnwrapSDKContext(goCtx)
30 | merkleRoot := k.GetMerkleRoot(ctx)
31 |
32 | return &types.QueryWhitelistedResponse{
33 | Whitelisted: k.VerifyMerkleTree(merkleRoot, req.Address, req.Proof),
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/x/claim/keeper/hooks.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/claim/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
8 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
9 | )
10 |
11 | func (k Keeper) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
12 | ret := k.SetClaimableActionReady(ctx, voterAddr, types.ActionVote)
13 | if !ret {
14 | panic("err.Error()")
15 | }
16 | }
17 |
18 | func (k Keeper) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
19 | // must not run on genesis
20 | if ctx.BlockHeight() <= 1 {
21 | return
22 | }
23 | ret := k.SetClaimableActionReady(ctx, delAddr, types.ActionDelegateStake)
24 | if !ret {
25 | panic("err.Error()")
26 | }
27 | }
28 |
29 | // ________________________________________________________________________________________
30 |
31 | // Hooks wrapper struct for slashing keeper
32 | type Hooks struct {
33 | k Keeper
34 | }
35 |
36 | var (
37 | _ govtypes.GovHooks = Hooks{}
38 | _ stakingtypes.StakingHooks = Hooks{}
39 | )
40 |
41 | // Return the wrapper struct
42 | func (k Keeper) Hooks() Hooks {
43 | return Hooks{k}
44 | }
45 |
46 | // governance hooks
47 | func (h Hooks) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) {}
48 |
49 | func (h Hooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) {
50 | }
51 |
52 | func (h Hooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
53 | h.k.AfterProposalVote(ctx, proposalID, voterAddr)
54 | }
55 |
56 | func (h Hooks) AfterProposalInactive(ctx sdk.Context, proposalID uint64) {}
57 | func (h Hooks) AfterProposalActive(ctx sdk.Context, proposalID uint64) {}
58 |
59 | func (h Hooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) {}
60 | func (h Hooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) {}
61 |
62 | // staking hooks
63 | func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
64 | func (h Hooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
65 | func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
66 | }
67 |
68 | func (h Hooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
69 | }
70 |
71 | func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
72 | }
73 |
74 | func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
75 | }
76 |
77 | func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
78 | }
79 |
80 | func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
81 | }
82 |
83 | func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
84 | h.k.AfterDelegationModified(ctx, delAddr, valAddr)
85 | }
86 | func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {}
87 |
--------------------------------------------------------------------------------
/x/claim/keeper/keeper.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/tendermint/tendermint/libs/log"
7 |
8 | "mun/x/claim/types"
9 |
10 | "github.com/cosmos/cosmos-sdk/codec"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
13 | )
14 |
15 | type (
16 | Keeper struct {
17 | cdc codec.Codec
18 | storeKey sdk.StoreKey
19 |
20 | accountKeeper types.AccountKeeper
21 | bankKeeper types.BankKeeper
22 | stakingKeeper types.StakingKeeper
23 | distrKeeper types.DistrKeeper
24 |
25 | paramstore paramtypes.Subspace
26 | }
27 | )
28 |
29 | func NewKeeper(
30 | cdc codec.Codec,
31 | storeKey sdk.StoreKey,
32 | accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper,
33 | stakingKeeper types.StakingKeeper, distrKeeper types.DistrKeeper,
34 | ps paramtypes.Subspace,
35 | ) *Keeper {
36 | // set KeyTable if it has not already been set
37 | if !ps.HasKeyTable() {
38 | ps = ps.WithKeyTable(types.ParamKeyTable())
39 | }
40 |
41 | return &Keeper{
42 | cdc: cdc,
43 | storeKey: storeKey,
44 | accountKeeper: accountKeeper,
45 | bankKeeper: bankKeeper,
46 | stakingKeeper: stakingKeeper,
47 | distrKeeper: distrKeeper,
48 | paramstore: ps,
49 | }
50 | }
51 |
52 | func (k Keeper) Logger(ctx sdk.Context) log.Logger {
53 | return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
54 | }
55 |
56 | // GetModuleAccountBalance gets the airdrop coin balance of module account
57 | func (k Keeper) GetModuleAccountAddress(ctx sdk.Context) sdk.AccAddress {
58 | return k.accountKeeper.GetModuleAddress(types.ModuleName)
59 | }
60 |
61 | // GetModuleAccountBalance gets the airdrop coin balance of module account
62 | func (k Keeper) GetModuleAccountBalance(ctx sdk.Context) sdk.Coin {
63 | moduleAccAddr := k.GetModuleAccountAddress(ctx)
64 | params := k.GetParams(ctx)
65 | return k.bankKeeper.GetBalance(ctx, moduleAccAddr, params.ClaimDenom)
66 | }
67 |
--------------------------------------------------------------------------------
/x/claim/keeper/merkle.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "bytes"
5 | "crypto/sha256"
6 | "errors"
7 | )
8 |
9 | func calcSha256(data []byte) []byte {
10 | s := sha256.Sum256(data)
11 | return s[:]
12 | }
13 |
14 | func VerifyProof(data []byte, hashes [][]byte, root []byte, dirs string) (bool, error) {
15 | dataHash := calcSha256(data)
16 | if len(hashes) != len(dirs) {
17 | return false, errors.New("invalid proof")
18 | }
19 |
20 | for i, hash := range hashes {
21 | if dirs[i] == 'R' {
22 | dataHash = calcSha256(append(dataHash, hash...))
23 | } else {
24 | dataHash = calcSha256(append(hash, dataHash...))
25 | }
26 | }
27 | return bytes.Equal(dataHash, root), nil
28 | }
29 |
--------------------------------------------------------------------------------
/x/claim/keeper/msg_server.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/claim/types"
5 | )
6 |
7 | type msgServer struct {
8 | Keeper
9 | }
10 |
11 | // NewMsgServerImpl returns an implementation of the MsgServer interface
12 | // for the provided Keeper.
13 | func NewMsgServerImpl(keeper Keeper) types.MsgServer {
14 | return &msgServer{Keeper: keeper}
15 | }
16 |
17 | var _ types.MsgServer = msgServer{}
18 |
--------------------------------------------------------------------------------
/x/claim/keeper/msg_server_claim_for.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/claim/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | func (k msgServer) ClaimFor(goCtx context.Context, msg *types.MsgClaimFor) (*types.MsgClaimForResponse, error) {
12 | ctx := sdk.UnwrapSDKContext(goCtx)
13 | address, err := sdk.AccAddressFromBech32(msg.Sender)
14 | if err != nil {
15 | return nil, err
16 | }
17 | params := k.GetParams(ctx)
18 | if !params.IsAirdropEnabled(ctx.BlockTime()) {
19 | return nil, types.ErrAirdropNotEnabled
20 | }
21 |
22 | // Check if whitelisted for Initial Claim
23 | if msg.GetAction() == types.ActionInitialClaim {
24 | merkleRoot := k.Keeper.GetMerkleRoot(ctx)
25 | if !k.Keeper.VerifyMerkleTree(merkleRoot, msg.Sender, msg.GetProof()) {
26 | return nil, types.ErrUnauthorizedClaimer
27 | }
28 | }
29 |
30 | coins, err := k.Keeper.ClaimCoinsForAction(ctx, address, msg.GetAction())
31 | if err != nil {
32 | return nil, err
33 | }
34 | ctx.EventManager().EmitEvents(sdk.Events{
35 | sdk.NewEvent(
36 | sdk.EventTypeMessage,
37 | sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
38 | sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
39 | ),
40 | })
41 | return &types.MsgClaimForResponse{
42 | Address: msg.Sender,
43 | ClaimedAmount: coins,
44 | }, nil
45 | }
46 |
--------------------------------------------------------------------------------
/x/claim/keeper/msg_server_update_merkle_root.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 | "mun/x/claim/types"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | )
9 |
10 | const (
11 | AdminAddress = "mun1g5azxlyk6hnurr627xqd4n6efwjhmngqh3qkl5"
12 | )
13 |
14 | func (k msgServer) UpdateMerkleRoot(goCtx context.Context, msg *types.MsgUpdateMerkleRoot) (*types.MsgUpdateMerkleRootResponse, error) {
15 | ctx := sdk.UnwrapSDKContext(goCtx)
16 |
17 | if AdminAddress != msg.Sender {
18 | return nil, types.ErrInvalidAdminAddress
19 | }
20 |
21 | k.Keeper.SetMerkleRoot(ctx, msg.RootValue)
22 |
23 | return &types.MsgUpdateMerkleRootResponse{}, nil
24 | }
25 |
--------------------------------------------------------------------------------
/x/claim/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/claim/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // GetParams returns the total set of claim parameters.
10 | func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
11 | k.paramstore.GetParamSet(ctx, ¶ms)
12 | return params
13 | }
14 |
15 | // SetParams sets claim parameters to the param space.
16 | func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
17 | k.paramstore.SetParamSet(ctx, ¶ms)
18 | }
19 |
--------------------------------------------------------------------------------
/x/claim/module.go:
--------------------------------------------------------------------------------
1 | package claim
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 |
8 | // this line is used by starport scaffolding # 1
9 |
10 | "github.com/gorilla/mux"
11 | "github.com/grpc-ecosystem/grpc-gateway/runtime"
12 | "github.com/spf13/cobra"
13 |
14 | abci "github.com/tendermint/tendermint/abci/types"
15 |
16 | "mun/x/claim/client/cli"
17 | "mun/x/claim/keeper"
18 | "mun/x/claim/types"
19 |
20 | "github.com/cosmos/cosmos-sdk/client"
21 | "github.com/cosmos/cosmos-sdk/codec"
22 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
23 | sdk "github.com/cosmos/cosmos-sdk/types"
24 | "github.com/cosmos/cosmos-sdk/types/module"
25 | )
26 |
27 | var (
28 | _ module.AppModule = AppModule{}
29 | _ module.AppModuleBasic = AppModuleBasic{}
30 | _ module.AppModuleSimulation = AppModule{}
31 | )
32 |
33 | // ----------------------------------------------------------------------------
34 | // AppModuleBasic
35 | // ----------------------------------------------------------------------------
36 |
37 | // AppModuleBasic implements the AppModuleBasic interface for the claim module.
38 | type AppModuleBasic struct {
39 | cdc codec.BinaryCodec
40 | }
41 |
42 | func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic {
43 | return AppModuleBasic{cdc: cdc}
44 | }
45 |
46 | // Name returns the claim module's name.
47 | func (AppModuleBasic) Name() string {
48 | return types.ModuleName
49 | }
50 |
51 | func (AppModuleBasic) RegisterCodec(cdc *codec.LegacyAmino) {
52 | types.RegisterLegacyAminoCodec(cdc)
53 | }
54 |
55 | func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
56 | types.RegisterLegacyAminoCodec(cdc)
57 | }
58 |
59 | // RegisterInterfaces registers the module's interface types
60 | func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
61 | types.RegisterInterfaces(reg)
62 | }
63 |
64 | // DefaultGenesis returns the claim module's default genesis state.
65 | func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
66 | return cdc.MustMarshalJSON(types.DefaultGenesis())
67 | }
68 |
69 | // ValidateGenesis performs genesis state validation for the claim module.
70 | func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
71 | var genState types.GenesisState
72 | if err := cdc.UnmarshalJSON(bz, &genState); err != nil {
73 | return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
74 | }
75 | return genState.Validate()
76 | }
77 |
78 | // RegisterRESTRoutes registers the claim module's REST service handlers.
79 | func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
80 | }
81 |
82 | // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module.
83 | func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
84 | err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
85 | if err != nil {
86 | panic(err)
87 | }
88 | }
89 |
90 | // GetTxCmd returns the claim module's root tx command.
91 | func (a AppModuleBasic) GetTxCmd() *cobra.Command {
92 | return cli.GetTxCmd()
93 | }
94 |
95 | // GetQueryCmd returns the claim module's root query command.
96 | func (AppModuleBasic) GetQueryCmd() *cobra.Command {
97 | return cli.GetQueryCmd(types.StoreKey)
98 | }
99 |
100 | // ----------------------------------------------------------------------------
101 | // AppModule
102 | // ----------------------------------------------------------------------------
103 |
104 | // AppModule implements the AppModule interface for the claim module.
105 | type AppModule struct {
106 | AppModuleBasic
107 |
108 | accountKeeper types.AccountKeeper
109 | bankKeeper types.BankKeeper
110 | keeper keeper.Keeper
111 | }
112 |
113 | func NewAppModule(cdc codec.Codec, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, keeper keeper.Keeper) AppModule {
114 | return AppModule{
115 | AppModuleBasic: NewAppModuleBasic(cdc),
116 | accountKeeper: accountKeeper,
117 | bankKeeper: bankKeeper,
118 | keeper: keeper,
119 | }
120 | }
121 |
122 | // Name returns the claim module's name.
123 | func (am AppModule) Name() string {
124 | return am.AppModuleBasic.Name()
125 | }
126 |
127 | // Route returns the claim module's message routing key.
128 | func (am AppModule) Route() sdk.Route {
129 | return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
130 | }
131 |
132 | // QuerierRoute returns the claim module's query routing key.
133 | func (AppModule) QuerierRoute() string { return types.QuerierRoute }
134 |
135 | // LegacyQuerierHandler returns the claim module's Querier.
136 | func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
137 | return nil
138 | }
139 |
140 | // RegisterServices registers a GRPC query service to respond to the
141 | // module-specific GRPC queries.
142 | func (am AppModule) RegisterServices(cfg module.Configurator) {
143 | types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
144 | types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
145 | err := cfg.RegisterMigration(types.ModuleName, 2, func(sdk.Context) error { return nil })
146 | if err != nil {
147 | panic(err)
148 | }
149 | }
150 |
151 | // RegisterInvariants registers the claim module's invariants.
152 | func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
153 |
154 | // InitGenesis performs the claim module's genesis initialization It returns
155 | // no validator updates.
156 | func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
157 | var genState types.GenesisState
158 | // Initialize global index to index in genesis state
159 | cdc.MustUnmarshalJSON(gs, &genState)
160 |
161 | return am.keeper.InitGenesis(ctx, genState)
162 | }
163 |
164 | // ExportGenesis returns the claim module's exported genesis state as raw JSON bytes.
165 | func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
166 | genState := am.keeper.ExportGenesis(ctx)
167 | return cdc.MustMarshalJSON(genState)
168 | }
169 |
170 | // ConsensusVersion implements ConsensusVersion.
171 | func (AppModule) ConsensusVersion() uint64 { return 2 }
172 |
173 | // BeginBlock executes all ABCI BeginBlock logic respective to the claim module.
174 | func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
175 |
176 | // EndBlock executes all ABCI EndBlock logic respective to the claim module. It
177 | // returns no validator updates.
178 | func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
179 | EndBlocker(ctx, am.keeper)
180 | return []abci.ValidatorUpdate{}
181 | }
182 |
--------------------------------------------------------------------------------
/x/claim/module_simulation.go:
--------------------------------------------------------------------------------
1 | package claim
2 |
3 | import (
4 | "math/rand"
5 | "mun/x/claim/simulation"
6 | "mun/x/claim/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/types/module"
10 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
11 | )
12 |
13 | // GenerateGenesisState creates a randomized GenState of the ibank module.
14 | func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
15 | simulation.RandomizedGenState(simState)
16 | }
17 |
18 | // ProposalContents returns nothing for governance proposals.
19 | func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
20 | return nil
21 | }
22 |
23 | // RandomizedParams creates randomized cronos param changes for the simulator.
24 | func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
25 | return simulation.ParamChanges(r)
26 | }
27 |
28 | // RegisterStoreDecoder registers a decoder for ibank module's types
29 | func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
30 | sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
31 | }
32 |
33 | // WeightedOperations returns the all the ibank module operations with their respective weights.
34 | func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
35 | return simulation.WeightedOperations(
36 | simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, &am.keeper,
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/x/claim/simulation/decoder.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "mun/x/claim/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | "github.com/cosmos/cosmos-sdk/types/kv"
10 | )
11 |
12 | // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
13 | // Value to the corresponding claim type.
14 | func NewDecodeStore(cdc codec.BinaryCodec) func(kvA, kvB kv.Pair) string {
15 | return func(kvA, kvB kv.Pair) string {
16 | switch {
17 | case bytes.Equal(kvA.Key, types.ClaimRecordsStorePrefix):
18 | var claimRecordA, claimRecordB types.ClaimRecord
19 | cdc.MustUnmarshal(kvA.Value, &claimRecordA)
20 | cdc.MustUnmarshal(kvB.Value, &claimRecordB)
21 | return fmt.Sprintf("%v\n%v", claimRecordA, claimRecordB)
22 | case bytes.Equal(kvA.Key, types.MerkleRootStorePrefix):
23 | return fmt.Sprintf("%v\n%v", string(kvA.Value), string(kvB.Value))
24 | default:
25 | panic(fmt.Sprintf("invalid claim key prefix %v", kvA.Key))
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/x/claim/simulation/decoder_test.go:
--------------------------------------------------------------------------------
1 | package simulation_test
2 |
3 | import (
4 | "fmt"
5 | "mun/app"
6 | "mun/x/claim/simulation"
7 | "mun/x/claim/types"
8 | "testing"
9 |
10 | "github.com/cosmos/cosmos-sdk/types/kv"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | func TestDecodeStore(t *testing.T) {
15 | cdc := app.MakeEncodingConfig().Marshaler
16 | dec := simulation.NewDecodeStore(cdc)
17 |
18 | merkleRoot := "558ad18828f6da6d471cdb1a3443f039a770e03617f163896980d914d643e4bc"
19 | claimRecord := types.ClaimRecord{
20 | Address: "mun1vk2zrdsg74vrztr5pe5qa0h6ljgmfy4sz2apec",
21 | ActionReady: make([]bool, 4),
22 | ActionCompleted: make([]bool, 4),
23 | }
24 |
25 | kvParis := kv.Pairs{
26 | Pairs: []kv.Pair{
27 | {Key: types.ClaimRecordsStorePrefix, Value: cdc.MustMarshal(&claimRecord)},
28 | {Key: types.MerkleRootStorePrefix, Value: []byte(merkleRoot)},
29 | },
30 | }
31 |
32 | tests := []struct {
33 | name string
34 | expectedLog string
35 | }{
36 | {"ClaimRecord", fmt.Sprintf("%v\n%v", claimRecord, claimRecord)},
37 | {"MerkleRoot", fmt.Sprintf("%v\n%v", merkleRoot, merkleRoot)},
38 | {"other", ""},
39 | }
40 |
41 | for i, tt := range tests {
42 | i, tt := i, tt
43 | t.Run(tt.name, func(t *testing.T) {
44 | switch i {
45 | case len(tests) - 1:
46 | require.Panics(t, func() { dec(kvParis.Pairs[i], kvParis.Pairs[i]) }, tt.name)
47 | default:
48 | require.Equal(t, tt.expectedLog, dec(kvParis.Pairs[i], kvParis.Pairs[i]), tt.name)
49 | }
50 | })
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/x/claim/simulation/genesis.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "math/rand"
7 | "mun/x/claim/types"
8 | "time"
9 |
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | "github.com/cosmos/cosmos-sdk/types/module"
12 | )
13 |
14 | const (
15 | Enabled = "enabled"
16 | ClaimDenom = "claim_denom"
17 | StartTime = "start_time"
18 | DurationUntilDecay = "duration_until_decay"
19 | DurationOfDecay = "duratin_of_decay"
20 | )
21 |
22 | func RandomEnabledFlag(r *rand.Rand) bool {
23 | return r.Int63n(101) <= 50 // 50% chance of airdrop enabled
24 | }
25 |
26 | func RandomStartTime(r *rand.Rand) time.Time {
27 | return time.Time{}.Add(time.Second * time.Duration(r.Int63n(10000)))
28 | }
29 |
30 | func RandomDurationUntilDecay(r *rand.Rand) time.Duration {
31 | // 1~100 seconds
32 | return time.Second * time.Duration(1+r.Int63n(100))
33 | }
34 |
35 | func RandomDurationOfDecay(r *rand.Rand) time.Duration {
36 | // 1~5000 seconds
37 | return time.Second * time.Duration(1+r.Int63n(5000))
38 | }
39 |
40 | func RandomGenesisModuleAccountBalance(r *rand.Rand) sdk.Coin {
41 | // 1000000 ~ 2000000 TMUN
42 | return sdk.NewCoin("utmun", sdk.NewInt(r.Int63n(1000000)+1000000).Mul(sdk.NewInt(1000000)))
43 | }
44 |
45 | func RandomGenesisMerkleRoot() string {
46 | return "04c287c1de1a9734959d8c04725fe56d7b70efefd4f13eb6885386cf55a8501b" // sha256("random genesis merkle root")
47 | }
48 |
49 | func RandomGenesisClaimRecords(simState *module.SimulationState) []types.ClaimRecord {
50 | records := make([]types.ClaimRecord, 0)
51 |
52 | for _, acc := range simState.Accounts {
53 | records = append(records, types.ClaimRecord{
54 | Address: acc.Address.String(),
55 | ActionReady: make([]bool, 0),
56 | ActionCompleted: make([]bool, 0),
57 | })
58 | }
59 | return records
60 | }
61 |
62 | // RandomizedGenState generates a random GenesisState for claim
63 | func RandomizedGenState(simState *module.SimulationState) {
64 | var enabled bool
65 | simState.AppParams.GetOrGenerate(
66 | simState.Cdc, Enabled, &enabled, simState.Rand,
67 | func(r *rand.Rand) { enabled = RandomEnabledFlag(r) },
68 | )
69 |
70 | claimDenom := "utmun"
71 |
72 | var startTime time.Time
73 | simState.AppParams.GetOrGenerate(
74 | simState.Cdc, StartTime, &startTime, simState.Rand,
75 | func(r *rand.Rand) { startTime = RandomStartTime(r) },
76 | )
77 |
78 | var durationUntilDecay time.Duration
79 | simState.AppParams.GetOrGenerate(
80 | simState.Cdc, DurationUntilDecay, &durationUntilDecay, simState.Rand,
81 | func(r *rand.Rand) { durationUntilDecay = RandomDurationUntilDecay(r) },
82 | )
83 |
84 | var durationOfDecay time.Duration
85 | simState.AppParams.GetOrGenerate(
86 | simState.Cdc, DurationOfDecay, &durationOfDecay, simState.Rand,
87 | func(r *rand.Rand) { durationOfDecay = RandomDurationOfDecay(r) },
88 | )
89 |
90 | params := types.NewParams(
91 | enabled,
92 | claimDenom,
93 | startTime,
94 | durationUntilDecay,
95 | durationOfDecay,
96 | )
97 |
98 | claimGenesis := types.NewGenesisState(
99 | RandomGenesisModuleAccountBalance(simState.Rand),
100 | params,
101 | RandomGenesisClaimRecords(simState),
102 | RandomGenesisMerkleRoot(),
103 | )
104 |
105 | bz, err := json.MarshalIndent(&claimGenesis.Params, "", " ")
106 | if err != nil {
107 | panic(err)
108 | }
109 | fmt.Printf("Selected randomly generated claim parameters:\n%s\n", bz)
110 | simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(claimGenesis)
111 | }
112 |
--------------------------------------------------------------------------------
/x/claim/simulation/genesis_test.go:
--------------------------------------------------------------------------------
1 | package simulation_test
2 |
3 | import (
4 | "encoding/json"
5 | "math/rand"
6 | "mun/x/claim/simulation"
7 | "mun/x/claim/types"
8 | "testing"
9 |
10 | "github.com/cosmos/cosmos-sdk/codec"
11 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
12 | "github.com/cosmos/cosmos-sdk/types/module"
13 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
14 | )
15 |
16 | func TestRandomizedGenState(t *testing.T) {
17 | interfaceRegistry := codectypes.NewInterfaceRegistry()
18 | cdc := codec.NewProtoCodec(interfaceRegistry)
19 | s := rand.NewSource(1)
20 | r := rand.New(s)
21 |
22 | simState := module.SimulationState{
23 | AppParams: make(simtypes.AppParams),
24 | Cdc: cdc,
25 | Rand: r,
26 | NumBonded: 3,
27 | Accounts: simtypes.RandomAccounts(r, 3),
28 | InitialStake: 1000,
29 | GenState: make(map[string]json.RawMessage),
30 | }
31 |
32 | simulation.RandomizedGenState(&simState)
33 |
34 | var claimGenesis types.GenesisState
35 | simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &claimGenesis)
36 | }
37 |
--------------------------------------------------------------------------------
/x/claim/simulation/operations.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "crypto/sha256"
5 | "fmt"
6 | "math/rand"
7 | "mun/x/claim/keeper"
8 | "mun/x/claim/types"
9 |
10 | "github.com/cosmos/cosmos-sdk/baseapp"
11 | "github.com/cosmos/cosmos-sdk/codec"
12 | simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
13 | sdk "github.com/cosmos/cosmos-sdk/types"
14 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
15 | "github.com/cosmos/cosmos-sdk/x/simulation"
16 | )
17 |
18 | const (
19 | DefaultWeightMsgClaimFor int = 100
20 | DefaultWeightMsgUpdateMerkleRoot int = 80
21 |
22 | OpWeightMsgClaimFor = "op_weight_msg_claim_for"
23 | OpWeightMsgUpdateMerkleRoot = "op_weight_msg_update_merkle_root"
24 | )
25 |
26 | func WeightedOperations(
27 | appParams simtypes.AppParams,
28 | cdc codec.JSONCodec,
29 | ak types.AccountKeeper,
30 | bk types.BankKeeper,
31 | k *keeper.Keeper,
32 | ) []simtypes.WeightedOperation {
33 | var (
34 | weightMsgClaimFor int
35 | weightMsgUpdateMerkleRoot int
36 | )
37 |
38 | appParams.GetOrGenerate(cdc, OpWeightMsgClaimFor, &weightMsgClaimFor, nil,
39 | func(_ *rand.Rand) {
40 | weightMsgClaimFor = DefaultWeightMsgClaimFor
41 | },
42 | )
43 |
44 | appParams.GetOrGenerate(cdc, OpWeightMsgUpdateMerkleRoot, &weightMsgUpdateMerkleRoot, nil,
45 | func(_ *rand.Rand) {
46 | weightMsgUpdateMerkleRoot = DefaultWeightMsgUpdateMerkleRoot
47 | },
48 | )
49 |
50 | return simulation.WeightedOperations{
51 | // simulation.NewWeightedOperation(
52 | // weightMsgClaimFor,
53 | // SimulateMsgClaimFor(ak, bk, k),
54 | // ),
55 | // simulation.NewWeightedOperation(
56 | // weightMsgUpdateMerkleRoot,
57 | // SimulateMsgUpdateMerkleRoot(ak),
58 | // ),
59 | }
60 | }
61 |
62 | func SimulateMsgClaimFor(
63 | ak types.AccountKeeper,
64 | bk types.BankKeeper,
65 | k *keeper.Keeper,
66 | ) simtypes.Operation {
67 | return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
68 | ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
69 | simAccount, _ := simtypes.RandomAcc(r, accs)
70 |
71 | sender := simAccount.Address.String()
72 | msg := types.NewMsgClaimFor(sender, types.Action(rand.Intn(3)), "")
73 |
74 | txCtx := simulation.OperationInput{
75 | R: r,
76 | App: app,
77 | TxGen: simappparams.MakeTestEncodingConfig().TxConfig,
78 | Cdc: nil,
79 | Msg: msg,
80 | MsgType: msg.Type(),
81 | Context: ctx,
82 | SimAccount: simAccount,
83 | AccountKeeper: ak,
84 | Bankkeeper: bk,
85 | ModuleName: types.ModuleName,
86 | }
87 |
88 | return simulation.GenAndDeliverTxWithRandFees(txCtx)
89 | }
90 | }
91 |
92 | func SimulateMsgUpdateMerkleRoot(ak types.AccountKeeper) simtypes.Operation {
93 | return func(
94 | r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
95 | ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
96 | simAccount, _ := simtypes.RandomAcc(r, accs)
97 |
98 | // Generate random merkle root hash
99 | randomValue := fmt.Sprintf("%d", rand.Int())
100 | merkleRoot := fmt.Sprintf("%x", sha256.Sum256([]byte(randomValue)))
101 |
102 | msg := types.NewMsgUpdateMerkleRoot(simAccount.Address.String(), merkleRoot)
103 |
104 | txCtx := simulation.OperationInput{
105 | R: r,
106 | App: app,
107 | TxGen: simappparams.MakeTestEncodingConfig().TxConfig,
108 | Cdc: nil,
109 | Msg: msg,
110 | MsgType: msg.Type(),
111 | Context: ctx,
112 | SimAccount: simAccount,
113 | AccountKeeper: ak,
114 | ModuleName: types.ModuleName,
115 | }
116 |
117 | return simulation.GenAndDeliverTxWithRandFees(txCtx)
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/x/claim/simulation/params.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "mun/x/claim/types"
7 |
8 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
9 | "github.com/cosmos/cosmos-sdk/x/simulation"
10 | )
11 |
12 | // ParamChanges defines the parameters that can be modified by param change proposals
13 | // on the simulation
14 | func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
15 | return []simtypes.ParamChange{
16 | simulation.NewSimParamChange(types.ModuleName, string(types.KeyEnabled),
17 | func(r *rand.Rand) string {
18 | return fmt.Sprintf("%v", RandomEnabledFlag(r))
19 | },
20 | ),
21 | simulation.NewSimParamChange(types.ModuleName, string(types.KeyStartTime),
22 | func(r *rand.Rand) string {
23 | return fmt.Sprintf("\"%s\"", RandomStartTime(r).UTC().Format("2006-01-02T15:04:05Z07:00"))
24 | },
25 | ),
26 | simulation.NewSimParamChange(types.ModuleName, string(types.KeyDurationUntilDecay),
27 | func(r *rand.Rand) string {
28 | return fmt.Sprintf("\"%d\"", RandomDurationUntilDecay(r))
29 | },
30 | ),
31 | simulation.NewSimParamChange(types.ModuleName, string(types.KeyDurationOfDecay),
32 | func(r *rand.Rand) string {
33 | return fmt.Sprintf("\"%d\"", RandomDurationOfDecay(r))
34 | },
35 | ),
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/x/claim/simulation/params_test.go:
--------------------------------------------------------------------------------
1 | package simulation_test
2 |
3 | import (
4 | "math/rand"
5 | "mun/x/claim/simulation"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestParamChanges(t *testing.T) {
12 | s := rand.NewSource(1)
13 | r := rand.New(s)
14 |
15 | expected := []struct {
16 | composedKey string
17 | key string
18 | simValue string
19 | subspace string
20 | }{
21 | {"claim/Enabled", "Enabled", "false", "claim"},
22 | {"claim/StartTime", "StartTime", "\"0001-01-01T00:59:11Z\"", "claim"},
23 | {"claim/DurationUntilDecay", "DurationUntilDecay", "\"22000000000\"", "claim"},
24 | {"claim/DurationOfDecay", "DurationOfDecay", "\"52000000000\"", "claim"},
25 | }
26 |
27 | paramChanges := simulation.ParamChanges(r)
28 |
29 | require.Len(t, paramChanges, 4)
30 |
31 | for i, p := range paramChanges {
32 | require.Equal(t, expected[i].composedKey, p.ComposedKey())
33 | require.Equal(t, expected[i].key, p.Key())
34 | require.Equal(t, expected[i].simValue, p.SimValue()(r))
35 | require.Equal(t, expected[i].subspace, p.Subspace())
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/x/claim/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
6 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/cosmos/cosmos-sdk/types/msgservice"
9 | )
10 |
11 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
12 | // cdc.RegisterConcrete(&MsgInitialClaim{}, "claim/InitialClaim", nil)
13 | cdc.RegisterConcrete(&MsgClaimFor{}, "claim/ClaimFor", nil)
14 | // this line is used by starport scaffolding # 2
15 | }
16 |
17 | func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
18 | registry.RegisterImplementations((*sdk.Msg)(nil),
19 | // &MsgInitialClaim{},
20 | &MsgClaimFor{},
21 | )
22 |
23 | // this line is used by starport scaffolding # 3
24 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
25 | }
26 |
27 | var (
28 | amino = codec.NewLegacyAmino()
29 | // ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry())
30 | ModuleCdc = codec.NewAminoCodec(amino)
31 | )
32 |
33 | func init() {
34 | RegisterLegacyAminoCodec(amino)
35 | cryptocodec.RegisterCrypto(amino)
36 | amino.Seal()
37 | }
38 |
--------------------------------------------------------------------------------
/x/claim/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // DONTCOVER
4 |
5 | import (
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 | )
8 |
9 | // x/claim module sentinel errors
10 | var (
11 | ErrAirdropNotEnabled = sdkerrors.Register(ModuleName, 2, "airdrop not enabled")
12 | ErrIncorrectModuleAccountBalance = sdkerrors.Register(ModuleName, 3, "claim module account balance != sum of all claim record InitialClaimableAmounts")
13 | ErrUnauthorizedClaimer = sdkerrors.Register(ModuleName, 4, "address is not allowed to claim")
14 | ErrInvalidAdminAddress = sdkerrors.Register(ModuleName, 5, "admin address is not valid")
15 | ErrInvalidBech32Address = sdkerrors.Register(ModuleName, 6, "invalid bech32 address")
16 | )
17 |
--------------------------------------------------------------------------------
/x/claim/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | EventTypeClaim = "claim"
5 | AttributeValueCategory = ModuleName
6 | )
7 |
--------------------------------------------------------------------------------
/x/claim/types/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
6 | )
7 |
8 | type AccountKeeper interface {
9 | GetModuleAddress(name string) sdk.AccAddress
10 | SetModuleAccount(ctx sdk.Context, macc authtypes.ModuleAccountI)
11 | GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI // only used for simulation
12 | }
13 |
14 | type BankKeeper interface {
15 | SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
16 | SendCoinsFromModuleToModule(ctx sdk.Context, senderPool, recipientPool string, amt sdk.Coins) error
17 | GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
18 | MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
19 | SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
20 | }
21 |
22 | type StakingKeeper interface {
23 | BondDenom(sdk.Context) string
24 | }
25 |
26 | type DistrKeeper interface {
27 | FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error
28 | }
29 |
--------------------------------------------------------------------------------
/x/claim/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "encoding/json"
5 | "time"
6 |
7 | "github.com/cosmos/cosmos-sdk/codec"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | // this line is used by starport scaffolding # genesis/types/import
12 |
13 | // DefaultIndex is the default capability global index
14 | const DefaultIndex uint64 = 1
15 |
16 | // DefaultGenesis returns the default Capability genesis state
17 | func DefaultGenesis() *GenesisState {
18 | return &GenesisState{
19 | // this line is used by starport scaffolding # genesis/types/default
20 | ModuleAccountBalance: sdk.NewCoin(DefaultClaimDenom, sdk.ZeroInt()),
21 | Params: DefaultParams(),
22 | ClaimRecords: make([]ClaimRecord, 0),
23 | MerkleRoot: "",
24 | }
25 | }
26 |
27 | func DefaultParams() Params {
28 | return Params{
29 | AirdropEnabled: true,
30 | AirdropStartTime: time.Time{},
31 | DurationUntilDecay: DefaultDurationUntilDecay,
32 | DurationOfDecay: DefaultDurationOfDecay,
33 | ClaimDenom: DefaultClaimDenom,
34 | }
35 | }
36 |
37 | func NewGenesisState(moduleAccountBalance sdk.Coin, params Params, claimRecords []ClaimRecord, merkleRoot string) *GenesisState {
38 | return &GenesisState{
39 | ModuleAccountBalance: moduleAccountBalance,
40 | Params: params,
41 | ClaimRecords: claimRecords,
42 | MerkleRoot: merkleRoot,
43 | }
44 | }
45 |
46 | // Validate performs basic genesis state validation returning an error upon any
47 | // failure.
48 | func (gs GenesisState) Validate() error {
49 | // this line is used by starport scaffolding # genesis/types/validate
50 | totalClaimable := sdk.Coins{}
51 | for _, claimRecord := range gs.ClaimRecords {
52 | totalClaimable = totalClaimable.Add(claimRecord.InitialClaimableAmount...)
53 | }
54 |
55 | if !totalClaimable.IsEqual(sdk.NewCoins(gs.ModuleAccountBalance)) {
56 | return ErrIncorrectModuleAccountBalance
57 | }
58 |
59 | return nil
60 | }
61 |
62 | // GetGenesisStateFromAppState return GenesisState
63 | func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.RawMessage) *GenesisState {
64 | var genesisState GenesisState
65 |
66 | if appState[ModuleName] != nil {
67 | cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState)
68 | }
69 |
70 | return &genesisState
71 | }
72 |
--------------------------------------------------------------------------------
/x/claim/types/genesis_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "mun/x/claim/types"
8 |
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | "github.com/stretchr/testify/require"
11 | )
12 |
13 | func TestGenesisState_Validate(t *testing.T) {
14 | for _, tc := range []struct {
15 | desc string
16 | genState *types.GenesisState
17 | valid bool
18 | }{
19 | {
20 | desc: "default is valid",
21 | genState: types.DefaultGenesis(),
22 | valid: true,
23 | },
24 | {
25 | desc: "valid genesis state",
26 | genState: &types.GenesisState{
27 | // this line is used by starport scaffolding # types/genesis/validField
28 | ModuleAccountBalance: sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()),
29 | Params: types.Params{
30 | AirdropEnabled: true,
31 | AirdropStartTime: time.Time{},
32 | DurationUntilDecay: time.Hour * 24 * 60,
33 | DurationOfDecay: time.Hour * 24 * 30 * 4,
34 | ClaimDenom: sdk.DefaultBondDenom,
35 | },
36 | ClaimRecords: []types.ClaimRecord{},
37 | },
38 | valid: true,
39 | },
40 | // this line is used by starport scaffolding # types/genesis/testcase
41 | } {
42 | t.Run(tc.desc, func(t *testing.T) {
43 | err := tc.genState.Validate()
44 | if tc.valid {
45 | require.NoError(t, err)
46 | } else {
47 | require.Error(t, err)
48 | }
49 | })
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/x/claim/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName defines the module name
5 | ModuleName = "claim"
6 |
7 | // StoreKey defines the primary module store key
8 | StoreKey = ModuleName
9 |
10 | // RouterKey is the message route for slashing
11 | RouterKey = ModuleName
12 |
13 | // QuerierRoute defines the module's query routing key
14 | QuerierRoute = ModuleName
15 |
16 | // MemStoreKey defines the in-memory store key
17 | MemStoreKey = "mem_claim"
18 |
19 | // ParamsKey defines the store key for claim module parameters
20 | ParamsKey = "params"
21 |
22 | // ActionKey defines the store key to store user accomplished actions
23 | ActionKey = "action"
24 |
25 | InitialClaimAmount = "1000000000utmun"
26 | )
27 |
28 | // KVStore keys
29 | var (
30 | // ClaimRecordsStorePrefix defines the store prefix for the claim records
31 | ClaimRecordsStorePrefix = []byte{0x01}
32 |
33 | // MerkleRootStorePrefix defines the store prefix for the merkle root
34 | MerkleRootStorePrefix = []byte{0x02}
35 | )
36 |
--------------------------------------------------------------------------------
/x/claim/types/message_claim_for.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | )
7 |
8 | var _ sdk.Msg = &MsgClaimFor{}
9 |
10 | // msg types
11 | const (
12 | TypeMsgClaimFor = "claim_for"
13 | )
14 |
15 | func NewMsgClaimFor(sender string, action Action, proof string) *MsgClaimFor {
16 | return &MsgClaimFor{
17 | Sender: sender,
18 | Action: action,
19 | Proof: proof,
20 | }
21 | }
22 |
23 | func (msg *MsgClaimFor) Route() string {
24 | return RouterKey
25 | }
26 |
27 | func (msg *MsgClaimFor) Type() string {
28 | return TypeMsgClaimFor
29 | }
30 |
31 | func (msg *MsgClaimFor) GetSigners() []sdk.AccAddress {
32 | sender, err := sdk.AccAddressFromBech32(msg.Sender)
33 | if err != nil {
34 | panic(err)
35 | }
36 | return []sdk.AccAddress{sender}
37 | }
38 |
39 | func (msg *MsgClaimFor) GetSignBytes() []byte {
40 | bz := ModuleCdc.MustMarshalJSON(msg)
41 | return sdk.MustSortJSON(bz)
42 | }
43 |
44 | func (msg *MsgClaimFor) ValidateBasic() error {
45 | _, err := sdk.AccAddressFromBech32(msg.Sender)
46 | if err != nil {
47 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid sender address (%s)", err)
48 | }
49 | return nil
50 | }
51 |
--------------------------------------------------------------------------------
/x/claim/types/message_update_merkle_root.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | )
7 |
8 | var _ sdk.Msg = &MsgUpdateMerkleRoot{}
9 |
10 | // msg types
11 | const (
12 | TypeMsgUpdateMerkleRoot = "update_merkle_root"
13 | )
14 |
15 | func NewMsgUpdateMerkleRoot(sender string, value string) *MsgUpdateMerkleRoot {
16 | return &MsgUpdateMerkleRoot{
17 | Sender: sender,
18 | RootValue: value,
19 | }
20 | }
21 |
22 | func (msg *MsgUpdateMerkleRoot) Route() string {
23 | return RouterKey
24 | }
25 |
26 | func (msg *MsgUpdateMerkleRoot) Type() string {
27 | return TypeMsgUpdateMerkleRoot
28 | }
29 |
30 | func (msg *MsgUpdateMerkleRoot) GetSigners() []sdk.AccAddress {
31 | sender, err := sdk.AccAddressFromBech32(msg.Sender)
32 | if err != nil {
33 | panic(err)
34 | }
35 | return []sdk.AccAddress{sender}
36 | }
37 |
38 | func (msg *MsgUpdateMerkleRoot) ValidateBasic() error {
39 | _, err := sdk.AccAddressFromBech32(msg.Sender)
40 | if err != nil {
41 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid sender address (%s)", err)
42 | }
43 | return nil
44 | }
45 |
--------------------------------------------------------------------------------
/x/claim/types/params.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | "time"
7 |
8 | paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
9 | yaml "gopkg.in/yaml.v2"
10 | )
11 |
12 | var (
13 | DefaultClaimDenom = "utmun"
14 | DefaultDurationUntilDecay = time.Hour
15 | DefaultDurationOfDecay = time.Hour * 5
16 | )
17 |
18 | // Parameter store keys
19 | var (
20 | KeyEnabled = []byte("Enabled")
21 | KeyStartTime = []byte("StartTime")
22 | KeyClaimDenom = []byte("ClaimDenom")
23 | KeyDurationUntilDecay = []byte("DurationUntilDecay")
24 | KeyDurationOfDecay = []byte("DurationOfDecay")
25 | )
26 |
27 | func NewParams(enabled bool, claimDenom string, startTime time.Time, durationUntilDecay, durationOfDecay time.Duration) Params {
28 | return Params{
29 | AirdropEnabled: enabled,
30 | ClaimDenom: claimDenom,
31 | AirdropStartTime: startTime,
32 | DurationUntilDecay: durationUntilDecay,
33 | DurationOfDecay: durationOfDecay,
34 | }
35 | }
36 |
37 | // String implements the stringer interface for Params
38 | func (p Params) String() string {
39 | out, err := yaml.Marshal(p)
40 | if err != nil {
41 | return ""
42 | }
43 | return string(out)
44 | }
45 |
46 | // ParamSetPairs - Implements params.ParamSet
47 | func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
48 | return paramtypes.ParamSetPairs{
49 | paramtypes.NewParamSetPair(KeyEnabled, &p.AirdropEnabled, validateEnabled),
50 | paramtypes.NewParamSetPair(KeyClaimDenom, &p.ClaimDenom, validateDenom),
51 | paramtypes.NewParamSetPair(KeyStartTime, &p.AirdropStartTime, validateTime),
52 | paramtypes.NewParamSetPair(KeyDurationUntilDecay, &p.DurationUntilDecay, validateDuration),
53 | paramtypes.NewParamSetPair(KeyDurationOfDecay, &p.DurationOfDecay, validateDuration),
54 | }
55 | }
56 |
57 | // Validate validates all params
58 | func (p Params) Validate() error {
59 | if err := validateEnabled(p.AirdropEnabled); err != nil {
60 | return err
61 | }
62 | err := validateDenom(p.ClaimDenom)
63 | return err
64 | }
65 |
66 | func (p Params) IsAirdropEnabled(t time.Time) bool {
67 | if !p.AirdropEnabled {
68 | return false
69 | }
70 | if p.AirdropStartTime.IsZero() {
71 | return false
72 | }
73 | if t.Before(p.AirdropStartTime) {
74 | return false
75 | }
76 | return true
77 | }
78 |
79 | // ParamKeyTable for staking module
80 | func ParamKeyTable() paramtypes.KeyTable {
81 | return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
82 | }
83 |
84 | func validateEnabled(i interface{}) error {
85 | _, ok := i.(bool)
86 | if !ok {
87 | return fmt.Errorf("invalid parameter type: %T", i)
88 | }
89 | return nil
90 | }
91 |
92 | func validateDenom(i interface{}) error {
93 | v, ok := i.(string)
94 | if !ok {
95 | return fmt.Errorf("invalid parameter type: %T", i)
96 | }
97 |
98 | if strings.TrimSpace(v) == "" {
99 | return fmt.Errorf("invalid denom: %s", v)
100 | }
101 |
102 | return nil
103 | }
104 |
105 | func validateTime(i interface{}) error {
106 | _, ok := i.(time.Time)
107 | if !ok {
108 | return fmt.Errorf("invalid parameter type: %T", i)
109 | }
110 | return nil
111 | }
112 |
113 | func validateDuration(i interface{}) error {
114 | d, ok := i.(time.Duration)
115 | if !ok {
116 | return fmt.Errorf("invalid parameter type: %T", i)
117 | }
118 | if d < 1 {
119 | return fmt.Errorf("duration must be greater than or equal to 1: %d", d)
120 | }
121 | return nil
122 | }
123 |
--------------------------------------------------------------------------------
/x/claim/types/tx_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "testing"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestMsgJsonSignBytes(t *testing.T) {
12 | goodAddress := sdk.AccAddress(make([]byte, 20)).String()
13 | specs := map[string]struct {
14 | src legacytx.LegacyMsg
15 | exp string
16 | }{
17 | "MsgClaimFor": {
18 | src: &MsgClaimFor{Sender: goodAddress},
19 | exp: `
20 | {
21 | "type":"claim/ClaimFor",
22 | "value": {"sender": "cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnrql8a"}
23 | }`,
24 | },
25 | }
26 | for name, spec := range specs {
27 | t.Run(name, func(t *testing.T) {
28 | bz := spec.src.GetSignBytes()
29 | assert.JSONEq(t, spec.exp, string(bz), "raw: %s", string(bz))
30 | })
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/x/claim/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
--------------------------------------------------------------------------------
/x/ibank/README.md:
--------------------------------------------------------------------------------
1 | # IBANK
2 |
3 | The ``IBANK`` module is a custom module that allows secure transfer of tokens between brokers. The module is designed for scenarios where the sender wishes to send tokens with a password that the receiver must know to receive the coins. `ibank` allows brokers to easily send funds from one to another, with added security and peace of mind.
4 |
5 | ## Features
6 |
7 | - Secure transfer of tokens between brokers
8 | - Encrypted password for the receiver to retrieve funds
9 | - Tokens are locked in the module throughout the transfer process
10 | - Funds will automatically return to the sender if the duration expires or max retry limit exceeds.
--------------------------------------------------------------------------------
/x/ibank/abci.go:
--------------------------------------------------------------------------------
1 | package ibank
2 |
3 | import (
4 | "fmt"
5 | "mun/x/ibank/keeper"
6 | "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
12 | txCount := k.GetTransactionCount(ctx)
13 |
14 | var id = k.GetTransactionChaser(ctx)
15 | for ; id <= txCount; id++ {
16 | tx, found := k.GetTransaction(ctx, id)
17 | if !found {
18 | break
19 | }
20 |
21 | if !k.IsExpired(ctx, tx) {
22 | break
23 | }
24 |
25 | if tx.Status == types.TxPending {
26 | if err := k.Refund(ctx, tx, true); err != nil {
27 | ctx.Logger().Error(fmt.Sprintf("ibank: refund error on end blocker, id: %d", id))
28 | }
29 | }
30 | }
31 |
32 | k.SetTransactionChaser(ctx, id)
33 | }
34 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/query.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | // "strings"
6 |
7 | "github.com/spf13/cobra"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | // "github.com/cosmos/cosmos-sdk/client/flags"
11 | // sdk "github.com/cosmos/cosmos-sdk/types"
12 |
13 | "mun/x/ibank/types"
14 | )
15 |
16 | // GetQueryCmd returns the cli query commands for this module
17 | func GetQueryCmd(queryRoute string) *cobra.Command {
18 | // Group ibank queries under a subcommand
19 | cmd := &cobra.Command{
20 | Use: types.ModuleName,
21 | Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
22 | DisableFlagParsing: true,
23 | SuggestionsMinimumDistance: 2,
24 | RunE: client.ValidateCmd,
25 | }
26 |
27 | cmd.AddCommand(CmdQueryParams())
28 | cmd.AddCommand(CmdListTransaction())
29 | cmd.AddCommand(CmdShowTransaction())
30 | cmd.AddCommand(CmdShowIncoming())
31 | cmd.AddCommand(CmdShowOutgoing())
32 |
33 | // this line is used by starport scaffolding # 1
34 |
35 | return cmd
36 | }
37 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/query_params.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/spf13/cobra"
11 | )
12 |
13 | func CmdQueryParams() *cobra.Command {
14 | cmd := &cobra.Command{
15 | Use: "params",
16 | Short: "shows the parameters of the module",
17 | Args: cobra.NoArgs,
18 | RunE: func(cmd *cobra.Command, args []string) error {
19 | clientCtx := client.GetClientContextFromCmd(cmd)
20 |
21 | queryClient := types.NewQueryClient(clientCtx)
22 |
23 | res, err := queryClient.Params(context.Background(), &types.QueryParamsRequest{})
24 | if err != nil {
25 | return err
26 | }
27 |
28 | return clientCtx.PrintProto(res)
29 | },
30 | }
31 |
32 | flags.AddQueryFlagsToCmd(cmd)
33 |
34 | return cmd
35 | }
36 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/query_show_incoming.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/spf13/cast"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var _ = strconv.Itoa(0)
15 |
16 | func CmdShowIncoming() *cobra.Command {
17 | cmd := &cobra.Command{
18 | Use: "incoming [receiver] [pending]",
19 | Short: "Query show-incoming",
20 | Args: cobra.ExactArgs(2),
21 | RunE: func(cmd *cobra.Command, args []string) (err error) {
22 | reqReceiver := args[0]
23 | reqPending, err := cast.ToBoolE(args[1])
24 | if err != nil {
25 | return err
26 | }
27 |
28 | clientCtx, err := client.GetClientQueryContext(cmd)
29 | if err != nil {
30 | return err
31 | }
32 |
33 | queryClient := types.NewQueryClient(clientCtx)
34 |
35 | params := &types.QueryIncomingRequest{
36 |
37 | Receiver: reqReceiver,
38 | Pending: reqPending,
39 | }
40 |
41 | res, err := queryClient.Incoming(cmd.Context(), params)
42 | if err != nil {
43 | return err
44 | }
45 |
46 | return clientCtx.PrintProto(res)
47 | },
48 | }
49 |
50 | flags.AddQueryFlagsToCmd(cmd)
51 |
52 | return cmd
53 | }
54 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/query_show_outgoing.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/spf13/cast"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var _ = strconv.Itoa(0)
15 |
16 | func CmdShowOutgoing() *cobra.Command {
17 | cmd := &cobra.Command{
18 | Use: "outgoing [sender] [pending]",
19 | Short: "Query show-outgoing",
20 | Args: cobra.ExactArgs(2),
21 | RunE: func(cmd *cobra.Command, args []string) (err error) {
22 | reqSender := args[0]
23 | reqPending, err := cast.ToBoolE(args[1])
24 | if err != nil {
25 | return err
26 | }
27 |
28 | clientCtx, err := client.GetClientQueryContext(cmd)
29 | if err != nil {
30 | return err
31 | }
32 |
33 | queryClient := types.NewQueryClient(clientCtx)
34 |
35 | params := &types.QueryOutgoingRequest{
36 |
37 | Sender: reqSender,
38 | Pending: reqPending,
39 | }
40 |
41 | res, err := queryClient.Outgoing(cmd.Context(), params)
42 | if err != nil {
43 | return err
44 | }
45 |
46 | return clientCtx.PrintProto(res)
47 | },
48 | }
49 |
50 | flags.AddQueryFlagsToCmd(cmd)
51 |
52 | return cmd
53 | }
54 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/query_transaction.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "context"
5 | "strconv"
6 |
7 | "mun/x/ibank/types"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | "github.com/cosmos/cosmos-sdk/client/flags"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | func CmdListTransaction() *cobra.Command {
15 | cmd := &cobra.Command{
16 | Use: "list-transaction [address]",
17 | Short: "list all transaction",
18 | Args: cobra.ExactArgs(1),
19 | RunE: func(cmd *cobra.Command, args []string) error {
20 | reqAddress := args[0]
21 |
22 | clientCtx, err := client.GetClientQueryContext(cmd)
23 | if err != nil {
24 | return err
25 | }
26 |
27 | queryClient := types.NewQueryClient(clientCtx)
28 |
29 | params := &types.QueryAllTransactionRequest{
30 | Address: reqAddress,
31 | }
32 |
33 | res, err := queryClient.TransactionAll(context.Background(), params)
34 | if err != nil {
35 | return err
36 | }
37 |
38 | return clientCtx.PrintProto(res)
39 | },
40 | }
41 |
42 | flags.AddPaginationFlagsToCmd(cmd, cmd.Use)
43 | flags.AddQueryFlagsToCmd(cmd)
44 |
45 | return cmd
46 | }
47 |
48 | func CmdShowTransaction() *cobra.Command {
49 | cmd := &cobra.Command{
50 | Use: "show-transaction [id]",
51 | Short: "shows a transaction",
52 | Args: cobra.ExactArgs(1),
53 | RunE: func(cmd *cobra.Command, args []string) error {
54 | clientCtx := client.GetClientContextFromCmd(cmd)
55 |
56 | queryClient := types.NewQueryClient(clientCtx)
57 |
58 | id, err := strconv.ParseUint(args[0], 10, 64)
59 | if err != nil {
60 | return err
61 | }
62 |
63 | params := &types.QueryGetTransactionRequest{
64 | Id: id,
65 | }
66 |
67 | res, err := queryClient.Transaction(context.Background(), params)
68 | if err != nil {
69 | return err
70 | }
71 |
72 | return clientCtx.PrintProto(res)
73 | },
74 | }
75 |
76 | flags.AddQueryFlagsToCmd(cmd)
77 |
78 | return cmd
79 | }
80 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | "github.com/spf13/cobra"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | // "github.com/cosmos/cosmos-sdk/client/flags"
11 | "mun/x/ibank/types"
12 | )
13 |
14 | var (
15 | DefaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Minute).Nanoseconds())
16 | )
17 |
18 | // const (
19 | // flagPacketTimeoutTimestamp = "packet-timeout-timestamp"
20 | // listSeparator = ","
21 | // )
22 |
23 | // GetTxCmd returns the transaction commands for this module
24 | func GetTxCmd() *cobra.Command {
25 | cmd := &cobra.Command{
26 | Use: types.ModuleName,
27 | Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
28 | DisableFlagParsing: true,
29 | SuggestionsMinimumDistance: 2,
30 | RunE: client.ValidateCmd,
31 | }
32 |
33 | cmd.AddCommand(CmdSend())
34 | cmd.AddCommand(CmdReceive())
35 | // this line is used by starport scaffolding # 1
36 |
37 | return cmd
38 | }
39 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/tx_receive.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/cosmos/cosmos-sdk/client/tx"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | var _ = strconv.Itoa(0)
15 |
16 | func CmdReceive() *cobra.Command {
17 | cmd := &cobra.Command{
18 | Use: "receive [transaction-id] [password]",
19 | Short: "Broadcast message receive",
20 | Args: cobra.ExactArgs(2),
21 | RunE: func(cmd *cobra.Command, args []string) (err error) {
22 | argTransactionID := args[0]
23 | argPassword := args[1]
24 |
25 | clientCtx, err := client.GetClientTxContext(cmd)
26 | if err != nil {
27 | return err
28 | }
29 |
30 | txnID, err := strconv.ParseInt(argTransactionID, 10, 64)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | msg := types.NewMsgReceive(
36 | clientCtx.GetFromAddress().String(),
37 | txnID,
38 | argPassword,
39 | )
40 | if err := msg.ValidateBasic(); err != nil {
41 | return err
42 | }
43 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
44 | },
45 | }
46 |
47 | flags.AddTxFlagsToCmd(cmd)
48 |
49 | return cmd
50 | }
51 |
--------------------------------------------------------------------------------
/x/ibank/client/cli/tx_send.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "strconv"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/cosmos/cosmos-sdk/client/tx"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | "github.com/spf13/cobra"
13 | )
14 |
15 | var _ = strconv.Itoa(0)
16 |
17 | func CmdSend() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: "send [to-address] [amount] [password-hash]",
20 | Short: "Broadcast message send",
21 | Args: cobra.ExactArgs(3),
22 | RunE: func(cmd *cobra.Command, args []string) (err error) {
23 | argToAddress := args[0]
24 | argPassword := args[2]
25 | argAmount, err := sdk.ParseCoinNormalized(args[1])
26 | if err != nil {
27 | return err
28 | }
29 |
30 | clientCtx, err := client.GetClientTxContext(cmd)
31 | if err != nil {
32 | return err
33 | }
34 |
35 | msg := types.NewMsgSend(
36 | clientCtx.GetFromAddress().String(),
37 | argToAddress,
38 | argAmount,
39 | argPassword,
40 | )
41 | if err := msg.ValidateBasic(); err != nil {
42 | return err
43 | }
44 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
45 | },
46 | }
47 |
48 | flags.AddTxFlagsToCmd(cmd)
49 |
50 | return cmd
51 | }
52 |
--------------------------------------------------------------------------------
/x/ibank/genesis.go:
--------------------------------------------------------------------------------
1 | package ibank
2 |
3 | import (
4 | "mun/x/ibank/keeper"
5 | "mun/x/ibank/types"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | )
9 |
10 | // InitGenesis initializes the module's state from a provided genesis state.
11 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
12 | // Set all the transaction
13 | for _, elem := range genState.TransactionList {
14 | k.SetTransaction(ctx, elem)
15 | }
16 |
17 | k.CreateModuleAccount(ctx)
18 | k.SetTransactionCount(ctx, genState.TransactionCount)
19 | k.SetTransactionChaser(ctx, genState.TransactionChaser)
20 |
21 | // this line is used by starport scaffolding # genesis/module/init
22 | k.SetParams(ctx, genState.Params)
23 | }
24 |
25 | // ExportGenesis returns the module's exported genesis
26 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
27 | genesis := types.DefaultGenesis()
28 | genesis.Params = k.GetParams(ctx)
29 |
30 | genesis.TransactionList = k.GetAllTransaction(ctx)
31 | genesis.TransactionCount = k.GetTransactionCount(ctx)
32 | genesis.TransactionChaser = k.GetTransactionChaser(ctx)
33 | // this line is used by starport scaffolding # genesis/module/export
34 |
35 | return genesis
36 | }
37 |
--------------------------------------------------------------------------------
/x/ibank/keeper/grpc_query.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/ibank/types"
5 | "time"
6 | )
7 |
8 | var _ types.QueryServer = Keeper{}
9 |
10 | func CalculateTimeLeftInSeconds(start, end time.Time, expirationDuration time.Duration) uint32 {
11 | if start.Add(expirationDuration).After(end) {
12 | return uint32(expirationDuration.Seconds() - end.Sub(start).Seconds())
13 | }
14 | return 0
15 | }
16 |
--------------------------------------------------------------------------------
/x/ibank/keeper/grpc_query_params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "google.golang.org/grpc/codes"
10 | "google.golang.org/grpc/status"
11 | )
12 |
13 | func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
14 | if req == nil {
15 | return nil, status.Error(codes.InvalidArgument, "invalid request")
16 | }
17 | ctx := sdk.UnwrapSDKContext(c)
18 |
19 | return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil
20 | }
21 |
--------------------------------------------------------------------------------
/x/ibank/keeper/grpc_query_show_incoming.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/store/prefix"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | "google.golang.org/grpc/codes"
11 | "google.golang.org/grpc/status"
12 | )
13 |
14 | func (k Keeper) Incoming(goCtx context.Context, req *types.QueryIncomingRequest) (*types.QueryIncomingResponse, error) {
15 | if req == nil {
16 | return nil, status.Error(codes.InvalidArgument, "invalid request")
17 | }
18 |
19 | var transactions []types.TransactionWrapper
20 | ctx := sdk.UnwrapSDKContext(goCtx)
21 |
22 | expirationDuration := k.GetParams(ctx).DurationOfExpiration
23 |
24 | store := ctx.KVStore(k.storeKey)
25 | transactionStore := prefix.NewStore(store, types.KeyPrefix(types.TransactionKey))
26 |
27 | pageRes, err := paginate(transactionStore, req.Pagination, func(key []byte, value []byte, appendable bool) (error, bool) {
28 | var transaction types.Transaction
29 | if err := k.cdc.Unmarshal(value, &transaction); err != nil {
30 | return err, false
31 | }
32 |
33 | // check receiver
34 | if req.Receiver != transaction.Receiver {
35 | return nil, false
36 | }
37 |
38 | // only shows pending transactions
39 | if req.Pending && transaction.Status != types.TxPending {
40 | return nil, false
41 | }
42 |
43 | if appendable {
44 | wrapper := types.TransactionWrapper{
45 | Transaction: transaction,
46 | TimeLeft: CalculateTimeLeftInSeconds(transaction.SentAt, ctx.BlockTime(), expirationDuration),
47 | }
48 | transactions = append(transactions, wrapper)
49 | }
50 | return nil, true
51 | })
52 |
53 | if err != nil {
54 | return nil, status.Error(codes.Internal, err.Error())
55 | }
56 |
57 | return &types.QueryIncomingResponse{Transactions: transactions, Pagination: pageRes}, nil
58 | }
59 |
--------------------------------------------------------------------------------
/x/ibank/keeper/grpc_query_show_outgoing.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | "mun/x/ibank/types"
8 |
9 | "github.com/cosmos/cosmos-sdk/store/prefix"
10 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | querytypes "github.com/cosmos/cosmos-sdk/types/query"
13 | db "github.com/tendermint/tm-db"
14 | "google.golang.org/grpc/codes"
15 | "google.golang.org/grpc/status"
16 | )
17 |
18 | func (k Keeper) Outgoing(goCtx context.Context, req *types.QueryOutgoingRequest) (*types.QueryOutgoingResponse, error) {
19 | if req == nil {
20 | return nil, status.Error(codes.InvalidArgument, "invalid request")
21 | }
22 |
23 | var transactions []types.TransactionWrapper
24 | ctx := sdk.UnwrapSDKContext(goCtx)
25 |
26 | store := ctx.KVStore(k.storeKey)
27 | transactionStore := prefix.NewStore(store, types.KeyPrefix(types.TransactionKey))
28 |
29 | expirationDuration := k.GetParams(ctx).DurationOfExpiration
30 |
31 | pageRes, err := paginate(transactionStore, req.Pagination, func(key []byte, value []byte, appendable bool) (error, bool) {
32 | var transaction types.Transaction
33 | if err := k.cdc.Unmarshal(value, &transaction); err != nil {
34 | return err, false
35 | }
36 |
37 | // check sender
38 | if req.Sender != transaction.Sender {
39 | return nil, false
40 | }
41 |
42 | // only shows pending transactions
43 | if req.Pending && transaction.Status != types.TxPending {
44 | return nil, false
45 | }
46 |
47 | if appendable {
48 | wrapper := types.TransactionWrapper{
49 | Transaction: transaction,
50 | TimeLeft: CalculateTimeLeftInSeconds(transaction.SentAt, ctx.BlockTime(), expirationDuration),
51 | }
52 | transactions = append(transactions, wrapper)
53 | }
54 | return nil, true
55 | })
56 |
57 | if err != nil {
58 | return nil, status.Error(codes.Internal, err.Error())
59 | }
60 |
61 | return &types.QueryOutgoingResponse{Transactions: transactions, Pagination: pageRes}, nil
62 | }
63 |
64 | func paginate(
65 | prefixStore storetypes.KVStore,
66 | pageRequest *querytypes.PageRequest,
67 | onResult func([]byte, []byte, bool) (error, bool),
68 | ) (*querytypes.PageResponse, error) {
69 | if pageRequest == nil {
70 | pageRequest = &querytypes.PageRequest{}
71 | }
72 |
73 | offset := pageRequest.Offset
74 | key := pageRequest.Key
75 | limit := pageRequest.Limit
76 | countTotal := pageRequest.CountTotal
77 | reverse := pageRequest.Reverse
78 |
79 | if offset > 0 && key != nil {
80 | return nil, fmt.Errorf("invalid request, either offset or key is expected, got both")
81 | }
82 |
83 | if limit == 0 {
84 | limit = 100 //DefaultLimit
85 |
86 | // count total results when the limit is zero/not supplied
87 | countTotal = true
88 | }
89 |
90 | if len(key) != 0 {
91 | iterator := getIterator(prefixStore, key, reverse)
92 | defer iterator.Close()
93 |
94 | var count uint64
95 | var nextKey []byte
96 |
97 | for ; iterator.Valid(); iterator.Next() {
98 | if count == limit {
99 | nextKey = iterator.Key()
100 | break
101 | }
102 | if iterator.Error() != nil {
103 | return nil, iterator.Error()
104 | }
105 | err, eligible := onResult(iterator.Key(), iterator.Value(), true)
106 | if !eligible {
107 | continue
108 | }
109 | if err != nil {
110 | return nil, err
111 | }
112 |
113 | count++
114 | }
115 |
116 | return &querytypes.PageResponse{
117 | NextKey: nextKey,
118 | }, nil
119 | }
120 |
121 | iterator := getIterator(prefixStore, nil, reverse)
122 | defer iterator.Close()
123 |
124 | end := offset + limit
125 |
126 | var count uint64
127 | var nextKey []byte
128 |
129 | for ; iterator.Valid(); iterator.Next() {
130 | err, eligible := onResult(iterator.Key(), iterator.Value(), count >= offset)
131 | if err != nil {
132 | return nil, err
133 | }
134 | if !eligible {
135 | continue
136 | }
137 |
138 | if count == end {
139 | nextKey = iterator.Key()
140 | if !countTotal {
141 | break
142 | }
143 | }
144 |
145 | if iterator.Error() != nil {
146 | return nil, iterator.Error()
147 | }
148 |
149 | count++
150 | }
151 |
152 | res := &querytypes.PageResponse{NextKey: nextKey}
153 | if countTotal {
154 | res.Total = count
155 | }
156 |
157 | return res, nil
158 | }
159 |
160 | func getIterator(prefixStore storetypes.KVStore, start []byte, reverse bool) db.Iterator {
161 | if reverse {
162 | var end []byte
163 | if start != nil {
164 | itr := prefixStore.Iterator(start, nil)
165 | defer itr.Close()
166 | if itr.Valid() {
167 | itr.Next()
168 | end = itr.Key()
169 | }
170 | }
171 | return prefixStore.ReverseIterator(nil, end)
172 | }
173 | return prefixStore.Iterator(start, nil)
174 | }
175 |
--------------------------------------------------------------------------------
/x/ibank/keeper/grpc_query_transaction.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/store/prefix"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
11 | "google.golang.org/grpc/codes"
12 | "google.golang.org/grpc/status"
13 | )
14 |
15 | func (k Keeper) TransactionAll(c context.Context, req *types.QueryAllTransactionRequest) (*types.QueryAllTransactionResponse, error) {
16 | if req == nil {
17 | return nil, status.Error(codes.InvalidArgument, "invalid request")
18 | }
19 |
20 | var transactions []types.TransactionWrapper
21 | ctx := sdk.UnwrapSDKContext(c)
22 |
23 | store := ctx.KVStore(k.storeKey)
24 | transactionStore := prefix.NewStore(store, types.KeyPrefix(types.TransactionKey))
25 |
26 | expirationDuration := k.GetParams(ctx).DurationOfExpiration
27 |
28 | pageRes, err := paginate(transactionStore, req.Pagination, func(key []byte, value []byte, appendable bool) (error, bool) {
29 | var transaction types.Transaction
30 | if err := k.cdc.Unmarshal(value, &transaction); err != nil {
31 | return err, false
32 | }
33 |
34 | if transaction.Sender != req.Address && transaction.Receiver != req.Address {
35 | return nil, false
36 | }
37 |
38 | wrapper := types.TransactionWrapper{
39 | Transaction: transaction,
40 | TimeLeft: CalculateTimeLeftInSeconds(transaction.SentAt, ctx.BlockTime(), expirationDuration),
41 | }
42 | transactions = append(transactions, wrapper)
43 | return nil, true
44 | })
45 |
46 | if err != nil {
47 | return nil, status.Error(codes.Internal, err.Error())
48 | }
49 |
50 | return &types.QueryAllTransactionResponse{Transactions: transactions, Pagination: pageRes}, nil
51 | }
52 |
53 | func (k Keeper) Transaction(c context.Context, req *types.QueryGetTransactionRequest) (*types.QueryGetTransactionResponse, error) {
54 | if req == nil {
55 | return nil, status.Error(codes.InvalidArgument, "invalid request")
56 | }
57 |
58 | ctx := sdk.UnwrapSDKContext(c)
59 | transaction, found := k.GetTransaction(ctx, req.Id)
60 | if !found {
61 | return nil, sdkerrors.ErrKeyNotFound
62 | }
63 |
64 | return &types.QueryGetTransactionResponse{Transaction: transaction}, nil
65 | }
66 |
--------------------------------------------------------------------------------
/x/ibank/keeper/keeper.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "crypto/sha256"
5 | "errors"
6 | "fmt"
7 | "strconv"
8 |
9 | "mun/x/ibank/types"
10 |
11 | "github.com/cosmos/cosmos-sdk/codec"
12 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
13 | sdk "github.com/cosmos/cosmos-sdk/types"
14 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
15 | paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
16 | "github.com/tendermint/tendermint/libs/log"
17 | )
18 |
19 | type (
20 | Keeper struct {
21 | cdc codec.BinaryCodec
22 | storeKey storetypes.StoreKey
23 | // memKey storetypes.StoreKey
24 | paramstore paramtypes.Subspace
25 |
26 | accountKeeper types.AccountKeeper
27 | bankKeeper types.BankKeeper
28 | }
29 | )
30 |
31 | func NewKeeper(
32 | cdc codec.BinaryCodec,
33 | storeKey storetypes.StoreKey,
34 | ps paramtypes.Subspace,
35 |
36 | accountKeeper types.AccountKeeper,
37 | bankKeeper types.BankKeeper,
38 | ) *Keeper {
39 | // set KeyTable if it has not already been set
40 | if !ps.HasKeyTable() {
41 | ps = ps.WithKeyTable(types.ParamKeyTable())
42 | }
43 |
44 | return &Keeper{
45 |
46 | cdc: cdc,
47 | storeKey: storeKey,
48 | paramstore: ps,
49 | accountKeeper: accountKeeper,
50 | bankKeeper: bankKeeper,
51 | }
52 | }
53 |
54 | func (k Keeper) Logger(ctx sdk.Context) log.Logger {
55 | return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
56 | }
57 |
58 | func (k Keeper) CreateModuleAccount(ctx sdk.Context) {
59 | macc := authtypes.NewEmptyModuleAccount(types.ModuleName, authtypes.Minter)
60 | k.accountKeeper.SetModuleAccount(ctx, macc)
61 | }
62 |
63 | // This function send amt Coin from `from` account to a module account
64 | func (k Keeper) SendCoin(ctx sdk.Context, from, to sdk.AccAddress, amt sdk.Coin, password string) error {
65 | if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, from, types.ModuleName, sdk.Coins{amt}); err != nil {
66 | return err
67 | }
68 |
69 | txnID := k.AppendTransaction(ctx, types.Transaction{
70 | Sender: from.String(),
71 | Receiver: to.String(),
72 | Coins: sdk.Coins{amt},
73 | SentAt: ctx.BlockTime(),
74 | ReceivedAt: ctx.BlockTime(),
75 | Status: types.TxPending,
76 | Password: password,
77 | Retry: 3,
78 | })
79 |
80 | ctx.EventManager().EmitEvent(sdk.NewEvent(
81 | types.EventTypeIBank,
82 | sdk.NewAttribute(types.AttributeKeyAction, "send"),
83 | sdk.NewAttribute(types.AttributeKeySender, from.String()),
84 | sdk.NewAttribute(types.AttributeKeyRecipient, to.String()),
85 | sdk.NewAttribute(types.AttributeKeyAmount, amt.Amount.String()+amt.GetDenom()),
86 | sdk.NewAttribute(types.AttributeKeyRemittanceID, strconv.FormatUint(txnID, 10)),
87 | ))
88 |
89 | return nil
90 | }
91 |
92 | func (k Keeper) ReceiveCoin(
93 | ctx sdk.Context,
94 | receiver sdk.AccAddress,
95 | transactionID int64,
96 | words string,
97 | ) error {
98 | txn, found := k.GetTransaction(ctx, uint64(transactionID))
99 | if !found {
100 | return types.ErrNoTransaction
101 | }
102 |
103 | // Check if transaction is performed
104 | if txn.Status != types.TxPending {
105 | if txn.Status == types.TxSent {
106 | return types.ErrAlreadyReceived
107 | } else if txn.Status == types.TxExpired {
108 | return types.ErrTxExpired
109 | } else {
110 | return types.ErrTxDeclined
111 | }
112 | }
113 |
114 | // Check if transaction is expired
115 | if k.IsExpired(ctx, txn) {
116 | return types.ErrTxExpired
117 | }
118 |
119 | to, err := sdk.AccAddressFromBech32(txn.Receiver)
120 | if err != nil || !to.Equals(receiver) {
121 | return types.ErrInvalidReceiver
122 | }
123 |
124 | // check password hash
125 | // hash := sha256.Sum256([]byte(password))
126 | // formattedHash := fmt.Sprintf("%x", hash)
127 | if txn.Password != k.GetPasswordFromWords(ctx, words) {
128 | txn.Retry--
129 |
130 | if txn.Retry == 0 {
131 | // maximum number of retries is exceeded, the funds will return to the sender
132 | ctx.EventManager().EmitEvent(
133 | sdk.NewEvent(
134 | types.EventTypeIBank,
135 | sdk.NewAttribute(types.AttributeKeyAction, "receive"),
136 | sdk.NewAttribute(types.AttributeKeyReceiveSuccess, "false"),
137 | sdk.NewAttribute(types.AttributeKeyRefunded, "true"),
138 | ),
139 | )
140 |
141 | return k.Refund(ctx, txn, false)
142 | } else {
143 | // incorrect password; deduct retry and save
144 | k.SetTransaction(ctx, txn)
145 | ctx.EventManager().EmitEvent(
146 | sdk.NewEvent(
147 | types.EventTypeIBank,
148 | sdk.NewAttribute(types.AttributeKeyAction, "receive"),
149 | sdk.NewAttribute(types.AttributeKeyReceiveSuccess, "false"),
150 | ),
151 | )
152 | return nil
153 | }
154 | }
155 |
156 | txn.ReceivedAt = ctx.BlockTime()
157 | txn.Status = types.TxSent
158 | k.SetTransaction(ctx, txn)
159 |
160 | err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, txn.Coins)
161 |
162 | if err == nil {
163 | ctx.EventManager().EmitEvent(
164 | sdk.NewEvent(
165 | types.EventTypeIBank,
166 | sdk.NewAttribute(types.AttributeKeyAction, "receive"),
167 | sdk.NewAttribute(types.AttributeKeyReceiveSuccess, "true"),
168 | ),
169 | )
170 | } else {
171 | ctx.EventManager().EmitEvent(
172 | sdk.NewEvent(
173 | types.EventTypeIBank,
174 | sdk.NewAttribute(types.AttributeKeyAction, "receive"),
175 | sdk.NewAttribute(types.AttributeKeyReceiveSuccess, "false"),
176 | ),
177 | )
178 | }
179 |
180 | return err
181 | }
182 |
183 | func (k Keeper) IsExpired(ctx sdk.Context, tranaction types.Transaction) bool {
184 | params := k.GetParams(ctx)
185 |
186 | // transaction.SentAt + ExpirationDuration < CurrentTime -> Expired
187 | return tranaction.SentAt.Add(params.GetDurationOfExpiration()).Before(ctx.BlockTime())
188 | }
189 |
190 | func (k Keeper) Refund(ctx sdk.Context, transaction types.Transaction, expired bool) error {
191 | if transaction.Status != types.TxPending {
192 | return errors.New("only can refund pending txns")
193 | }
194 |
195 | if expired && !k.IsExpired(ctx, transaction) {
196 | return errors.New("tx is in progress")
197 | }
198 |
199 | sender, err := sdk.AccAddressFromBech32(transaction.Sender)
200 | if err != nil {
201 | return err
202 | }
203 |
204 | if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, transaction.Coins); err != nil {
205 | return err
206 | }
207 |
208 | if expired {
209 | transaction.Status = types.TxExpired
210 | } else {
211 | transaction.Status = types.TxDeclined
212 | transaction.Retry = 0
213 | }
214 | k.SetTransaction(ctx, transaction)
215 |
216 | return nil
217 | }
218 |
219 | func (k Keeper) GetPasswordFromWords(ctx sdk.Context, words string) string {
220 | hash := sha256.Sum256([]byte(words))
221 | return fmt.Sprintf("%x", hash)
222 | }
223 |
--------------------------------------------------------------------------------
/x/ibank/keeper/keeper_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "mun/app"
5 | "mun/x/ibank/types"
6 | "testing"
7 |
8 | "github.com/cosmos/cosmos-sdk/simapp"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | "github.com/stretchr/testify/suite"
11 | tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
12 | "github.com/tendermint/tendermint/types/time"
13 | )
14 |
15 | const (
16 | fooDenom = "foo"
17 | barDenom = "bar"
18 | )
19 |
20 | func newFooCoin(amt int64) sdk.Coin {
21 | return sdk.NewInt64Coin(fooDenom, amt)
22 | }
23 |
24 | func newBarCoin(amt int64) sdk.Coin {
25 | return sdk.NewInt64Coin(barDenom, amt)
26 | }
27 |
28 | type IntegrationTestSuite struct {
29 | suite.Suite
30 |
31 | Ctx sdk.Context
32 | App *app.App
33 | }
34 |
35 | func (suite *IntegrationTestSuite) SetupTest() {
36 | isCheckTx := false
37 |
38 | suite.App = app.Setup()
39 | suite.Ctx = suite.App.GetBaseApp().NewContext(isCheckTx, tmproto.Header{
40 | ChainID: "mun-test-1",
41 | Height: 1,
42 | Time: time.Now().UTC(),
43 | })
44 | }
45 |
46 | func (suite *IntegrationTestSuite) TestCreateModuleAccount() {
47 | app := suite.App
48 |
49 | // remove module account
50 | ibankModuleAcc := app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName))
51 | app.AccountKeeper.RemoveAccount(suite.Ctx, ibankModuleAcc)
52 |
53 | // ensure module account was removed
54 | suite.Ctx = app.BaseApp.NewContext(false, tmproto.Header{})
55 | ibankModuleAcc = app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName))
56 | suite.Require().Nil(ibankModuleAcc)
57 |
58 | // create module account
59 | app.IbankKeeper.CreateModuleAccount(suite.Ctx)
60 |
61 | // check module account is initialized
62 | ibankModuleAcc = app.AccountKeeper.GetAccount(suite.Ctx, app.AccountKeeper.GetModuleAddress(types.ModuleName))
63 | suite.Require().NotNil(ibankModuleAcc)
64 | }
65 |
66 | func (suite *IntegrationTestSuite) TestSendCoin() {
67 | app, ctx := suite.App, suite.Ctx
68 | balances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
69 |
70 | // Alice
71 | addrAlice := sdk.AccAddress([]byte("addr1_______________"))
72 | accAlice := app.AccountKeeper.NewAccountWithAddress(ctx, addrAlice)
73 | app.AccountKeeper.SetAccount(ctx, accAlice)
74 | suite.Require().NoError(simapp.FundAccount(app.BankKeeper, ctx, addrAlice, balances))
75 | suite.Require().Equal(balances, app.BankKeeper.GetAllBalances(ctx, addrAlice))
76 |
77 | // Bob
78 | addrBob := sdk.AccAddress([]byte("addr2_______________"))
79 |
80 | suite.Require().Nil(app.AccountKeeper.GetAccount(ctx, addrBob))
81 | app.BankKeeper.GetAllBalances(ctx, addrBob)
82 | suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addrBob))
83 |
84 | // Module account
85 | addrIbank := app.AccountKeeper.GetModuleAddress(types.ModuleName)
86 | suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addrIbank))
87 |
88 | // Sending
89 | sendAmt := newFooCoin(50)
90 | password := "password"
91 | suite.Require().NoError(app.IbankKeeper.SendCoin(ctx, addrAlice, addrBob, sendAmt, password))
92 |
93 | // Check balances
94 | expectedAliceBalances := sdk.NewCoins(newFooCoin(50), newBarCoin(50))
95 | app.BankKeeper.GetAllBalances(ctx, addrAlice)
96 | suite.Require().Equal(expectedAliceBalances, app.BankKeeper.GetAllBalances(ctx, addrAlice))
97 | suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addrBob))
98 | suite.Require().Equal(sdk.NewCoins(sendAmt), app.BankKeeper.GetAllBalances(ctx, addrIbank))
99 |
100 | // Check pending transaction
101 | tx, found := app.IbankKeeper.GetTransaction(ctx, 0)
102 | suite.Require().Equal(true, found)
103 | suite.Require().Equal([]sdk.Coin{sendAmt}, tx.Coins)
104 | suite.Require().Equal(password, tx.Password)
105 | suite.Require().Equal(addrAlice.String(), tx.Sender)
106 | suite.Require().Equal(addrBob.String(), tx.Receiver)
107 | suite.Require().Equal(int32(3), tx.Retry)
108 | suite.Require().Equal(types.TxnStatus_TXN_PENDING, tx.Status)
109 | }
110 |
111 | func (suite *IntegrationTestSuite) TestReceiveCoin() {
112 | app, ctx := suite.App, suite.Ctx
113 | bankKeeper := app.BankKeeper
114 |
115 | // Test case
116 | aliceBalances := sdk.NewCoins(newFooCoin(100), newBarCoin(50))
117 | bobBalances := sdk.NewCoins(newFooCoin(10))
118 | sendAmt := newBarCoin(30)
119 | updatedAliceBal1 := aliceBalances.Sub(sdk.NewCoins(sendAmt)) // balance after send
120 | expectedAliceBal := aliceBalances.Sub(sdk.NewCoins(sendAmt)) //sdk.NewCoins(newFooCoin(90), newBarCoin(50))
121 | expectedBobBal := bobBalances.Add(sendAmt)
122 |
123 | phrases := "word1 word2 word3 word4 word5 word6"
124 | password := app.IbankKeeper.GetPasswordFromWords(ctx, phrases)
125 | transactionId := 0
126 |
127 | // Alice
128 | addrAlice := sdk.AccAddress([]byte("addr1_______________"))
129 | accAlice := app.AccountKeeper.NewAccountWithAddress(ctx, addrAlice)
130 | app.AccountKeeper.SetAccount(ctx, accAlice)
131 | suite.Require().NoError(simapp.FundAccount(bankKeeper, ctx, addrAlice, aliceBalances))
132 | suite.Require().Equal(aliceBalances, bankKeeper.GetAllBalances(ctx, addrAlice))
133 |
134 | // Bob
135 | addrBob := sdk.AccAddress([]byte("addr2_______________"))
136 | accBob := app.AccountKeeper.NewAccountWithAddress(ctx, addrBob)
137 | app.AccountKeeper.SetAccount(ctx, accBob)
138 | suite.Require().NoError(simapp.FundAccount(bankKeeper, ctx, addrBob, bobBalances))
139 | suite.Require().Equal(bobBalances, bankKeeper.GetAllBalances(ctx, addrBob))
140 |
141 | // Send
142 | suite.Require().NoError(app.IbankKeeper.SendCoin(ctx, addrAlice, addrBob, sendAmt, password))
143 |
144 | // Check balance after send
145 | suite.Require().Equal(updatedAliceBal1, bankKeeper.GetAllBalances(ctx, addrAlice))
146 |
147 | // Receive
148 | suite.Require().NoError(app.IbankKeeper.ReceiveCoin(ctx, addrBob, int64(transactionId), phrases))
149 |
150 | // check tx
151 | tx, found := app.IbankKeeper.GetTransaction(ctx, uint64(transactionId))
152 | suite.Require().Equal(true, found)
153 | suite.Require().Equal(types.TxnStatus_TXN_SENT, tx.Status)
154 |
155 | // Check result after receive
156 | suite.Require().Equal(expectedAliceBal, bankKeeper.GetAllBalances(ctx, addrAlice))
157 | suite.Require().Equal(expectedBobBal, bankKeeper.GetAllBalances(ctx, addrBob))
158 | }
159 |
160 | func (suite *IntegrationTestSuite) TestRefund() {
161 | }
162 |
163 | func TestKeeperTestSuite(t *testing.T) {
164 | suite.Run(t, new(IntegrationTestSuite))
165 | }
166 |
--------------------------------------------------------------------------------
/x/ibank/keeper/msg_server.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/ibank/types"
5 | )
6 |
7 | type msgServer struct {
8 | Keeper
9 | }
10 |
11 | // NewMsgServerImpl returns an implementation of the MsgServer interface
12 | // for the provided Keeper.
13 | func NewMsgServerImpl(keeper Keeper) types.MsgServer {
14 | return &msgServer{Keeper: keeper}
15 | }
16 |
17 | var _ types.MsgServer = msgServer{}
18 |
--------------------------------------------------------------------------------
/x/ibank/keeper/msg_server_receive.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | func (k msgServer) Receive(goCtx context.Context, msg *types.MsgReceive) (*types.MsgReceiveResponse, error) {
12 | ctx := sdk.UnwrapSDKContext(goCtx)
13 |
14 | receiver, err := sdk.AccAddressFromBech32(msg.Receiver)
15 | if err != nil {
16 | return nil, err
17 | }
18 |
19 | if err := k.ReceiveCoin(ctx, receiver, msg.TransactionId, msg.Password); err != nil {
20 | return nil, err
21 | }
22 |
23 | return &types.MsgReceiveResponse{}, nil
24 | }
25 |
--------------------------------------------------------------------------------
/x/ibank/keeper/msg_server_send.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | func (k msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) {
12 | ctx := sdk.UnwrapSDKContext(goCtx)
13 |
14 | from, err := sdk.AccAddressFromBech32(msg.FromAddress)
15 | if err != nil {
16 | return nil, err
17 | }
18 | to, err := sdk.AccAddressFromBech32(msg.ToAddress)
19 | if err != nil {
20 | return nil, err
21 | }
22 |
23 | if err := k.SendCoin(ctx, from, to, msg.Amount, msg.PasswordHash); err != nil {
24 | return nil, err
25 | }
26 |
27 | return &types.MsgSendResponse{}, nil
28 | }
29 |
--------------------------------------------------------------------------------
/x/ibank/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "mun/x/ibank/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // GetParams get all parameters as types.Params
10 | func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
11 | k.paramstore.GetParamSet(ctx, ¶ms)
12 | return
13 | }
14 |
15 | // SetParams set the params
16 | func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
17 | k.paramstore.SetParamSet(ctx, ¶ms)
18 | }
19 |
--------------------------------------------------------------------------------
/x/ibank/keeper/transaction.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "encoding/binary"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/store/prefix"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | )
11 |
12 | // GetTransactionCount get the total number of transaction
13 | func (k Keeper) GetTransactionCount(ctx sdk.Context) uint64 {
14 | store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
15 | byteKey := types.KeyPrefix(types.TransactionCountKey)
16 | bz := store.Get(byteKey)
17 |
18 | // Count doesn't exist: no element
19 | if bz == nil {
20 | return 0
21 | }
22 |
23 | // Parse bytes
24 | return binary.BigEndian.Uint64(bz)
25 | }
26 |
27 | // SetTransactionCount set the total number of transaction
28 | func (k Keeper) SetTransactionCount(ctx sdk.Context, count uint64) {
29 | store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
30 | byteKey := types.KeyPrefix(types.TransactionCountKey)
31 | bz := make([]byte, 8)
32 | binary.BigEndian.PutUint64(bz, count)
33 | store.Set(byteKey, bz)
34 | }
35 |
36 | func (k Keeper) GetTransactionChaser(ctx sdk.Context) uint64 {
37 | store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
38 | byteKey := types.KeyPrefix(types.TransactionChaserKey)
39 | bz := store.Get(byteKey)
40 |
41 | // Chaser doesn't exist: no element
42 | if bz == nil {
43 | return 0
44 | }
45 |
46 | // Parse bytes
47 | return binary.BigEndian.Uint64(bz)
48 | }
49 |
50 | func (k Keeper) SetTransactionChaser(ctx sdk.Context, chaser uint64) {
51 | store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte{})
52 | byteKey := types.KeyPrefix(types.TransactionChaserKey)
53 | bz := make([]byte, 8)
54 | binary.BigEndian.PutUint64(bz, chaser)
55 | store.Set(byteKey, bz)
56 | }
57 |
58 | // AppendTransaction appends a transaction in the store with a new id and update the count
59 | func (k Keeper) AppendTransaction(
60 | ctx sdk.Context,
61 | transaction types.Transaction,
62 | ) uint64 {
63 | // Create the transaction
64 | count := k.GetTransactionCount(ctx)
65 |
66 | // Set the ID of the appended value
67 | transaction.Id = count
68 |
69 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransactionKey))
70 | appendedValue := k.cdc.MustMarshal(&transaction)
71 | store.Set(GetTransactionIDBytes(transaction.Id), appendedValue)
72 |
73 | // Update transaction count
74 | k.SetTransactionCount(ctx, count+1)
75 |
76 | return count
77 | }
78 |
79 | // SetTransaction set a specific transaction in the store
80 | func (k Keeper) SetTransaction(ctx sdk.Context, transaction types.Transaction) {
81 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransactionKey))
82 | b := k.cdc.MustMarshal(&transaction)
83 | store.Set(GetTransactionIDBytes(transaction.Id), b)
84 | }
85 |
86 | // GetTransaction returns a transaction from its id
87 | func (k Keeper) GetTransaction(ctx sdk.Context, id uint64) (val types.Transaction, found bool) {
88 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransactionKey))
89 | b := store.Get(GetTransactionIDBytes(id))
90 | if b == nil {
91 | return val, false
92 | }
93 | k.cdc.MustUnmarshal(b, &val)
94 | return val, true
95 | }
96 |
97 | // RemoveTransaction removes a transaction from the store
98 | func (k Keeper) RemoveTransaction(ctx sdk.Context, id uint64) {
99 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransactionKey))
100 | store.Delete(GetTransactionIDBytes(id))
101 | }
102 |
103 | // GetAllTransaction returns all transaction
104 | func (k Keeper) GetAllTransaction(ctx sdk.Context) (list []types.Transaction) {
105 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TransactionKey))
106 | iterator := sdk.KVStorePrefixIterator(store, []byte{})
107 |
108 | defer iterator.Close()
109 |
110 | for ; iterator.Valid(); iterator.Next() {
111 | var val types.Transaction
112 | k.cdc.MustUnmarshal(iterator.Value(), &val)
113 | list = append(list, val)
114 | }
115 |
116 | return
117 | }
118 |
119 | // GetTransactionIDBytes returns the byte representation of the ID
120 | func GetTransactionIDBytes(id uint64) []byte {
121 | bz := make([]byte, 8)
122 | binary.BigEndian.PutUint64(bz, id)
123 | return bz
124 | }
125 |
126 | // GetTransactionIDFromBytes returns ID in uint64 format from a byte array
127 | func GetTransactionIDFromBytes(bz []byte) uint64 {
128 | return binary.BigEndian.Uint64(bz)
129 | }
130 |
--------------------------------------------------------------------------------
/x/ibank/module_simulation.go:
--------------------------------------------------------------------------------
1 | package ibank
2 |
3 | import (
4 | "math/rand"
5 | "mun/x/ibank/simulation"
6 | "mun/x/ibank/types"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/types/module"
10 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
11 | )
12 |
13 | // AppModuleSimulation functions
14 |
15 | // GenerateGenesisState creates a randomized GenState of the ibank module.
16 | func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
17 | simulation.RandomizedGenState(simState)
18 | }
19 |
20 | // RandomizedParams creates randomized cronos param changes for the simulator.
21 | func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
22 | return simulation.ParamChanges(r)
23 | }
24 |
25 | // ProposalContents returns nothing for governance proposals.
26 | func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
27 | return nil
28 | }
29 |
30 | // RegisterStoreDecoder registers a decoder for ibank module's types
31 | func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
32 | sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
33 | }
34 |
35 | // WeightedOperations returns the all the ibank module operations with their respective weights.
36 | func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
37 | return simulation.WeightedOperations(
38 | simState.AppParams, simState.Cdc, am.accountKeeper, am.bankKeeper, &am.keeper,
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/x/ibank/simulation/decoder.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "encoding/binary"
5 | "fmt"
6 |
7 | "mun/x/ibank/types"
8 |
9 | "github.com/cosmos/cosmos-sdk/codec"
10 | "github.com/cosmos/cosmos-sdk/types/kv"
11 | )
12 |
13 | // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
14 | // Value to the corresponding ibank type.
15 | func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
16 | return func(kvA, kvB kv.Pair) string {
17 | switch {
18 | case string(kvA.Key) == types.TransactionKey:
19 | var txA, txB types.Transaction
20 | cdc.MustUnmarshal(kvA.Value, &txA)
21 | cdc.MustUnmarshal(kvB.Value, &txB)
22 | return fmt.Sprintf("%v\n%v", txA, txB)
23 |
24 | case string(kvA.Key) == types.TransactionCountKey:
25 | return fmt.Sprintf("%v\n%v", binary.BigEndian.Uint64(kvA.Value), binary.BigEndian.Uint64(kvB.Value))
26 |
27 | case string(kvA.Key) == types.TransactionChaserKey:
28 | return fmt.Sprintf("%v\n%v", binary.BigEndian.Uint64(kvA.Value), binary.BigEndian.Uint64(kvB.Value))
29 |
30 | default:
31 | panic(fmt.Sprintf("invalid ibank key prefix %v", kvA.Key))
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/x/ibank/simulation/decoder_test.go:
--------------------------------------------------------------------------------
1 | package simulation_test
2 |
3 | import (
4 | "encoding/binary"
5 | "fmt"
6 | "testing"
7 |
8 | "mun/app"
9 | "mun/x/ibank/simulation"
10 | "mun/x/ibank/types"
11 |
12 | "github.com/cosmos/cosmos-sdk/types/kv"
13 | "github.com/stretchr/testify/require"
14 | )
15 |
16 | func TestDecodeStore(t *testing.T) {
17 | cdc := app.MakeEncodingConfig().Marshaler
18 | dec := simulation.NewDecodeStore(cdc)
19 |
20 | tx := types.Transaction{
21 | Id: 1,
22 | }
23 | txCount := 1
24 | txChaser := 1
25 | txCountInBytes := make([]byte, 8)
26 | txChaserInBytes := make([]byte, 8)
27 | binary.BigEndian.PutUint64(txCountInBytes, uint64(txCount))
28 | binary.BigEndian.PutUint64(txChaserInBytes, uint64(txChaser))
29 |
30 | kvParis := kv.Pairs{
31 | Pairs: []kv.Pair{
32 | {Key: []byte(types.TransactionKey), Value: cdc.MustMarshal(&tx)},
33 | {Key: []byte(types.TransactionCountKey), Value: txCountInBytes},
34 | {Key: []byte(types.TransactionChaserKey), Value: txChaserInBytes},
35 | },
36 | }
37 |
38 | tests := []struct {
39 | name string
40 | expectedLog string
41 | }{
42 | {"TransactionKey", fmt.Sprintf("%v\n%v", tx, tx)},
43 | {"TransactionCounterKey", fmt.Sprintf("%v\n%v", txCount, txCount)},
44 | {"TransactionChaserKey", fmt.Sprintf("%v\n%v", txChaser, txChaser)},
45 | {"other", ""},
46 | }
47 |
48 | for i, tt := range tests {
49 | i, tt := i, tt
50 | t.Run(tt.name, func(t *testing.T) {
51 | switch i {
52 | case len(tests) - 1:
53 | require.Panics(t, func() { dec(kvParis.Pairs[i], kvParis.Pairs[i]) }, tt.name)
54 | default:
55 | require.Equal(t, tt.expectedLog, dec(kvParis.Pairs[i], kvParis.Pairs[i]), tt.name)
56 | }
57 | })
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/x/ibank/simulation/genesis.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "math/rand"
7 | "time"
8 |
9 | "mun/x/ibank/types"
10 |
11 | "github.com/cosmos/cosmos-sdk/types/module"
12 | // "github.com/cosmos/cosmos-sdk/x/staking/types"
13 | )
14 |
15 | // Simulation parameter constants
16 | const (
17 | ExpirationTime = "expiration_time"
18 | )
19 |
20 | func getExpirationTime(r *rand.Rand) time.Duration {
21 | dur, _ := time.ParseDuration(types.DefaultDurationOfExpiration)
22 | return dur
23 | }
24 |
25 | func RandomizedGenState(simState *module.SimulationState) {
26 | var (
27 | expirationTime time.Duration
28 | )
29 |
30 | simState.AppParams.GetOrGenerate(
31 | simState.Cdc, ExpirationTime, &expirationTime, simState.Rand,
32 | func(r *rand.Rand) { expirationTime = getExpirationTime(r) },
33 | )
34 |
35 | params := types.NewParams(expirationTime)
36 |
37 | ibankGenesis := types.NewGenesisState(params)
38 |
39 | bz, err := json.MarshalIndent(&ibankGenesis.Params, "", " ")
40 | if err != nil {
41 | panic(err)
42 | }
43 | fmt.Printf("Selected randomly generated ibank parameters:\n%s\n", bz)
44 |
45 | simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(ibankGenesis)
46 | }
47 |
--------------------------------------------------------------------------------
/x/ibank/simulation/genesis_test.go:
--------------------------------------------------------------------------------
1 | package simulation_test
2 |
3 | import (
4 | "encoding/json"
5 | "math/rand"
6 | "mun/x/ibank/simulation"
7 | "mun/x/ibank/types"
8 | "testing"
9 | "time"
10 |
11 | "github.com/cosmos/cosmos-sdk/codec"
12 | "github.com/cosmos/cosmos-sdk/types/module"
13 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
14 | "github.com/stretchr/testify/require"
15 |
16 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
17 | )
18 |
19 | func TestRandomizedGenState(t *testing.T) {
20 | registry := codectypes.NewInterfaceRegistry()
21 | types.RegisterInterfaces(registry)
22 | cdc := codec.NewProtoCodec(registry)
23 |
24 | s := rand.NewSource(1)
25 | r := rand.New(s)
26 |
27 | simState := module.SimulationState{
28 | AppParams: make(simtypes.AppParams),
29 | Cdc: cdc,
30 | Rand: r,
31 | NumBonded: 3,
32 | Accounts: simtypes.RandomAccounts(r, 3),
33 | InitialStake: 1000,
34 | GenState: make(map[string]json.RawMessage),
35 | }
36 |
37 | simulation.RandomizedGenState(&simState)
38 |
39 | var ibankGenesis types.GenesisState
40 | simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &ibankGenesis)
41 |
42 | require.Equal(t, time.Duration(172800000000000), ibankGenesis.Params.DurationOfExpiration)
43 | }
44 |
--------------------------------------------------------------------------------
/x/ibank/simulation/helpers.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
6 | )
7 |
8 | // FindAccount find a specific address from an account list
9 | func FindAccount(accs []simtypes.Account, address string) (simtypes.Account, bool) {
10 | creator, err := sdk.AccAddressFromBech32(address)
11 | if err != nil {
12 | panic(err)
13 | }
14 | return simtypes.FindAccount(accs, creator)
15 | }
16 |
--------------------------------------------------------------------------------
/x/ibank/simulation/operations.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "math/rand"
5 | "mun/x/ibank/keeper"
6 | "mun/x/ibank/types"
7 |
8 | "github.com/cosmos/cosmos-sdk/baseapp"
9 | "github.com/cosmos/cosmos-sdk/codec"
10 | simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
13 | "github.com/cosmos/cosmos-sdk/x/simulation"
14 | )
15 |
16 | const (
17 | DefaultWeightMsgSend int = 100
18 | DefaultWeightMsgReceive int = 100
19 |
20 | OpWeightMsgSend = "op_weight_msg_send"
21 | OpWeightMsgReceive = "op_weight_msg_receive"
22 | )
23 |
24 | func WeightedOperations(
25 | appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper,
26 | bk types.BankKeeper, k *keeper.Keeper,
27 | ) simulation.WeightedOperations {
28 | var (
29 | weightMsgSend int
30 | weightMsgReceive int
31 | )
32 |
33 | appParams.GetOrGenerate(cdc, OpWeightMsgSend, &weightMsgSend, nil,
34 | func(_ *rand.Rand) {
35 | weightMsgSend = DefaultWeightMsgSend
36 | },
37 | )
38 |
39 | appParams.GetOrGenerate(cdc, OpWeightMsgReceive, &weightMsgReceive, nil,
40 | func(_ *rand.Rand) {
41 | weightMsgReceive = DefaultWeightMsgReceive
42 | },
43 | )
44 |
45 | return simulation.WeightedOperations{
46 | simulation.NewWeightedOperation(
47 | weightMsgSend,
48 | SimulateMsgSend(ak, bk, k),
49 | ),
50 | // simulation.NewWeightedOperation(
51 | // weightMsgReceive,
52 | // SimulateMsgReceive(ak, bk, k),
53 | // ),
54 | }
55 | }
56 |
57 | func SimulateMsgSend(
58 | ak types.AccountKeeper,
59 | bk types.BankKeeper,
60 | k *keeper.Keeper,
61 | ) simtypes.Operation {
62 | return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
63 | ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
64 | msg := &types.MsgSend{}
65 |
66 | if len(accs) < 2 {
67 | return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "Send simulation: not enough accounts"), nil, nil
68 | }
69 |
70 | fromAccount, _ := simtypes.RandomAcc(r, accs)
71 | toAccount, _ := simtypes.RandomAcc(r, accs)
72 |
73 | password := "557cf1df72ade86102a1d8f8e83cec2eab834133c2f7e6a1d64f13603d69fece" // sha256("word1 word2 word3 word4 word5 word6")
74 | spendable := bk.SpendableCoins(ctx, fromAccount.Address)
75 | if len(spendable) == 0 {
76 | return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "Send simulation: not enough funds to simulate"), nil, nil
77 | }
78 |
79 | msg = types.NewMsgSend(
80 | fromAccount.Address.String(),
81 | toAccount.Address.String(),
82 | spendable[0],
83 | password,
84 | )
85 |
86 | txCtx := simulation.OperationInput{
87 | R: r,
88 | App: app,
89 | TxGen: simappparams.MakeTestEncodingConfig().TxConfig,
90 | Cdc: nil,
91 | Msg: msg,
92 | MsgType: msg.Type(),
93 | Context: ctx,
94 | SimAccount: fromAccount,
95 | AccountKeeper: ak,
96 | Bankkeeper: bk,
97 | ModuleName: types.ModuleName,
98 | CoinsSpentInMsg: sdk.NewCoins(spendable[0]),
99 | }
100 |
101 | return simulation.GenAndDeliverTxWithRandFees(txCtx)
102 | }
103 | }
104 |
105 | func SimulateMsgReceive(
106 | ak types.AccountKeeper,
107 | bk types.BankKeeper,
108 | k *keeper.Keeper,
109 | ) simtypes.Operation {
110 | return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
111 | ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
112 | simAccount, _ := simtypes.RandomAcc(r, accs)
113 | msg := &types.MsgReceive{}
114 |
115 | txCount := k.GetTransactionCount(ctx)
116 | if txCount == 0 {
117 | return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "Send simulation: no ibank txs to simulate"), nil, nil
118 | }
119 |
120 | txID := rand.Int63n(int64(txCount))
121 | password := "word1 word2 word3 word4 word5 word6"
122 |
123 | msg = types.NewMsgReceive(
124 | simAccount.Address.String(),
125 | txID,
126 | password,
127 | )
128 |
129 | txCtx := simulation.OperationInput{
130 | R: r,
131 | App: app,
132 | TxGen: simappparams.MakeTestEncodingConfig().TxConfig,
133 | Cdc: nil,
134 | Msg: msg,
135 | MsgType: msg.Type(),
136 | Context: ctx,
137 | SimAccount: simAccount,
138 | AccountKeeper: ak,
139 | Bankkeeper: bk,
140 | ModuleName: types.ModuleName,
141 | }
142 |
143 | return simulation.GenAndDeliverTxWithRandFees(txCtx)
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/x/ibank/simulation/params.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "math/rand"
5 |
6 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
7 | // "github.com/cosmos/cosmos-sdk/x/staking/types"
8 | )
9 |
10 | // ParamChanges defines the parameters that can be modified by param change proposals
11 | // on the simulation
12 | func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
13 | return []simtypes.ParamChange{}
14 | }
15 |
--------------------------------------------------------------------------------
/x/ibank/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/cosmos/cosmos-sdk/types/msgservice"
8 | )
9 |
10 | func RegisterCodec(cdc *codec.LegacyAmino) {
11 | cdc.RegisterConcrete(&MsgSend{}, "ibank/Send", nil)
12 | cdc.RegisterConcrete(&MsgReceive{}, "ibank/Receive", nil)
13 | // this line is used by starport scaffolding # 2
14 | }
15 |
16 | func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
17 | registry.RegisterImplementations((*sdk.Msg)(nil),
18 | &MsgSend{},
19 | )
20 | registry.RegisterImplementations((*sdk.Msg)(nil),
21 | &MsgReceive{},
22 | )
23 | // this line is used by starport scaffolding # 3
24 |
25 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
26 | }
27 |
28 | var (
29 | Amino = codec.NewLegacyAmino()
30 | ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry())
31 | )
32 |
--------------------------------------------------------------------------------
/x/ibank/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // DONTCOVER
4 |
5 | import (
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 | )
8 |
9 | // x/ibank module sentinel errors
10 | var (
11 | ErrNoTransaction = sdkerrors.Register(ModuleName, 2, "transaction not found")
12 | ErrAlreadyReceived = sdkerrors.Register(ModuleName, 3, "already received this fund")
13 | ErrTxExpired = sdkerrors.Register(ModuleName, 4, "transaction has expired")
14 | ErrTxDeclined = sdkerrors.Register(ModuleName, 5, "transaction is declined")
15 | ErrInvalidReceiver = sdkerrors.Register(ModuleName, 6, "invalid receiver")
16 | )
17 |
--------------------------------------------------------------------------------
/x/ibank/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | EventTypeIBank = "ibank"
5 | AttributeValueCategory = ModuleName
6 |
7 | AttributeKeyReceiveSuccess = "receive_success"
8 | AttributeKeyRefunded = "refund"
9 | AttributeKeySender = "sender"
10 | AttributeKeyRecipient = "recipient"
11 | AttributeKeyRemittanceID = "remittance_id"
12 | AttributeKeyAmount = "amount"
13 | AttributeKeyAction = "action"
14 | )
15 |
--------------------------------------------------------------------------------
/x/ibank/types/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | "github.com/cosmos/cosmos-sdk/x/auth/types"
6 | )
7 |
8 | // AccountKeeper defines the expected account keeper used for simulations (noalias)
9 | type AccountKeeper interface {
10 | GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
11 | GetModuleAddress(name string) sdk.AccAddress
12 | SetModuleAccount(ctx sdk.Context, macc types.ModuleAccountI)
13 | GetModuleAccount(ctx sdk.Context, moduleName string) types.ModuleAccountI
14 | NewAccount(ctx sdk.Context, acc types.AccountI) types.AccountI
15 | // Methods imported from account should be defined here
16 | }
17 |
18 | // BankKeeper defines the expected interface needed to retrieve account balances.
19 | type BankKeeper interface {
20 | SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
21 |
22 | MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
23 |
24 | SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
25 | SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
26 | // Methods imported from bank should be defined here
27 | }
28 |
--------------------------------------------------------------------------------
/x/ibank/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | // DefaultIndex is the default global index
8 | const DefaultIndex uint64 = 1
9 |
10 | // DefaultGenesis returns the default genesis state
11 | func DefaultGenesis() *GenesisState {
12 | return &GenesisState{
13 | Params: DefaultParams(),
14 | TransactionList: []Transaction{},
15 | TransactionCount: 0,
16 | TransactionChaser: 0,
17 | // this line is used by starport scaffolding # genesis/types/default
18 | }
19 | }
20 |
21 | func NewGenesisState(params Params) *GenesisState {
22 | return &GenesisState{
23 | Params: params,
24 | TransactionList: nil,
25 | TransactionCount: 0,
26 | TransactionChaser: 0,
27 | }
28 | }
29 |
30 | // Validate performs basic genesis state validation returning an error upon any
31 | // failure.
32 | func (gs GenesisState) Validate() error {
33 | // Check for duplicated ID in transaction
34 | transactionIDMap := make(map[uint64]bool)
35 | transactionCount := gs.GetTransactionCount()
36 | for _, elem := range gs.TransactionList {
37 | if _, ok := transactionIDMap[elem.Id]; ok {
38 | return fmt.Errorf("duplicated id for transaction")
39 | }
40 | if elem.Id >= transactionCount {
41 | return fmt.Errorf("transaction id should be lower or equal than the last id")
42 | }
43 | transactionIDMap[elem.Id] = true
44 | }
45 |
46 | if gs.Params.DurationOfExpiration <= 0 {
47 | return fmt.Errorf("duration of expiration should be positive; %d", gs.Params.DurationOfExpiration)
48 | }
49 | // this line is used by starport scaffolding # genesis/types/validate
50 |
51 | return gs.Params.Validate()
52 | }
53 |
--------------------------------------------------------------------------------
/x/ibank/types/genesis_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 |
6 | "mun/x/ibank/types"
7 |
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestGenesisState_Validate(t *testing.T) {
12 | for _, tc := range []struct {
13 | desc string
14 | genState *types.GenesisState
15 | valid bool
16 | }{
17 | {
18 | desc: "default is valid",
19 | genState: types.DefaultGenesis(),
20 | valid: true,
21 | },
22 | {
23 | desc: "valid genesis state",
24 | genState: &types.GenesisState{
25 | Params: types.DefaultParams(),
26 | TransactionList: []types.Transaction{
27 | {
28 | Id: 0,
29 | },
30 | {
31 | Id: 1,
32 | },
33 | },
34 | TransactionCount: 2,
35 | // this line is used by starport scaffolding # types/genesis/validField
36 | },
37 | valid: true,
38 | },
39 | {
40 | desc: "duplicated transaction",
41 | genState: &types.GenesisState{
42 | TransactionList: []types.Transaction{
43 | {
44 | Id: 0,
45 | },
46 | {
47 | Id: 0,
48 | },
49 | },
50 | },
51 | valid: false,
52 | },
53 | {
54 | desc: "invalid transaction count",
55 | genState: &types.GenesisState{
56 | TransactionList: []types.Transaction{
57 | {
58 | Id: 1,
59 | },
60 | },
61 | TransactionCount: 0,
62 | },
63 | valid: false,
64 | },
65 | // this line is used by starport scaffolding # types/genesis/testcase
66 | } {
67 | t.Run(tc.desc, func(t *testing.T) {
68 | err := tc.genState.Validate()
69 | if tc.valid {
70 | require.NoError(t, err)
71 | } else {
72 | require.Error(t, err)
73 | }
74 | })
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/x/ibank/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName defines the module name
5 | ModuleName = "ibank"
6 |
7 | // StoreKey defines the primary module store key
8 | StoreKey = ModuleName
9 |
10 | // RouterKey defines the module's message routing key
11 | RouterKey = ModuleName
12 |
13 | // MemStoreKey defines the in-memory store key
14 | MemStoreKey = "mem_ibank"
15 | )
16 |
17 | func KeyPrefix(p string) []byte {
18 | return []byte(p)
19 | }
20 |
21 | const (
22 | TransactionKey = "Transaction/value/"
23 | TransactionCountKey = "Transaction/count/"
24 | TransactionChaserKey = "Transaction/chaser/"
25 | )
26 |
--------------------------------------------------------------------------------
/x/ibank/types/message_receive.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | )
7 |
8 | const TypeMsgReceive = "receive"
9 |
10 | var _ sdk.Msg = &MsgReceive{}
11 |
12 | func NewMsgReceive(receiver string, transactionID int64, password string) *MsgReceive {
13 | return &MsgReceive{
14 | Receiver: receiver,
15 | TransactionId: transactionID,
16 | Password: password,
17 | }
18 | }
19 |
20 | func (msg *MsgReceive) Route() string {
21 | return RouterKey
22 | }
23 |
24 | func (msg *MsgReceive) Type() string {
25 | return TypeMsgReceive
26 | }
27 |
28 | func (msg *MsgReceive) GetSigners() []sdk.AccAddress {
29 | receiver, err := sdk.AccAddressFromBech32(msg.Receiver)
30 | if err != nil {
31 | panic(err)
32 | }
33 | return []sdk.AccAddress{receiver}
34 | }
35 |
36 | func (msg *MsgReceive) GetSignBytes() []byte {
37 | bz := ModuleCdc.MustMarshalJSON(msg)
38 | return sdk.MustSortJSON(bz)
39 | }
40 |
41 | func (msg *MsgReceive) ValidateBasic() error {
42 | _, err := sdk.AccAddressFromBech32(msg.Receiver)
43 | if err != nil {
44 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid receiver address (%s)", err)
45 | }
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/x/ibank/types/message_send.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | )
7 |
8 | const TypeMsgSend = "send"
9 |
10 | var _ sdk.Msg = &MsgSend{}
11 |
12 | func NewMsgSend(fromAddress string, toAddress string, amount sdk.Coin, password string) *MsgSend {
13 | return &MsgSend{
14 | FromAddress: fromAddress,
15 | ToAddress: toAddress,
16 | Amount: amount,
17 | PasswordHash: password,
18 | }
19 | }
20 |
21 | func (msg *MsgSend) Route() string {
22 | return RouterKey
23 | }
24 |
25 | func (msg *MsgSend) Type() string {
26 | return TypeMsgSend
27 | }
28 |
29 | func (msg *MsgSend) GetSigners() []sdk.AccAddress {
30 | fromAddress, err := sdk.AccAddressFromBech32(msg.FromAddress)
31 | if err != nil {
32 | panic(err)
33 | }
34 | return []sdk.AccAddress{fromAddress}
35 | }
36 |
37 | func (msg *MsgSend) GetSignBytes() []byte {
38 | bz := ModuleCdc.MustMarshalJSON(msg)
39 | return sdk.MustSortJSON(bz)
40 | }
41 |
42 | func (msg *MsgSend) ValidateBasic() error {
43 | _, err := sdk.AccAddressFromBech32(msg.FromAddress)
44 | if err != nil {
45 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid fromAddress address (%s)", err)
46 | }
47 | return nil
48 | }
49 |
--------------------------------------------------------------------------------
/x/ibank/types/params.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "time"
6 |
7 | paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
8 | "gopkg.in/yaml.v2"
9 | )
10 |
11 | const (
12 | DefaultDurationOfExpiration = "48h"
13 | )
14 |
15 | // Parameter store keys
16 | var (
17 | KeyDurationOfExpiration = []byte("DurationOfExpiration")
18 | )
19 |
20 | var _ paramtypes.ParamSet = (*Params)(nil)
21 |
22 | // ParamKeyTable the param key table for launch module
23 | func ParamKeyTable() paramtypes.KeyTable {
24 | return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
25 | }
26 |
27 | // NewParams creates a new Params instance
28 | func NewParams(duration time.Duration) Params {
29 | return Params{
30 | DurationOfExpiration: duration,
31 | }
32 | }
33 |
34 | // DefaultParams returns a default set of parameters
35 | func DefaultParams() Params {
36 | dur, _ := time.ParseDuration(DefaultDurationOfExpiration)
37 | return NewParams(dur)
38 | }
39 |
40 | // ParamSetPairs get the params.ParamSet
41 | func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
42 | return paramtypes.ParamSetPairs{
43 | paramtypes.NewParamSetPair(KeyDurationOfExpiration, &p.DurationOfExpiration, validateDuration),
44 | }
45 | }
46 |
47 | // Validate validates the set of params
48 | func (p Params) Validate() error {
49 | return nil
50 | }
51 |
52 | // String implements the Stringer interface.
53 | func (p Params) String() string {
54 | out, _ := yaml.Marshal(p)
55 | return string(out)
56 | }
57 |
58 | func validateDuration(i interface{}) error {
59 | d, ok := i.(time.Duration)
60 | if !ok {
61 | return fmt.Errorf("invalid parameter type: %T", i)
62 | }
63 | if d < 1 {
64 | return fmt.Errorf("duration must be greater than 1: %d", d)
65 | }
66 | return nil
67 | }
68 |
--------------------------------------------------------------------------------
/x/ibank/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | TxPending TxnStatus = 0
5 | TxSent TxnStatus = 1
6 | TxExpired TxnStatus = 2
7 | TxDeclined TxnStatus = 3
8 | )
9 |
--------------------------------------------------------------------------------