├── .gitignore
├── HardForkContestInstruction.md
├── LICENSE
├── Mainnet-upgrade-instruction
└── MainnetUpgradeInstructions.md
├── Makefile
├── Makefile.ledger
├── NetworkRehearsalInstructions
└── NetworkRehearsalInstructions.md
├── README.md
├── SUMMARY.md
├── app
├── accountFetcher
│ ├── AccountFetcher.go
│ └── types
│ │ └── types.go
├── ante
│ ├── MempoolFeeDecorator.go
│ ├── NewSetUpContextDecorator.go
│ ├── NftChecksAnteHandler.go
│ ├── TaxDecorator.go
│ ├── ante.go
│ └── gasmeter
│ │ ├── ChargingGasMeter.go
│ │ ├── ChargingGasMeterInterface.go
│ │ ├── FreeGasMeter.go
│ │ └── GasMeterKeeper.go
├── app.go
└── test_common.go
├── cmd
├── blzcli
│ └── main.go
└── blzd
│ ├── genaccounts.go
│ └── main.go
├── curium.iml
├── docs
├── commands
│ ├── qAndTX.md
│ └── useful.md
├── nft
│ ├── Bluzelle NFT Secure Storage API.md
│ ├── auth-protocol.dia
│ ├── auth-protocol.png
│ ├── short protocol.dia
│ └── short protocol.png
├── oracle
│ ├── Diagram1.dia
│ └── Diagram1.dia~
├── public
│ └── buildvalidatorsentry.md
├── rest
│ └── buildrest.md
└── setup
│ ├── build.md
│ ├── deploy.md
│ ├── deployaddl.md
│ ├── devenv.md
│ └── os.md
├── go.mod
├── go.sum
├── home
├── .torrent.db
├── .torrent.db-shm
├── .torrent.db-wal
├── 4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0
└── nft
│ ├── .torrent.db
│ ├── .torrent.db-shm
│ ├── .torrent.db-wal
│ └── 4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0
├── localsetup.sh
├── package.json
├── public-validator-+-sentry
└── buildvalidatorsentry.md
├── rest-service
└── buildrest.md
├── scripts
├── deploy.ts
├── package.json
├── setup.ts
├── tsconfig.json
└── yarn.lock
├── test
├── integration
│ ├── .gitignore
│ ├── helpers
│ │ ├── bluzelle-client.ts
│ │ ├── blzcli.ts
│ │ └── nft-helpers.ts
│ ├── package.json
│ ├── specs
│ │ ├── ante.spec.ts
│ │ ├── nft
│ │ │ ├── MsgCreateNft.spec.ts
│ │ │ ├── MsgPublishFile.spec.ts
│ │ │ ├── nft-upload.spec.ts
│ │ │ └── store-nft.spec.ts
│ │ └── oracle
│ │ │ ├── oracle-utils.ts
│ │ │ ├── rest
│ │ │ ├── add-source.spec.ts
│ │ │ └── search-votes.spec.ts
│ │ │ ├── shouldBeFreeHelper.ts
│ │ │ └── sources.ts
│ ├── tsconfig.json
│ ├── yarn-error.log
│ └── yarn.lock
├── load
│ ├── package.json
│ ├── src
│ │ └── load.ts
│ ├── tsconfig.json
│ └── yarn.lock
└── oracle-mock
│ ├── node_modules
│ ├── .yarn-integrity
│ └── monet
│ │ ├── CHANGELOG.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── dist
│ │ ├── monet-pimp.js
│ │ ├── monet-pimp.min.js
│ │ ├── monet-pimp.min.js.map
│ │ ├── monet.d.ts
│ │ ├── monet.js
│ │ ├── monet.min.js
│ │ └── monet.min.js.map
│ │ ├── package.json
│ │ └── prepublish-test
│ │ ├── browser-global.js
│ │ ├── node-global.js
│ │ └── node-regular.js
│ ├── oracle-mock.ts
│ ├── package.json
│ └── yarn.lock
├── types
├── development.go
└── types.go
├── x
├── aggregator
│ ├── abci.go
│ ├── alias.go
│ ├── client
│ │ ├── cli
│ │ │ ├── query.go
│ │ │ └── tx.go
│ │ └── rest
│ │ │ ├── query.go
│ │ │ ├── rest.go
│ │ │ └── tx.go
│ ├── genesis.go
│ ├── handler.go
│ ├── keeper
│ │ ├── Averager.go
│ │ ├── Averager_test.go
│ │ ├── keeper.go
│ │ ├── keeper_test.go
│ │ ├── params.go
│ │ └── querier.go
│ ├── module.go
│ ├── spec
│ │ └── README.md
│ └── types
│ │ ├── codec.go
│ │ ├── errors.go
│ │ ├── events.go
│ │ ├── expected_keepers.go
│ │ ├── genesis.go
│ │ ├── keeper.go
│ │ ├── key.go
│ │ ├── key_test.go
│ │ ├── msg.go
│ │ ├── params.go
│ │ └── querier.go
├── crud
│ ├── alias.go
│ ├── client
│ │ ├── cli
│ │ │ ├── query.go
│ │ │ └── tx.go
│ │ └── rest
│ │ │ ├── query.go
│ │ │ ├── rest.go
│ │ │ └── tx.go
│ ├── gas_calculator.go
│ ├── gas_calculator_test.go
│ ├── genesis.go
│ ├── genesis_test.go
│ ├── handler.go
│ ├── handler_test.go
│ ├── internal
│ │ ├── keeper
│ │ │ ├── keeper.go
│ │ │ ├── keeper_test.go
│ │ │ ├── querier.go
│ │ │ └── querier_test.go
│ │ └── types
│ │ │ ├── codec.go
│ │ │ ├── key.go
│ │ │ ├── msgs.go
│ │ │ ├── msgs_test.go
│ │ │ ├── querier.go
│ │ │ ├── querier_test.go
│ │ │ ├── types.go
│ │ │ └── types_test.go
│ ├── mocks
│ │ ├── mock_gas.go
│ │ └── mock_keeper.go
│ ├── module.go
│ └── module_test.go
├── curium
│ ├── alias.go
│ ├── client
│ │ ├── cli
│ │ │ ├── query.go
│ │ │ └── tx.go
│ │ └── rest
│ │ │ ├── query.go
│ │ │ ├── rest.go
│ │ │ └── tx.go
│ ├── genesis.go
│ ├── handler.go
│ ├── keeper
│ │ ├── AccountInfo.go
│ │ ├── AccountInfo_test.go
│ │ ├── GenesisReader.go
│ │ ├── MsgBroadcastQueue.go
│ │ ├── MsgBroadcastQueue_test.go
│ │ ├── keeper.go
│ │ └── querier.go
│ ├── module.go
│ └── types
│ │ ├── codec.go
│ │ ├── genesis.go
│ │ ├── keys.go
│ │ └── types.go
├── nft
│ ├── alias.go
│ ├── client
│ │ ├── cli
│ │ │ ├── query.go
│ │ │ └── tx.go
│ │ └── rest
│ │ │ ├── getNftByVendorHandler.go
│ │ │ ├── getNftHandler.go
│ │ │ ├── query.go
│ │ │ ├── rest.go
│ │ │ ├── tx.go
│ │ │ └── uploadNftHandler.go
│ ├── demo
│ │ ├── demo.ts
│ │ ├── image.jpg
│ │ ├── package.json
│ │ └── yarn.lock
│ ├── genesis.go
│ ├── handler.go
│ ├── keeper
│ │ ├── TorrentClient.go
│ │ ├── createNft.go
│ │ ├── keeper.go
│ │ ├── nft.go
│ │ └── querier.go
│ ├── module.go
│ └── types
│ │ ├── codec.go
│ │ ├── genesis.go
│ │ ├── keys.go
│ │ ├── msgCreateNft.go
│ │ ├── msgPublishFile.go
│ │ ├── msgRegisterPeer.go
│ │ ├── nft.go
│ │ ├── peer.go
│ │ ├── querier.go
│ │ ├── uploadTokenManager.go
│ │ └── uploadTokenManager_test.go
├── oracle
│ ├── abci.go
│ ├── alias.go
│ ├── client
│ │ ├── cli
│ │ │ ├── query.go
│ │ │ └── tx.go
│ │ └── rest
│ │ │ ├── query.go
│ │ │ ├── rest.go
│ │ │ └── tx.go
│ ├── docs
│ │ └── arch.md
│ ├── feeder.go
│ ├── genesis.go
│ ├── handler.go
│ ├── keeper
│ │ ├── keeper.go
│ │ ├── keeper_global_config.go
│ │ ├── keeper_proof.go
│ │ ├── keeper_source.go
│ │ ├── keeper_test.go
│ │ ├── keeper_value.go
│ │ ├── keeper_vote.go
│ │ ├── params.go
│ │ └── querier.go
│ ├── module.go
│ ├── spec
│ │ └── README.md
│ └── types
│ │ ├── codec.go
│ │ ├── errors.go
│ │ ├── events.go
│ │ ├── expected_keepers.go
│ │ ├── genesis.go
│ │ ├── keeper.go
│ │ ├── key.go
│ │ ├── msg.go
│ │ ├── params.go
│ │ ├── querier.go
│ │ └── types.go
└── tax
│ ├── README.md
│ ├── alias.go
│ ├── client
│ ├── cli
│ │ ├── query.go
│ │ └── tx.go
│ └── rest
│ │ ├── query.go
│ │ ├── rest.go
│ │ └── tx.go
│ ├── genesis.go
│ ├── genesis_test.go
│ ├── handler.go
│ ├── handler_test.go
│ ├── internal
│ ├── keeper
│ │ ├── keeper.go
│ │ ├── keeper_test.go
│ │ ├── querier.go
│ │ └── querier_test.go
│ └── types
│ │ ├── codec.go
│ │ ├── key.go
│ │ ├── msg_collector.go
│ │ ├── msg_collector_test.go
│ │ ├── msg_percentage.go
│ │ ├── types.go
│ │ └── types_test.go
│ ├── module.go
│ └── module_test.go
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 |
15 | # Goland project files
16 | .idea/
17 | blzcli
18 | blzd
19 |
20 | # Garbage OS files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/Mainnet-upgrade-instruction/MainnetUpgradeInstructions.md:
--------------------------------------------------------------------------------
1 | # Mainnet Upgrade Instructions: from `Bluzelle Soft MainNet` to `Bluzelle Production Mainnet`
2 |
3 | Dear validators, you can now join the Bluzelle Production Mainnet by following [this guide](../public-validator-+-sentry/buildvalidatorsentry.md)
4 |
5 | **Please follow the instructions for the FORK path**. You will effectively be building new Mainnet nodes, but they will inherit the exact same state, accounts, etc as the existing Soft MainNet, as per a snapshot taken at a specific block height. Your new validator will in fact use the exact same consensus private key to sign blocks, as the old validator on the Soft MainNet. The new Mainnet will start all over again from block 0, but its starting state will be the state inherited from the snapshot taken from the Soft MainNet.
6 |
7 | :warning: Please complete the process as soon as possible. Please read carefully before you begin the fork from the Bluzelle Soft Mainnet.
8 |
9 | :warning: Just in case a revert could happen, please DO NOT delete your `Soft MainNet` validator and sentry machine(s) before you are instructed to do so. We expect the `Soft Mainnet` to be taken down on 4th February (tentatively). If for some reason we need to revert, your Soft MainNet validator WILL BE EXPECTED TO BE UP. If it is not up, you CAN BE SLASHED.
10 |
11 | :warning: As part of the process of forking the old network over to the new one, we **PRE-JAIL** all validators. This means that your validator, while already existing in the new network, is in a jailed state. You have NOT been slashed. The validator is effectively "frozen", safe from being slashed as it is not yet running. However, you should still join soon because unbonding has started. If you wait too long, you will risk losing all your delegations.
12 |
13 | :warning: If your Production Mainnet machines have a previous installation on them, you will need to remove those, before you continue. Please do all necessary cleanup on them to remove existing installation files, binaries, etc. It is recommended to conduct the rehearsal on a fresh machine, if possible.
14 |
15 | Please watch out for any communications on our [Discord server](https://discord.gg/KRhcKE6qS6).
16 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | PACKAGES=$(shell go list ./... | grep -v '/simulation')
2 |
3 | VERSION := $(shell echo $(shell git describe --tags --dirty) | sed 's/^v//')
4 | COMMIT := $(shell git log -1 --format='%H')
5 | COSMOS_SDK := $(shell grep -i cosmos-sdk go.mod | awk '{print $$2}')
6 |
7 | include Makefile.ledger
8 |
9 | build_tags += $(BUILD_TAGS)
10 | build_tags := $(strip $(build_tags))
11 |
12 | whitespace :=
13 | whitespace += $(whitespace)
14 | comma := ,
15 | build_tags_comma_sep := $(patsubst $(whitespace),$(comma),$(build_tags))
16 | coverage := $(shell mktemp -u).coverage.out
17 |
18 | # process linker flags
19 | LDFLAGS = -X github.com/cosmos/cosmos-sdk/version.Name=BluzelleService \
20 | -X github.com/cosmos/cosmos-sdk/version.ServerName=blzd \
21 | -X github.com/cosmos/cosmos-sdk/version.ClientName=blzcli \
22 | -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
23 | -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT)
24 |
25 | LDFLAGS_FAUCET = -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep),faucet,cosmos-sdk $(COSMOS_SDK)"
26 | LDFLAGS_NO_FAUCET = -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep),cosmos-sdk $(COSMOS_SDK)"
27 |
28 | BUILD_FLAGS := -tags "$(build_tags)"
29 | FAUCET_BUILD_FLAGS := -tags "$(build_tags),faucet"
30 |
31 | all:
32 | go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_NO_FAUCET)' ./cmd/blzd
33 | go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_NO_FAUCET)' ./cmd/blzcli
34 |
35 | clean:
36 | @rm -f blzd blzcli
37 |
38 | mainnet: go.sum
39 | go install -mod=readonly $(BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_NO_FAUCET)' ./cmd/blzd
40 | go install -mod=readonly $(BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_NO_FAUCET)' ./cmd/blzcli
41 |
42 | testnet:
43 | # only testnet has the faucet enabled...
44 | go install -mod=readonly $(FAUCET_BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_FAUCET)' ./cmd/blzd
45 | go install -mod=readonly $(FAUCET_BUILD_FLAGS) -ldflags '$(LDFLAGS) $(LDFLAGS_FAUCET)' ./cmd/blzcli
46 |
47 | go.sum: go.mod
48 | @echo "--> Ensure dependencies have not been modified"
49 | GO111MODULE=on go mod verify
50 |
51 | test:
52 | @go test -mod=readonly $(PACKAGES)
53 |
54 | test-tax:
55 | @go test -mod=readonly ./x/tax/...
56 |
57 | coverage:
58 | @go test -v -coverprofile=$(coverage) ./x/...
59 | @go tool cover -html=$(coverage)
60 | @rm $(coverage)
61 |
--------------------------------------------------------------------------------
/Makefile.ledger:
--------------------------------------------------------------------------------
1 | LEDGER_ENABLED ?= true
2 |
3 | build_tags =
4 | ifeq ($(LEDGER_ENABLED),true)
5 | ifeq ($(OS),Windows_NT)
6 | GCCEXE = $(shell where gcc.exe 2> NUL)
7 | ifeq ($(GCCEXE),)
8 | $(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false)
9 | else
10 | build_tags += ledger
11 | endif
12 | else
13 | UNAME_S = $(shell uname -s)
14 | ifeq ($(UNAME_S),OpenBSD)
15 | $(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988))
16 | else
17 | GCC = $(shell command -v gcc 2> /dev/null)
18 | ifeq ($(GCC),)
19 | $(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false)
20 | else
21 | build_tags += ledger
22 | endif
23 | endif
24 | endif
25 | endif
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CURIUM Overview
2 |
3 | [](https://travis-ci.com/bluzelle/curium) [](https://coveralls.io/github/bluzelle/curium?branch=devel)
4 |
5 | ## The Bluzelle Curium Application
6 |
7 | The decentralized database for Web 3.0. Bluzelle uses blockchain and edge computing for greater performance and security.
8 |
9 | ### Bluzelle Curium REST Service
10 |
11 | If all you need is the Light-client Daemon \(LCD\) REST server: [Building the Curium REST Service](rest-service/buildrest.md)
12 |
13 | ### Bluzelle Curium Public Validator + Sentry Installation
14 |
15 | If you want to setup your own validator + sentry \(optional\) on our network: [Building a Public TestNet Validator + Sentry](public-validator-+-sentry/buildvalidatorsentry.md)
16 |
17 | ### Bluzelle Curium Private Multi-Validator Zone Installation
18 |
19 | These are steps involved in setting up the OS, Dev Environment, building and deploying a multi-node Curium Zone.
20 |
21 | 1. [OS Setup for Curium](setup/os.md)
22 | 2. [Development Environment Setup](setup/devenv.md)
23 | 3. [Build the Curium Project](setup/build.md)
24 | 4. [Deploy the Initial Node](setup/deploy.md)
25 | 5. [Deploy Additional Nodes](setup/deployaddl.md)
26 |
27 | ### Using a Bluzelle Curium Multi-Validator Zone
28 |
29 | * [Queries and Transactions](docs/commands/qAndTX.md)
30 | * [Useful Operations](docs/commands/useful.md)
31 |
32 |
33 | HELLO WORLD 2
34 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | * [CURIUM Overview](README.md)
4 |
5 | ## Setup
6 |
7 | * [OS Setup for Curium](setup/os.md)
8 | * [Development Environment Setup](setup/devenv.md)
9 | * [Build the Curium Project](setup/build.md)
10 | * [Deploy the Initial Node](setup/deploy.md)
11 | * [Deploy Additional Nodes](setup/deployaddl.md)
12 |
13 | ## Public Validator + Sentry
14 |
15 | * [Building a Public Testnet Validator + Sentry](public-validator-+-sentry/buildvalidatorsentry.md)
16 |
17 | ## REST Service
18 |
19 | * [Building the CURIUM REST Service](rest-service/buildrest.md)
20 |
21 |
--------------------------------------------------------------------------------
/app/accountFetcher/AccountFetcher.go:
--------------------------------------------------------------------------------
1 | package accountFetcher
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/bluzelle/curium/app/accountFetcher/types"
6 | "github.com/bluzelle/curium/x/curium"
7 | "github.com/cosmos/cosmos-sdk/codec"
8 | "github.com/cosmos/cosmos-sdk/x/auth"
9 | abci "github.com/tendermint/tendermint/abci/types"
10 | )
11 |
12 | type BaseAppWithQuery interface {
13 | Query(req abci.RequestQuery) abci.ResponseQuery
14 |
15 | }
16 |
17 | func AccountFetcher(app BaseAppWithQuery, cdc *codec.Codec, cliHome string) types.AccountFetcherFn {
18 | krReader := curium.NewKeyringReader(cliHome)
19 | return func(name string) (types.AcctInfo, error){
20 | addr, err := krReader.GetAddress(name)
21 |
22 | if err != nil {
23 | return types.AcctInfo{}, err
24 | }
25 |
26 | d, _ := json.Marshal(map[string]string{
27 | "Address": addr.String(),
28 | })
29 | x := app.Query(abci.RequestQuery{
30 | Data: d,
31 | Path: "custom/acc/account",
32 | })
33 |
34 | var resp auth.BaseAccount
35 | cdc.MustUnmarshalJSON(x.Value, &resp)
36 |
37 |
38 |
39 | return types.AcctInfo{
40 | Name: name,
41 | Address: addr.String(),
42 | AccNum: resp.GetAccountNumber(),
43 | Seq: resp.GetSequence(),
44 | }, nil
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/accountFetcher/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type AccountFetcherFn func(name string) (AcctInfo, error)
4 |
5 | type AcctInfo struct {
6 | Name string
7 | Address string
8 | AccNum uint64
9 | Seq uint64
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/app/ante/MempoolFeeDecorator.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
6 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
7 | )
8 |
9 | type MempoolFeeDecorator struct{}
10 |
11 | func NewMempoolFeeDecorator() MempoolFeeDecorator {
12 | return MempoolFeeDecorator{}
13 | }
14 |
15 | func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
16 | feeTx, ok := tx.(ante.FeeTx)
17 | if !ok {
18 | return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
19 | }
20 |
21 | feeCoins := feeTx.GetFee()
22 | gas := feeTx.GetGas()
23 |
24 | // Ensure that the provided fees meet a minimum threshold for the validator,
25 | // if this is a CheckTx. This is only for local mempool purposes, and thus
26 | // is only ran on check tx.
27 | if ctx.IsCheckTx() && !simulate {
28 | specifiedGasPrice := sdk.NewDecCoinsFromCoins(feeCoins[0]).QuoDec(sdk.NewDec(int64(gas)))[0]
29 | minGasPrice := ctx.MinGasPrices()[0]
30 |
31 | if specifiedGasPrice.IsLT(minGasPrice) {
32 | return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "gas price too low; got: %s required: %s", specifiedGasPrice, minGasPrice)
33 | }
34 |
35 | if gas == 0 {
36 | return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "max gas cannot be 0")
37 | }
38 |
39 | }
40 |
41 | return next(ctx, tx, simulate)
42 | }
43 |
--------------------------------------------------------------------------------
/app/ante/NftChecksAnteHandler.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | nft "github.com/bluzelle/curium/x/nft/keeper"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 | )
8 |
9 | type NftChecksAnteHandler struct{
10 | NftKeeper nft.Keeper
11 | }
12 |
13 | func NewNftChecksAnteHandler(nftKeeper nft.Keeper) NftChecksAnteHandler {
14 | return NftChecksAnteHandler{
15 | NftKeeper: nftKeeper,
16 | }
17 | }
18 |
19 | func (mfd NftChecksAnteHandler) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
20 | signer := tx.GetMsgs()[0].GetSigners()[0]
21 | msgType := tx.GetMsgs()[0].Type()
22 |
23 | if msgType != "CreateNft" || mfd.NftKeeper.IsAuthorized(ctx, signer) {
24 | return next(ctx, tx, simulate)
25 | }
26 | return sdk.Context{}, sdkerrors.New("nft", 2, signer.String() + " is not on nft whitelist")
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/app/ante/TaxDecorator.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/tax"
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/keeper"
8 | bank "github.com/cosmos/cosmos-sdk/x/bank"
9 | "github.com/cosmos/cosmos-sdk/x/gov/types"
10 | )
11 |
12 |
13 |
14 |
15 | type TaxDecorator struct {
16 | ak keeper.AccountKeeper
17 | bk bank.Keeper
18 | tk tax.Keeper
19 | supplyKeeper types.SupplyKeeper
20 | }
21 |
22 | func NewTaxDecorator(ak keeper.AccountKeeper, sk types.SupplyKeeper, tk tax.Keeper, bk bank.Keeper) TaxDecorator {
23 | return TaxDecorator{
24 | ak: ak,
25 | supplyKeeper: sk,
26 | tk: tk,
27 | bk: bk,
28 | }
29 | }
30 |
31 | // FeeTx defines the interface to be implemented by Tx to use the FeeDecorators
32 | type FeeTx interface {
33 | sdk.Tx
34 | GetGas() uint64
35 | GetFee() sdk.Coins
36 | FeePayer() sdk.AccAddress
37 | }
38 |
39 | func (td TaxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
40 |
41 | if !simulate {
42 |
43 | feeTx, ok := tx.(FeeTx)
44 | if !ok {
45 | return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
46 | }
47 |
48 | feePayer := feeTx.FeePayer()
49 | feePayerAcc := td.ak.GetAccount(ctx, feePayer)
50 |
51 | if feePayerAcc == nil {
52 | return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", feePayer)
53 | }
54 |
55 | if err := collectTransactionTax(ctx, td, tx, feeTx.GetFee(), feePayer); err != nil {
56 | return ctx, err
57 | }
58 |
59 | }
60 | return next(ctx, tx, simulate)
61 | }
62 |
63 |
64 | func collectTransactionTax(ctx sdk.Context, dfd TaxDecorator, tx sdk.Tx, fees sdk.Coins, feePayer sdk.AccAddress) error {
65 |
66 | // deduct the fees
67 | if !fees.IsZero() {
68 | taxInfo := dfd.tk.GetTaxInfo(ctx)
69 |
70 | // handle bank send tx fee
71 | msgs := tx.GetMsgs()
72 | for _, msg := range msgs {
73 | if msg.Type() == "send" {
74 | bankmsg := msg.(bank.MsgSend)
75 | trfFees := sdk.Coins{}
76 | for _, coin := range bankmsg.Amount {
77 | feeAmt := coin.Amount.Int64() * taxInfo.TransferBp / 10000
78 | if feeAmt > 0 {
79 | trfFee := sdk.NewInt64Coin(coin.Denom, feeAmt)
80 | trfFees = append(trfFees, trfFee)
81 | }
82 | }
83 |
84 | if len(trfFees) > 0 {
85 | if err := dfd.bk.SendCoins(ctx, feePayer, taxInfo.Collector, trfFees); err != nil {
86 | return err
87 | }
88 | }
89 | }
90 | }
91 |
92 | }
93 | return nil
94 |
95 | }
96 |
97 |
98 |
--------------------------------------------------------------------------------
/app/ante/ante.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | "github.com/bluzelle/curium/app/ante/gasmeter"
5 | "github.com/bluzelle/curium/x/crud"
6 | nft "github.com/bluzelle/curium/x/nft/keeper"
7 | "github.com/bluzelle/curium/x/tax"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
10 | "github.com/cosmos/cosmos-sdk/x/auth/keeper"
11 | "github.com/cosmos/cosmos-sdk/x/bank"
12 | "github.com/cosmos/cosmos-sdk/x/gov/types"
13 | )
14 |
15 | func NewAnteHandler(
16 | accountKeeper keeper.AccountKeeper,
17 | supplyKeeper types.SupplyKeeper,
18 | taxKeeper tax.Keeper,
19 | bankKeeper bank.Keeper,
20 | crudKeeper crud.Keeper,
21 | nftKeeper *nft.Keeper,
22 | sigGasConsumer ante.SignatureVerificationGasConsumer,
23 | gasMeterKeeper *gasmeter.GasMeterKeeper,
24 | minGasPriceCoins sdk.DecCoins,
25 | ) sdk.AnteHandler {
26 | return sdk.ChainAnteDecorators(
27 | NewSetUpContextDecorator(gasMeterKeeper, supplyKeeper, accountKeeper, crudKeeper, minGasPriceCoins), // outermost AnteDecorator. SetUpContext must be called first
28 | NewMempoolFeeDecorator(),
29 | ante.NewValidateBasicDecorator(),
30 | ante.NewValidateMemoDecorator(accountKeeper),
31 | ante.NewConsumeGasForTxSizeDecorator(accountKeeper),
32 | ante.NewSetPubKeyDecorator(accountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
33 | ante.NewValidateSigCountDecorator(accountKeeper),
34 | ante.NewSigGasConsumeDecorator(accountKeeper, sigGasConsumer),
35 | ante.NewSigVerificationDecorator(accountKeeper),
36 | NewTaxDecorator(
37 | accountKeeper,
38 | supplyKeeper,
39 | taxKeeper,
40 | bankKeeper,
41 | ),
42 | ante.NewIncrementSequenceDecorator(accountKeeper), // innermost AnteDecorator
43 | NewNftChecksAnteHandler(*nftKeeper),
44 | )
45 | }
--------------------------------------------------------------------------------
/app/ante/gasmeter/ChargingGasMeterInterface.go:
--------------------------------------------------------------------------------
1 | package gasmeter
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | type ChargingGasMeterInterface interface {
6 | Charge(ctx sdk.Context) error
7 | GetGasPrice() sdk.DecCoins
8 | }
--------------------------------------------------------------------------------
/app/ante/gasmeter/FreeGasMeter.go:
--------------------------------------------------------------------------------
1 | package gasmeter
2 |
3 | import (
4 | "fmt"
5 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "math"
8 | )
9 |
10 | type freeGasMeter struct {
11 | limit storetypes.Gas
12 | consumed storetypes.Gas
13 | }
14 |
15 | func NewFreeGasMeter(limit storetypes.Gas) storetypes.GasMeter {
16 | return &freeGasMeter{
17 | limit: limit,
18 | consumed: 0,
19 | }
20 | }
21 |
22 | func (g *freeGasMeter) GasConsumed() storetypes.Gas {
23 | return 0
24 | }
25 |
26 | func (g *freeGasMeter) Limit() storetypes.Gas {
27 | return g.limit
28 | }
29 |
30 | func (g *freeGasMeter) GasConsumedToLimit() storetypes.Gas {
31 | if g.IsPastLimit() {
32 | return 0
33 | }
34 | return 0
35 | }
36 |
37 | // addUint64Overflow performs the addition operation on two uint64 integers and
38 | // returns a boolean on whether or not the result overflows.
39 | func addUint64Overflow(a, b uint64) (uint64, bool) {
40 | if math.MaxUint64-a < b {
41 | return 0, true
42 | }
43 |
44 | return a + b, false
45 | }
46 |
47 | func (g *freeGasMeter) ConsumeGas(amount storetypes.Gas, descriptor string) {
48 | var overflow bool
49 | // TODO: Should we set the consumed field after overflow checking?
50 | g.consumed, overflow = addUint64Overflow(g.consumed, amount)
51 | if overflow && g.limit != 0 {
52 | panic(storetypes.ErrorGasOverflow{descriptor})
53 | }
54 |
55 | if g.consumed > g.limit && g.limit != 0 {
56 | panic(storetypes.ErrorOutOfGas{descriptor})
57 | }
58 |
59 | }
60 |
61 | func (g *freeGasMeter) IsPastLimit() bool {
62 | return g.consumed > g.limit && g.limit != 0
63 | }
64 |
65 | func (g *freeGasMeter) IsOutOfGas() bool {
66 | return g.consumed >= g.limit
67 | }
68 |
69 | func (g *freeGasMeter) String() string {
70 | return fmt.Sprintf("FreeGasMeter:\n limit: %d\n consumed: %d", g.limit, g.consumed)
71 | }
72 |
73 | func (g *freeGasMeter) Charge (ctx sdk.Context) error {return nil}
74 |
75 | func (g *freeGasMeter) GetGasPrice() sdk.DecCoins {
76 | return sdk.NewDecCoins()
77 | }
--------------------------------------------------------------------------------
/app/ante/gasmeter/GasMeterKeeper.go:
--------------------------------------------------------------------------------
1 | package gasmeter
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | )
6 |
7 | type GasMeterKeeper struct {
8 | gasMeters []*sdk.GasMeter
9 | }
10 |
11 | func NewGasMeterKeeper () *GasMeterKeeper {
12 | return &GasMeterKeeper{
13 | gasMeters: make([]*sdk.GasMeter, 0),
14 | }
15 | }
16 |
17 | func (gk *GasMeterKeeper) ChargeAll (ctx sdk.Context) []error {
18 | errors := make([]error, 0)
19 | for _,gasMeter := range gk.gasMeters {
20 | gm := *gasMeter
21 | chargingGm := gm.(ChargingGasMeterInterface)
22 | err := chargingGm.Charge(ctx)
23 | if err != nil {
24 | errors = append(errors, err)
25 | }
26 | }
27 | return errors
28 | }
29 |
30 | func (gk *GasMeterKeeper) GetAllGasMeters () []*sdk.GasMeter {
31 | return gk.gasMeters
32 | }
33 |
34 | func (gk *GasMeterKeeper) AddGasMeter (gasMeter *sdk.GasMeter) {
35 | gk.gasMeters = append(gk.gasMeters, gasMeter)
36 | }
37 |
38 | func (gk *GasMeterKeeper) ClearAll () {
39 | gk.gasMeters = make([]*sdk.GasMeter, 0)
40 | }
41 |
--------------------------------------------------------------------------------
/curium.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/nft/Bluzelle NFT Secure Storage API.md:
--------------------------------------------------------------------------------
1 | # Bluzelle NFT Secure Storage API
2 |
3 | The bluzelle NFT API is a two step process.
4 |
5 | * Upload the file (from the browser)
6 | * Notify the network that the file has been uploaded (from your application server)
7 |
8 | The second step is necessary so that your identity credentials can be kept secure while not requiring you to act as the middle man for the upload. The file upload happens directly between the users browser and the Bluzelle Net.
9 |
10 | The process looks like this:
11 |
12 | 
13 |
14 | ### Step 1: Upload
15 |
16 | We have provided a helper function in our Bluzelle JS client library to aid with the upload. You can use this code in your browser application.
17 |
18 | ````typescript
19 | import {uploadNft} from 'bluzelle'
20 | uploadNft("https:...", data as Uint8Array, "your_org_id"))
21 | ````
22 |
23 |
24 |
25 | **The url and org_id will be provided to you by Bluzelle.**
26 |
27 | ### Step 2: Notify the network
28 |
29 | In order for the network to start replicating the uploaded file, it must be notified that the file has been uploaded. We have created another helper function to aid you.
30 |
31 | ```typescript
32 | bz.createNft(
33 | id, // The id you want to assign to this file
34 | hash, // The hash of the file
35 | vendor, // Your organization id
36 | userId, // Your id for the user that uploaded the file
37 | mime, // The mime type for this file
38 | 'metadata', // Any arbritrary metadata you want to store for this file
39 | gasParams) // The gas parameters for the transaction (these will be provided to you)
40 | ```
41 |
42 | ### Creating a bluzelle client instance
43 |
44 | Instructions on how to install and use the bluzelle JS client is at https://github.com/bluzelle/blzjs
45 |
46 |
--------------------------------------------------------------------------------
/docs/nft/auth-protocol.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/nft/auth-protocol.dia
--------------------------------------------------------------------------------
/docs/nft/auth-protocol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/nft/auth-protocol.png
--------------------------------------------------------------------------------
/docs/nft/short protocol.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/nft/short protocol.dia
--------------------------------------------------------------------------------
/docs/nft/short protocol.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/nft/short protocol.png
--------------------------------------------------------------------------------
/docs/oracle/Diagram1.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/oracle/Diagram1.dia
--------------------------------------------------------------------------------
/docs/oracle/Diagram1.dia~:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/docs/oracle/Diagram1.dia~
--------------------------------------------------------------------------------
/docs/rest/buildrest.md:
--------------------------------------------------------------------------------
1 | [Back](../../README.md)
2 | ***
3 |
4 | Starting the Light-client Daemon (Local REST Server)
5 | ====================================================
6 |
7 | >If required, please refer to the [OS Setup for Curium](../setup/os.md) and
8 | [Development Environment Setup](../setup/devenv.md) documents for
9 | instructions on how to set up your OS and Golang development environment.
10 |
11 |
12 | 1. In a terminal, change to the Curium project working directory
13 |
14 | cd ~/go/src/github.com/bluzelle/curium
15 |
16 | 2. Use make to build and install the blzd and blzcli executables
17 |
18 | make mainnet
19 |
20 | 3. Ensure Bluzelle CLI works by executing the binary, you should
21 | be able to execute the app from your home directory:
22 |
23 | cd
24 | blzcli
25 |
26 | The output of the Bluzelle CLI will be:
27 |
28 | Bluzelle CRUD Client
29 |
30 | Usage:
31 | blzcli [command]
32 |
33 | Available Commands:
34 | status Query remote node for status
35 | config Create or query an application CLI configuration file
36 | query Querying subcommands
37 | tx Transactions subcommands
38 |
39 | rest-server Start LCD (light-client daemon), a local REST server
40 |
41 | keys Add or view local private keys
42 |
43 | version Print the app version
44 | help Help about any command
45 |
46 | Flags:
47 | --chain-id string Chain ID of tendermint node
48 | -e, --encoding string Binary encoding (hex|b64|btc) (default "hex")
49 | -h, --help help for blzcli
50 | --home string directory for config and data (default "/Users/rnistuk/.blzcli")
51 | -o, --output string Output format (text|json) (default "text")
52 | --trace print out full stack trace on errors
53 |
54 | Use "blzcli [command] --help" for more information about a command.
55 |
56 | 4. Start the Light-client Daemon (LCD) on the command line using thes
57 | rest-server command with the "--node" argument to specify the IP address and RPC (TCP) port (typically 26657) of
58 | a Curium node in the zone to connect to
59 |
60 | blzcli rest-server --node :
61 |
62 | if the node is not specified the default value of "tcp://localhost:26657"
63 | will be used.
64 |
65 | 5. You will now be able to interact with the connected zone via the REST
66 | interface provided by the LCD.
67 |
68 | [Back](../../README.md)
69 |
--------------------------------------------------------------------------------
/docs/setup/devenv.md:
--------------------------------------------------------------------------------
1 | # Development Environment Setup
2 |
3 | [prev](os.md) \| [next](build.md)
4 |
5 | ## Development Environment Setup
6 |
7 | 1. Curium uses Golang, in \*nix, run these commands in a terminal
8 |
9 | ```text
10 | wget https://golang.org/dl/go1.15.6.linux-amd64.tar.gz
11 | sudo tar -C /usr/local -xzf go1.15.6.linux-amd64.tar.gz
12 | ```
13 |
14 | on macOS install the latest package from here: [https://golang.org/doc/install](https://golang.org/doc/install)
15 |
16 | 2. Make sure your Environment paths are set in your .profile file, for example, add the following to the end of your .profile, .\*rc file or equivalent
17 |
18 | ```text
19 | export GOPATH=$HOME/go
20 | export GOBIN=${GOPATH}/bin
21 | export PATH=$PATH:$GOBIN:/usr/local/go/bin
22 | ```
23 |
24 | GOPATH is where the golang project source files, packages and binaries are kept. Make sure that the Golang compiler folder _and_ the GOBIN are in the PATH.
25 |
26 | BE SURE to source the file that you added these paths to. For example, if it was to your ".profile" file, do the following:
27 |
28 | ```text
29 | source ~/.profile
30 | ```
31 |
32 | 3. Make the Golang working folders with the following commands in a terminal
33 |
34 | ```text
35 | mkdir -p ~/go/src/github.com/bluzelle
36 | mkdir ~/go/bin
37 | mkdir ~/go/pkg
38 | ```
39 |
40 | 4. In a terminal change directory to the the bluzelle directory
41 |
42 | ```text
43 | cd ~/go/src/github.com/bluzelle
44 | ```
45 |
46 | 5. Clone the Curium project from GitHub into the directory referenced above
47 |
48 | ```text
49 | git clone https://github.com/bluzelle/curium.git
50 | ```
51 |
52 | 6. Create an nft directory in your home directory
53 |
54 | ```text
55 | mkdir ~/nft
56 | ```
57 |
58 | CRITICAL: The "nft-base-dir" is where NFT files from the new Bluzelle NFT service will get stored to. It is vital that the volume this folder is in, be monitored and that it not fill up. NFT files can quickly overwhelm a small volume. If that volume happens to be the same one used by the blzd daemon, it can cause your node to crash completely, when full. In the case of a validator, your node could come down, and get slashed. It is recommended to keep this as a separate volume on a larger, monitored drive.
59 |
60 | [prev](os.md) \| [next](build.md)
61 |
62 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/bluzelle/curium
2 |
3 | go 1.15
4 |
5 | replace github.com/keybase/go-keychain => github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4
6 |
7 | require (
8 | github.com/anacrolix/torrent v1.28.0
9 | github.com/cosmos/cosmos-sdk v0.39.2
10 | github.com/cosmos/modules/incubator/faucet v0.0.0-20200315124306-c86f71ae76a0
11 | github.com/ethereum/go-ethereum v1.10.4
12 | github.com/golang/mock v1.4.4
13 | github.com/gorilla/mux v1.7.4
14 | github.com/magiconair/properties v1.8.1
15 | github.com/robfig/cron/v3 v3.0.1
16 | github.com/spf13/cobra v1.0.0
17 | github.com/spf13/viper v1.6.3
18 | github.com/stretchr/testify v1.7.0
19 | github.com/tendermint/go-amino v0.15.1
20 | github.com/tendermint/tendermint v0.33.9
21 | github.com/tendermint/tm-db v0.5.1
22 | github.com/wenxiang/go-nestedjson v0.0.0-20150910062500-11a6c4340577
23 | github.com/zeebo/bencode v1.0.0
24 | golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
25 | )
26 |
--------------------------------------------------------------------------------
/home/.torrent.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/.torrent.db
--------------------------------------------------------------------------------
/home/.torrent.db-shm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/.torrent.db-shm
--------------------------------------------------------------------------------
/home/.torrent.db-wal:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/.torrent.db-wal
--------------------------------------------------------------------------------
/home/4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0
--------------------------------------------------------------------------------
/home/nft/.torrent.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/nft/.torrent.db
--------------------------------------------------------------------------------
/home/nft/.torrent.db-shm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/nft/.torrent.db-shm
--------------------------------------------------------------------------------
/home/nft/.torrent.db-wal:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/nft/.torrent.db-wal
--------------------------------------------------------------------------------
/home/nft/4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/home/nft/4cbf988462cc3ba2e10e3aae9f5268546aa79016359fb45be7dd199c073125c0
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "curium",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "private": true,
7 | "scripts": {
8 | "build": "make testnet",
9 | "deploy": "yarn --cwd=scripts zx deploy.ts",
10 | "setup": "./scripts/setup.ts"
11 | }
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/rest-service/buildrest.md:
--------------------------------------------------------------------------------
1 | # Building the CURIUM REST Service
2 |
3 | [Back](../)
4 |
5 | ## Starting the Light-client Daemon \(Local REST Server\)
6 |
7 | > If required, please refer to the [OS Setup for Curium](../setup/os.md) and [Development Environment Setup](../setup/devenv.md) documents for instructions on how to set up your OS and Golang development environment.
8 |
9 | 1. In a terminal, change to the Curium project working directory
10 |
11 | ```text
12 | cd ~/go/src/github.com/bluzelle/curium
13 | ```
14 |
15 | 2. Use make to build and install the blzd and blzcli executables
16 |
17 | ```text
18 | make mainnet
19 | ```
20 |
21 | 3. Ensure Bluzelle CLI works by executing the binary, you should be able to execute the app from your home directory:
22 |
23 | ```text
24 | cd
25 | blzcli
26 | ```
27 |
28 | The output of the Bluzelle CLI will be:
29 |
30 | ```text
31 | Bluzelle CRUD Client
32 |
33 | Usage:
34 | blzcli [command]
35 |
36 | Available Commands:
37 | status Query remote node for status
38 | config Create or query an application CLI configuration file
39 | query Querying subcommands
40 | tx Transactions subcommands
41 |
42 | rest-server Start LCD (light-client daemon), a local REST server
43 |
44 | keys Add or view local private keys
45 |
46 | version Print the app version
47 | help Help about any command
48 |
49 | Flags:
50 | --chain-id string Chain ID of tendermint node
51 | -e, --encoding string Binary encoding (hex|b64|btc) (default "hex")
52 | -h, --help help for blzcli
53 | --home string directory for config and data (default "/Users/rnistuk/.blzcli")
54 | -o, --output string Output format (text|json) (default "text")
55 | --trace print out full stack trace on errors
56 |
57 | Use "blzcli [command] --help" for more information about a command.
58 | ```
59 |
60 | 4. Start the Light-client Daemon \(LCD\) on the command line using thes rest-server command with the "--node" argument to specify the IP address and RPC \(TCP\) port \(typically 26657\) of a Curium node in the zone to connect to
61 |
62 | ```text
63 | blzcli rest-server --node :
64 | ```
65 |
66 | if the node is not specified the default value of "tcp://localhost:26657" will be used.
67 |
68 | 5. You will now be able to interact with the connected zone via the REST interface provided by the LCD.
69 |
70 | [Back](../)
71 |
72 |
--------------------------------------------------------------------------------
/scripts/deploy.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env zx
2 | import {$, cd} from 'zx';
3 |
4 | const deployCurium = () => {
5 | Promise.resolve()
6 | .then(() => $`git remote add temporary-remote-curium git@github.com:bluzelle/curium.git`)
7 | .then(() => $`git checkout -b deploy-curium`)
8 | .then(() => cd('../../'))
9 | .then(() => $`git filter-branch -f --tree-filter 'rm -rf curium/scripts/deploy.ts' HEAD`)
10 | .then(() => $`git filter-branch -f \
11 | --subdirectory-filter curium/ \
12 | --prune-empty \
13 | --tag-name-filter cat -- --all`)
14 | .then(() => $`git push -f temporary-remote-curium devel`)
15 | .then(() => $`git fetch`)
16 | .then(() => $`git checkout origin/devel`)
17 | .then(() => $`git branch -f devel`)
18 | .then(() => $`git checkout devel`)
19 | .then(() => $`git branch -D deploy-curium`)
20 | .then(() => $`git remote remove temporary-remote-curium`)
21 | .catch(error => {
22 | console.log(`SOMETHING WENT WRONG: ${error.message}`)
23 | process.exit(1)
24 | })
25 | }
26 |
27 | deployCurium()
--------------------------------------------------------------------------------
/scripts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "curium-scripts",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "private": true,
7 | "dependencies": {
8 | "@types/lodash": "^4.14.172",
9 | "@types/node": "^16.6.2",
10 | "bip39": "^3.0.4",
11 | "delay": "^5.0.0",
12 | "lodash": "^4.17.21",
13 | "promise-passthrough": "^1.0.5",
14 | "ts-node": "^10.2.1",
15 | "typescript": "^4.3.5",
16 | "zx": "^3.0.0"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/test/integration/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/test/integration/helpers/bluzelle-client.ts:
--------------------------------------------------------------------------------
1 | import {bluzelle, BluzelleConfig} from "bluzelle";
2 | import {memoize, times} from 'lodash'
3 | import {GasInfo} from "bluzelle";
4 | import {getSwarm} from "@bluzelle/testing/lib/helpers/swarmHelpers";
5 | import {SwarmConfig} from "daemon-manager/lib/SwarmConfig";
6 | import {entropyToMnemonic} from "bip39";
7 | import {Some} from "monet";
8 | import {passThrough} from "promise-passthrough";
9 | import {getSentryUrl} from "./nft-helpers";
10 |
11 | export const getBzClient = memoize((config: Partial = {}) =>
12 | bluzelle({
13 | mnemonic: "vivid rack volume school expect tobacco hello paddle annual tobacco choice evoke consider fluid attract bind error setup depth wedding night shove note jazz",
14 | endpoint: 'https://localhost:1327',
15 | uuid: 'uuid',
16 | ...config
17 | })
18 | );
19 |
20 | export const getSwarmAndClient = () =>
21 | getSwarm([withTestUsers])
22 | .then(swarm => ({swarm}))
23 | .then(({swarm}) => swarm.getValidators()[0].getAuth().then(auth => ({swarm, auth})))
24 | .then(({swarm, auth}) =>
25 | ({
26 | swarm,
27 | auth,
28 | bz: bluzelle({
29 | mnemonic: auth.mnemonic,
30 | uuid: Date.now().toString(),
31 | endpoint: getSentryUrl(swarm)
32 | })
33 | })
34 | )
35 |
36 | export const defaultGasParams = (gasInfo: GasInfo = {}): GasInfo => ({gas_price: 10, max_gas: 100000000, ...gasInfo})
37 |
38 | function withTestUsers (config: SwarmConfig): SwarmConfig {
39 | return Some({
40 | ...config,
41 | additionalUsers: times(4).map(n =>({
42 | name: `test-${n}`,
43 | mnemonic: entropyToMnemonic((n + 1).toString().repeat(30) + 'aa')
44 | }))
45 | } as SwarmConfig)
46 | .map(passThrough((config: SwarmConfig) => console.log("******** test users ******\n", config.additionalUsers)))
47 | .join()
48 | }
--------------------------------------------------------------------------------
/test/integration/helpers/blzcli.ts:
--------------------------------------------------------------------------------
1 | import * as util from "util";
2 |
3 | const exec = util.promisify(require('child_process').exec);
4 |
5 | export const blzcli = (...args):Promise =>
6 | exec(`blzcli ${args.join(' ')}`);
7 |
8 | export const STANDARD_GAS = '--gas auto --gas-adjustment 2 --gas-prices 0.002ubnt'
9 | export const BLOCK = '--broadcast-mode block'
10 |
11 |
--------------------------------------------------------------------------------
/test/integration/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "curium-tests",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "private": true,
7 | "dependencies": {
8 | "@bluzelle/oracle-js": "^1.0.8",
9 | "@bluzelle/testing": "^1.0.0",
10 | "@types/chai": "^4.2.21",
11 | "@types/chai-as-promised": "^7.1.4",
12 | "@types/create-torrent": "^5.0.0",
13 | "@types/lodash": "^4.14.172",
14 | "@types/mocha": "^9.0.0",
15 | "@types/node": "^14.14.20",
16 | "@types/node-fetch": "^2.5.12",
17 | "async-wait-until": "^2.0.7",
18 | "bip39": "^3.0.4",
19 | "bluzelle": "^3.0.7",
20 | "chai": "^4.2.0",
21 | "chai-as-promised": "^7.1.1",
22 | "cksum": "^1.3.0",
23 | "create-torrent": "^5.0.1",
24 | "daemon-manager": "^1.0.4",
25 | "delay": "^5.0.0",
26 | "js-sha256": "^0.9.0",
27 | "lodash": "^4.17.21",
28 | "mocha": "^8.2.1",
29 | "monet": "^0.9.1",
30 | "node-fetch": "^2.6.1",
31 | "promise-passthrough": "^1.0.5",
32 | "ts-node": "^9.1.1",
33 | "typescript": "^4.1.3"
34 | },
35 | "scripts": {
36 | "test": "mocha -r ts-node/register specs/*/**/*.spec.ts"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/test/integration/specs/ante.spec.ts:
--------------------------------------------------------------------------------
1 | import {BLOCK, blzcli, STANDARD_GAS} from "../helpers/blzcli";
2 | import {getBzClient} from "../helpers/bluzelle-client";
3 | import {passThroughAwait} from "promise-passthrough";
4 | import {expect} from 'chai'
5 | import {addOracleSource} from 'oracle-js'
6 |
7 | describe('Ante handler tests', () => {
8 | it("should charge for regular transactions", async () => {
9 | await shouldCharge(
10 | (bz) => bz.upsert('foo', 'bar', {gas_price: 0.002, max_gas: 10000000})
11 | )
12 | });
13 |
14 | it('should not charge for oracle transactions', async () => {
15 | await shouldBeFree(
16 | (bz) => addOracleSource(bz, {
17 | Name: 'my-source',
18 | Url: 'my-url',
19 | Property: 'my-property'
20 | }, {gas_price: 0.002})
21 | )
22 | });
23 |
24 | })
25 |
26 | type CheckFn = (number) => number
27 | const shouldCharge = (fn: (API) => Promise, checkFn: CheckFn = (x) => x) =>
28 | getBzClient().getBNT({ubnt: true})
29 | .then(passThroughAwait(() => fn(getBzClient())))
30 | .then(async (before) =>
31 | expect(await getBzClient().getBNT({ubnt: true}))
32 | .to.be.lessThan(checkFn(before))
33 | )
34 |
35 | const shouldBeFree = (fn: (API) => Promise) =>
36 | getBzClient().getBNT({ubnt: true})
37 | .then(passThroughAwait(() => fn(getBzClient())))
38 | .then(async (before) =>
39 | expect(await getBzClient().getBNT({ubnt: true}))
40 | .to.equal(before)
41 | )
--------------------------------------------------------------------------------
/test/integration/specs/nft/MsgPublishFile.spec.ts:
--------------------------------------------------------------------------------
1 | import {defaultGasParams, getSwarmAndClient} from "../../helpers/bluzelle-client";
2 | import {Swarm} from "daemon-manager/lib/Swarm";
3 | import {API} from "bluzelle";
4 | import chai from 'chai'
5 | import asPromised from 'chai-as-promised'
6 | import createTorrent from 'create-torrent'
7 |
8 |
9 | chai.use(asPromised);
10 |
11 | describe('MsgPublishFile', function () {
12 | this.timeout(400_000);
13 | let bz: API
14 | let swarm: Swarm
15 |
16 | beforeEach(() => {
17 | return getSwarmAndClient()
18 | .then(({bz: newBz, swarm: newSwarm}) => {
19 | bz = newBz
20 | swarm = newSwarm
21 | bz.uuid = 'bluzelle'
22 | })
23 | .then(() => bz.upsert("nft-whitelist", JSON.stringify([bz.address]), defaultGasParams()))
24 | .then(() => Promise.all(swarm.getDaemons().map(daemon =>
25 | daemon.exec(`rm -rf ${daemon.getNftBaseDir()}/nft*`)
26 | )))
27 | });
28 |
29 | it('should be rejected if the metainfo includes tracker info', (done) => {
30 | new Promise((resolve) =>
31 | createTorrent(Buffer.from(''), {
32 | name: 'name',
33 | comment: 'comment',
34 | createdBy: 'createdBy',
35 | creationDate: Date.now(),
36 | private: true,
37 | pieceLength: 60,
38 | announceList: [['sometracker']],
39 | urlList: [],
40 | info: {}
41 | }, (err, torrent) => resolve(torrent))
42 | )
43 | .then(torrent =>
44 | bz.sendMessage({
45 | type: 'nft/PublishFile',
46 | value: {
47 | creator: bz.address,
48 | id: 'my-id',
49 | vendor: 'vendor',
50 | metainfo: Array.from(torrent as Uint8Array)
51 | }
52 | }, defaultGasParams())
53 | )
54 | .then(x => done("should have been rejected with error"))
55 | .catch(e => e.error === 'Invalid torrent metainfo in publish' ? done() : done(`wrong error: ${e.error}`))
56 | });
57 |
58 |
59 | })
--------------------------------------------------------------------------------
/test/integration/specs/nft/nft-upload.spec.ts:
--------------------------------------------------------------------------------
1 | import {getSwarmAndClient} from "../../helpers/bluzelle-client";
2 | import {Swarm} from "daemon-manager/lib/Swarm";
3 | import {API, uploadNft} from "bluzelle";
4 | import {getSentryUrl} from "../../helpers/nft-helpers";
5 |
6 | describe('nft upload', function() {
7 | this.timeout(100000);
8 | let bz: API
9 | let swarm: Swarm
10 | beforeEach(() => {
11 | return getSwarmAndClient()
12 | .then(({bz: newBz, swarm: newSwarm}) => {
13 | bz = newBz
14 | swarm = newSwarm
15 | })
16 | });
17 |
18 | it('should send a 403 if upload has not been authorized', (done) => {
19 | uploadNft(getSentryUrl(swarm), new TextEncoder().encode('data'), '1111', 'mintable')
20 | .then(x => done('should have thrown an error'))
21 | .catch(e => done(e.includes('auth invalid') ? undefined : `wrong error: ${e}`))
22 | })
23 | })
--------------------------------------------------------------------------------
/test/integration/specs/oracle/oracle-utils.ts:
--------------------------------------------------------------------------------
1 | import {API} from "../../../../../blzjs/client";
2 | import {passThrough} from "promise-passthrough";
3 | import {listOracleSources, Source} from '@bluzelle/oracle-js'
4 |
5 | const VALCONS = 'bluzellevalcons12345'
6 |
7 | export const deleteVotes = (bz: API) =>
8 | bz.sendMessage({
9 | type: 'oracle/MsgOracleDeleteVotes',
10 | value: {
11 | Prefix: '2',
12 | Owner: bz.address
13 | }
14 | }, {gas_price: 0.002})
15 |
16 | export const deleteSources = (bz: API): Promise =>
17 | listOracleSources(bz)
18 | .then((sources: Source[]): any => sources.length && bz.withTransaction(() =>
19 | sources.map((source: Source) => deleteSource(bz, source.Name))
20 | )
21 | )
22 |
23 | const deleteSource = (bz: API, name: string): Promise =>
24 | bz.sendMessage({
25 | type: 'oracle/MsgOracleDeleteSource',
26 | value: {
27 | Name: name,
28 | Owner: bz.address
29 | }
30 | }, {gas_price: 0.002});
31 |
32 | const awaitContext = (prop: string, fn: Function) => (state: Object) =>
33 | fn(state)
34 | .then((val: unknown) => ({...state, [prop]: val}))
35 |
36 | const getValcons = (bz: API) => bz.abciQuery('custom/oracle/getValcons', {})
37 | .then(x => x.result)
38 |
39 | const calculateProofSig = (bz: API, value: string) =>
40 | bz.abciQuery('custom/oracle/calculateVoteProofSig', {
41 | Value: value
42 | })
43 | .then(x => x.result)
44 |
45 |
46 | export const addVote = (bz: API, vote: any) =>
47 | Promise.resolve({bz: bz, vote: vote})
48 | .then(awaitContext('valcons', (ctx: any) => getValcons(ctx.bz)))
49 | .then(awaitContext('sig', (ctx: any) => calculateProofSig(ctx.bz, ctx.vote.Value)))
50 | .then(passThrough((ctx: any) =>
51 | bz.sendMessage({
52 | type: 'oracle/MsgOracleVoteProof',
53 | value: {
54 | ValidatorAddr: ctx.valcons,
55 | VoteSig: ctx.sig,
56 | Owner: ctx.bz.address,
57 | SourceName: ctx.vote.SourceName
58 | }
59 | }, {gas_price: 0.002})
60 | )
61 | )
62 | .then(ctx =>
63 | ctx.bz.sendMessage({
64 | type: 'oracle/MsgOracleVote',
65 | value: {
66 | ...vote,
67 | Valcons: ctx.valcons,
68 | Owner: ctx.bz.address,
69 | Batch: ""
70 | }
71 | }, {gas_price: 0.002})
72 | )
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/test/integration/specs/oracle/rest/add-source.spec.ts:
--------------------------------------------------------------------------------
1 | import {expect} from 'chai'
2 | import {API, bluzelle} from "bluzelle";
3 | import {deleteSources} from "../oracle-utils";
4 | import {getBzClient} from "../../../helpers/bluzelle-client";
5 | import {feedSources} from "../sources";
6 | import {listOracleSources, addOracleSource} from '@bluzelle/oracle-js'
7 |
8 | describe.skip('add-source functions', function() {
9 | this.timeout(10000);
10 | let bz: API
11 |
12 | beforeEach(() => bz = getBzClient());
13 | beforeEach(() => deleteSources(bz));
14 |
15 | it('should add sources', () => {
16 | return addOracleSource(bz, {Name: 'my-source', Url: 'my-url', Property: 'my-property', Weight: "100"}, {gas_price: 0.002})
17 | .then(() => listOracleSources(bz))
18 | .then(sources => {
19 | expect(sources).to.have.length(1);
20 | expect(sources[0].Name).to.equal('my-source');
21 | });
22 | });
23 |
24 | it('should be able to add a source', async () => {
25 | await addOracleSource(
26 | bz,
27 | {
28 | Name: feedSources[0].name,
29 | Url: feedSources[0].url,
30 | Property: feedSources[0].property,
31 | Weight: '100'
32 | },
33 | {gas_price: 0.002}
34 | )
35 |
36 | await listOracleSources(bz)
37 | .then(sources => expect(sources).to.deep.equal([{
38 | Name: "binance-eth-in-usdt",
39 | Url: "https://api.binance.com/api/v1/ticker/price?symbol=ETHUSDT",
40 | Property: "price",
41 | Owner: "bluzelle1ws42h2gjr6q8u5d2teexhrzz9xr9lqrxru50u2"
42 | }]));
43 |
44 | });
45 |
46 | });
47 |
48 |
--------------------------------------------------------------------------------
/test/integration/specs/oracle/rest/search-votes.spec.ts:
--------------------------------------------------------------------------------
1 | import {API} from "../../../../../../blzjs/client";
2 | import {getBzClient} from "../../../helpers/bluzelle-client";
3 | import {addVote, deleteVotes} from "../oracle-utils";
4 | import {expect} from "chai";
5 | import {passThrough} from "promise-passthrough";
6 | import {searchOracleVotes} from '@bluzelle/oracle-js'
7 |
8 | describe.skip('search-votes functions', function () {
9 | this.timeout(60000);
10 | let bz: API
11 |
12 | beforeEach(() => bz = getBzClient());
13 | beforeEach(() => deleteVotes(bz));
14 |
15 | it('should search votes', () => {
16 | return Promise.all([
17 | addVote(bz, {
18 | Value: '10.5',
19 | SourceName: 'my-source'
20 | }),
21 | addVote(bz, {
22 | Value: '20.2',
23 | SourceName: 'my-source-2'
24 | })
25 | ])
26 | .then(() => searchOracleVotes(bz, {Prefix: '2021'}))
27 | .then(passThrough(votes => expect(votes).to.have.length(2)))
28 | .then((votes: any[]) => votes.map(v => parseFloat(v.Value)))
29 | .then(votes => expect(votes).to.deep.equal([20.2, 10.5]))
30 | });
31 |
32 | it('should search vote keys', () => {
33 | return bz.abciQuery("/custom/oracle/searchvotekeys", {
34 | Prefix: '2021'
35 | })
36 | .then(x => x)
37 | })
38 | });
39 |
40 |
--------------------------------------------------------------------------------
/test/integration/specs/oracle/shouldBeFreeHelper.ts:
--------------------------------------------------------------------------------
1 | import {getBzClient} from "../../helpers/bluzelle-client";
2 | import {passThroughAwait} from "promise-passthrough";
3 | import {expect} from 'chai'
4 |
5 | export const testShouldBeFree = (msgName: string, fn: (API) => Promise) =>
6 | it(`message ${msgName} should be free`, () =>
7 | getBzClient().getBNT({ubnt: true})
8 | .then(passThroughAwait(() => fn(getBzClient())))
9 | .then(async (ubnt) => expect(await getBzClient().getBNT({ubnt: true})).to.equal(ubnt))
10 | )
--------------------------------------------------------------------------------
/test/load/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "curium-load",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "@types/chai": "^4.2.21",
8 | "@types/lodash": "^4.14.172",
9 | "@types/node": "^16.9.1",
10 | "async-wait-until": "^2.0.7",
11 | "bluzelle": "^3.0.9",
12 | "chai": "^4.3.4",
13 | "cksum": "^1.3.0",
14 | "daemon-manager": "^1.0.4",
15 | "delay": "^5.0.0",
16 | "js-sha256": "^0.9.0",
17 | "lodash": "^4.17.21",
18 | "monet": "^0.9.2",
19 | "promise-passthrough": "^1.0.5",
20 | "ts-node": "^10.2.1",
21 | "typescript": "^4.4.3"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/.yarn-integrity:
--------------------------------------------------------------------------------
1 | {
2 | "systemParams": "darwin-x64-83",
3 | "modulesFolders": [
4 | "node_modules"
5 | ],
6 | "flags": [],
7 | "linkedModules": [
8 | "bluzelle",
9 | "daemon-manager",
10 | "oracle-js"
11 | ],
12 | "topLevelPatterns": [
13 | "monet@^0.9.1"
14 | ],
15 | "lockfileEntries": {
16 | "monet@^0.9.1": "https://registry.yarnpkg.com/monet/-/monet-0.9.1.tgz#89686a22d9dd8a6228fcde5265fcd86aa63981a7"
17 | },
18 | "files": [],
19 | "artifacts": {}
20 | }
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-2018 Chris Myers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/dist/monet-pimp.js:
--------------------------------------------------------------------------------
1 | /**
2 | * monet-pimp.js 0.9.0-rc.1
3 | *
4 | * This file needs to be included after monet.js
5 | *
6 | * (c) 2012-2018 Chris Myers
7 | * @license Monet-pimp.js may be freely distributed under the MIT license.
8 | * For all details and documentation:
9 | * https://monet.github.io/monet.js/
10 | */
11 | (function(root, factory) {
12 | if (typeof define === "function" && define.amd) {
13 | define([ "monet" ], factory);
14 | } else if (typeof module === "object" && module.exports) {
15 | module.exports = factory(require("monet"), root);
16 | } else {
17 | factory(root.Monet, root);
18 | }
19 | })(typeof self !== "undefined" ? self : this, function(Monet, rootGlobalObject) {
20 | "use strict";
21 | function wrapReader(fn, args) {
22 | var newArgs = args || [];
23 | return function() {
24 | var args1 = newArgs.concat(Array.prototype.slice.call(arguments));
25 | return args1.length + 1 >= fn.length ? getStatic("Reader")(function(c) {
26 | return fn.apply(null, args1.concat(c));
27 | }) : wrapReader(fn, args1);
28 | };
29 | }
30 | function getStatic(name) {
31 | return rootGlobalObject && rootGlobalObject[name] || Monet[name];
32 | }
33 | Object.prototype.cons = function(list) {
34 | return list.cons(this);
35 | };
36 | Object.prototype.some = Object.prototype.just = function() {
37 | return getStatic("Some")(this);
38 | };
39 | Object.prototype.success = function() {
40 | return getStatic("Validation").success(this);
41 | };
42 | Object.prototype.fail = function() {
43 | return getStatic("Validation").fail(this);
44 | };
45 | Object.prototype.right = function() {
46 | return getStatic("Either").Right(this);
47 | };
48 | Object.prototype.left = function() {
49 | return getStatic("Either").Left(this);
50 | };
51 | Array.prototype.list = function() {
52 | return getStatic("List").fromArray(this);
53 | };
54 | Function.prototype.curry = function() {
55 | return Monet.curry(this);
56 | };
57 | Function.prototype.compose = function(g) {
58 | return Monet.compose(this, g);
59 | };
60 | Function.prototype.andThen = Function.prototype.map = function(g) {
61 | var f = this;
62 | return function(x) {
63 | return g(f(x));
64 | };
65 | };
66 | Function.prototype.io = function() {
67 | return getStatic("IO")(this);
68 | };
69 | Function.prototype.io1 = function() {
70 | var f = this;
71 | return function(x) {
72 | return getStatic("IO")(function() {
73 | return f(x);
74 | });
75 | };
76 | };
77 | Function.prototype.reader = function() {
78 | return wrapReader(this);
79 | };
80 | });
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/dist/monet-pimp.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * monet-pimp.js 0.9.0-rc.1
3 | *
4 | * This file needs to be included after monet.js
5 | *
6 | * (c) 2012-2018 Chris Myers
7 | * @license Monet-pimp.js may be freely distributed under the MIT license.
8 | * For all details and documentation:
9 | * https://monet.github.io/monet.js/
10 | */
11 | !function(t,e){"function"==typeof define&&define.amd?define(["monet"],e):"object"==typeof module&&module.exports?module.exports=e(require("monet"),t):e(t.Monet,t)}("undefined"!=typeof self?self:this,function(e,n){"use strict";function getStatic(t){return n&&n[t]||e[t]}Object.prototype.cons=function(t){return t.cons(this)},Object.prototype.some=Object.prototype.just=function(){return getStatic("Some")(this)},Object.prototype.success=function(){return getStatic("Validation").success(this)},Object.prototype.fail=function(){return getStatic("Validation").fail(this)},Object.prototype.right=function(){return getStatic("Either").Right(this)},Object.prototype.left=function(){return getStatic("Either").Left(this)},Array.prototype.list=function(){return getStatic("List").fromArray(this)},Function.prototype.curry=function(){return e.curry(this)},Function.prototype.compose=function(t){return e.compose(this,t)},Function.prototype.andThen=Function.prototype.map=function(e){var n=this;return function(t){return e(n(t))}},Function.prototype.io=function(){return getStatic("IO")(this)},Function.prototype.io1=function(){var e=this;return function(t){return getStatic("IO")(function(){return e(t)})}},Function.prototype.reader=function(){return function wrapReader(n,t){var o=t||[];return function(){var e=o.concat(Array.prototype.slice.call(arguments));return e.length+1>=n.length?getStatic("Reader")(function(t){return n.apply(null,e.concat(t))}):wrapReader(n,e)}}(this)}});
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/dist/monet-pimp.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["dist/monet-pimp.js"],"names":["root","factory","define","amd","module","exports","require","Monet","self","this","rootGlobalObject","getStatic","name","Object","prototype","cons","list","some","just","success","fail","right","Right","left","Left","Array","fromArray","Function","curry","compose","g","andThen","map","f","x","io","io1","reader","wrapReader","fn","args","newArgs","args1","concat","slice","call","arguments","length","c","apply"],"mappings":";;;;;;;;;;CAUA,SAAUA,EAAMC,GACU,mBAAXC,QAAyBA,OAAOC,IACvCD,OAAO,CAAE,SAAWD,GACK,iBAAXG,QAAuBA,OAAOC,QAC5CD,OAAOC,QAAUJ,EAAQK,QAAQ,SAAUN,GAE3CC,EAAQD,EAAKO,MAAOP,GAN5B,CAQmB,oBAATQ,KAAuBA,KAAOC,KAAM,SAASF,EAAOG,GAC1D,aAUA,SAASC,UAAUC,GACf,OAAOF,GAAoBA,EAAiBE,IAASL,EAAMK,GAE/DC,OAAOC,UAAUC,KAAO,SAASC,GAC7B,OAAOA,EAAKD,KAAKN,OAErBI,OAAOC,UAAUG,KAAOJ,OAAOC,UAAUI,KAAO,WAC5C,OAAOP,UAAU,OAAVA,CAAkBF,OAE7BI,OAAOC,UAAUK,QAAU,WACvB,OAAOR,UAAU,cAAcQ,QAAQV,OAE3CI,OAAOC,UAAUM,KAAO,WACpB,OAAOT,UAAU,cAAcS,KAAKX,OAExCI,OAAOC,UAAUO,MAAQ,WACrB,OAAOV,UAAU,UAAUW,MAAMb,OAErCI,OAAOC,UAAUS,KAAO,WACpB,OAAOZ,UAAU,UAAUa,KAAKf,OAEpCgB,MAAMX,UAAUE,KAAO,WACnB,OAAOL,UAAU,QAAQe,UAAUjB,OAEvCkB,SAASb,UAAUc,MAAQ,WACvB,OAAOrB,EAAMqB,MAAMnB,OAEvBkB,SAASb,UAAUe,QAAU,SAASC,GAClC,OAAOvB,EAAMsB,QAAQpB,KAAMqB,IAE/BH,SAASb,UAAUiB,QAAUJ,SAASb,UAAUkB,IAAM,SAASF,GAC3D,IAAIG,EAAIxB,KACR,OAAO,SAASyB,GACZ,OAAOJ,EAAEG,EAAEC,MAGnBP,SAASb,UAAUqB,GAAK,WACpB,OAAOxB,UAAU,KAAVA,CAAgBF,OAE3BkB,SAASb,UAAUsB,IAAM,WACrB,IAAIH,EAAIxB,KACR,OAAO,SAASyB,GACZ,OAAOvB,UAAU,KAAVA,CAAgB,WACnB,OAAOsB,EAAEC,OAIrBP,SAASb,UAAUuB,OAAS,WACxB,OAzDJ,SAASC,WAAWC,EAAIC,GACpB,IAAIC,EAAUD,GAAQ,GACtB,OAAO,WACH,IAAIE,EAAQD,EAAQE,OAAOlB,MAAMX,UAAU8B,MAAMC,KAAKC,YACtD,OAAOJ,EAAMK,OAAS,GAAKR,EAAGQ,OAASpC,UAAU,SAAVA,CAAoB,SAASqC,GAChE,OAAOT,EAAGU,MAAM,KAAMP,EAAMC,OAAOK,MAClCV,WAAWC,EAAIG,IAmDjBJ,CAAW7B","file":"dist/monet-pimp.min.js.map"}
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/prepublish-test/browser-global.js:
--------------------------------------------------------------------------------
1 | describe('Browser: global Monet object', function () {
2 | it('should be available', function () {
3 | expect(Monet).toBeDefined()
4 | expect(Monet.Maybe).toBeDefined()
5 | expect(Monet.Either).toBeDefined()
6 | expect(Monet.Validation.success).toBe(Monet.Success)
7 |
8 | expect(() => Maybe).toThrow()
9 | expect(() => Either).toThrow()
10 | })
11 | })
12 |
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/prepublish-test/node-global.js:
--------------------------------------------------------------------------------
1 | global.Monet = require('../dist/monet.js')
2 |
3 | describe('Node: global Monet object', function () {
4 | it('should be available', function () {
5 | expect(Monet).toBeDefined()
6 | expect(Monet.Maybe).toBeDefined()
7 | expect(Monet.Either).toBeDefined()
8 | expect(Monet.Validation.success).toBe(Monet.Success)
9 |
10 | expect(() => Maybe).toThrow()
11 | expect(() => Either).toThrow()
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/test/oracle-mock/node_modules/monet/prepublish-test/node-regular.js:
--------------------------------------------------------------------------------
1 | const monet = require('../dist/monet.js')
2 |
3 | describe('Node: monet.js exports object', function () {
4 | it('should be available', function () {
5 | expect(monet).toBeDefined()
6 | expect(monet.Maybe).toBeDefined()
7 | expect(monet.Either).toBeDefined()
8 | expect(monet.Validation.success).toBe(monet.Success)
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/test/oracle-mock/oracle-mock.ts:
--------------------------------------------------------------------------------
1 | import { serve, ServerRequest } from "https://deno.land/std@0.86.0/http/server.ts";
2 |
3 | const port = 8080;
4 | const server = serve({ hostname: "0.0.0.0", port });
5 | console.log(`http://localhost:${port}`);
6 |
7 | const counter = function* (): Generator {
8 | let count = 1;
9 | while(1) {
10 | yield count += 1
11 | }
12 | }()
13 |
14 | for await (const request of server) {
15 | Promise.resolve(request.url)
16 | .then(url => endpoints()[url])
17 | .then(fn => fn ? fn(request) : '')
18 | .then(result => JSON.stringify(result))
19 | .then(body => request.respond({ status: 200, body}))
20 | }
21 |
22 | function endpoints() {
23 | return {
24 | '/number-whole': (req: ServerRequest) => ({
25 | price: counter.next().value
26 | }),
27 | '/number-fractional': (req: ServerRequest) => ({
28 | price: counter.next().value *.1
29 | }),
30 | '/string-whole': (req: ServerRequest) => ({
31 | price: counter.next().value.toString()
32 | }),
33 | '/deep': (req: ServerRequest) => ({
34 | deep: {
35 | deeper: {
36 | price: counter.next().value
37 | }
38 | }
39 | })
40 | } as Record
41 | }
42 |
--------------------------------------------------------------------------------
/test/oracle-mock/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "monet": "^0.9.1"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/test/oracle-mock/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | monet@^0.9.1:
6 | version "0.9.1"
7 | resolved "https://registry.yarnpkg.com/monet/-/monet-0.9.1.tgz#89686a22d9dd8a6228fcde5265fcd86aa63981a7"
8 | integrity sha512-GaZw308g6t0WD+U2mGujwJckGp2b8AGGVuB6PiIwkXbq6rJeiqddre2mdbO4PxjyILPi+7GgtRkkfr6dBYXWtA==
9 |
--------------------------------------------------------------------------------
/types/development.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "os"
5 | "strings"
6 | )
7 |
8 | func IsDevelopment () (bool) {
9 | env, valid := os.LookupEnv("ENVIRONMENT")
10 | return valid && strings.Contains(env, "DEVEL")
11 | }
--------------------------------------------------------------------------------
/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // AppName is the name of the Cosmos app
5 |
6 | AppName = "CRUD"
7 | )
8 |
9 | const (
10 | // Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
11 |
12 | Bech32PrefixAccAddr = "bluzelle"
13 |
14 | // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key
15 |
16 | Bech32PrefixAccPub = "bluzellepub"
17 |
18 | // Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address
19 |
20 | Bech32PrefixValAddr = "bluzellevaloper"
21 |
22 | // Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key
23 |
24 | Bech32PrefixValPub = "bluzellevaloperpub"
25 |
26 | // Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address
27 |
28 | Bech32PrefixConsAddr = "bluzellevalcons"
29 |
30 | // Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key
31 |
32 | Bech32PrefixConsPub = "bluzellevalconspub"
33 | )
34 |
--------------------------------------------------------------------------------
/x/aggregator/abci.go:
--------------------------------------------------------------------------------
1 | package aggregator
2 |
3 | import (
4 | "github.com/bluzelle/curium/app/ante/gasmeter"
5 | "github.com/bluzelle/curium/x/aggregator/keeper"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 |
10 | func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
11 | k.AggregateValues(ctx.WithGasMeter(gasmeter.NewFreeGasMeter(0)))
12 | }
--------------------------------------------------------------------------------
/x/aggregator/alias.go:
--------------------------------------------------------------------------------
1 | package aggregator
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/aggregator/keeper"
5 | "github.com/bluzelle/curium/x/aggregator/types"
6 | )
7 |
8 | var (
9 | ModuleName = types.ModuleName
10 | StoreKey = types.StoreKey
11 | NewKeeper = keeper.NewKeeper
12 | NewQuerier = keeper.NewQuerier
13 | ModuleCdc = types.ModuleCdc
14 | RegisterCodec = types.RegisterCodec
15 |
16 | )
17 |
18 | type (
19 | Keeper = keeper.Keeper
20 | )
--------------------------------------------------------------------------------
/x/aggregator/client/cli/query.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "github.com/cosmos/cosmos-sdk/client/context"
6 | "github.com/spf13/cobra"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/cosmos/cosmos-sdk/codec"
11 |
12 | "github.com/bluzelle/curium/x/aggregator/types"
13 | )
14 |
15 | // GetQueryCmd returns the cli query commands for this module
16 | func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
17 | // Group aggregator queries under a subcommand
18 | aggregatorQueryCmd := &cobra.Command{
19 | Use: types.ModuleName,
20 | Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
21 | DisableFlagParsing: true,
22 | SuggestionsMinimumDistance: 2,
23 | RunE: client.ValidateCmd,
24 | }
25 |
26 | aggregatorQueryCmd.AddCommand(
27 | flags.GetCommands(
28 | GetCmdQSearchValues(queryRoute, cdc),
29 | // this line is used by starport scaffolding # 1
30 | )...,
31 | )
32 |
33 | return aggregatorQueryCmd
34 | }
35 |
36 | func GetCmdQSearchValues(queryRoute string, cdc *codec.Codec) *cobra.Command {
37 | return &cobra.Command{
38 | Use: "search-values",
39 | Short: "Search aggregator values",
40 | Args: cobra.ExactArgs(1),
41 | RunE: func(cmd *cobra.Command, args []string) error {
42 | cliCtx := context.NewCLIContext().WithCodec(cdc)
43 | data := types.QueryReqSearchValues{
44 | Prefix: args[0],
45 | }
46 | json := cdc.MustMarshalJSON(data)
47 | res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QuerySearchValues), json)
48 |
49 | if err != nil {
50 | fmt.Printf("Error: %s", err)
51 | return nil
52 | }
53 |
54 | var out []types.AggregatorValue
55 | cdc.MustUnmarshalJSON(res, &out)
56 |
57 | return cliCtx.PrintOutput(out)
58 | },
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/x/aggregator/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/spf13/cobra"
7 |
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | _ "github.com/cosmos/cosmos-sdk/client/context"
11 | "github.com/cosmos/cosmos-sdk/codec"
12 | _ "github.com/cosmos/cosmos-sdk/types"
13 | _ "github.com/cosmos/cosmos-sdk/x/auth"
14 | _ "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
15 | "github.com/bluzelle/curium/x/aggregator/types"
16 | )
17 |
18 | // GetTxCmd returns the transaction commands for this module
19 | func GetTxCmd(cdc *codec.Codec) *cobra.Command {
20 | aggregatorTxCmd := &cobra.Command{
21 | Use: types.ModuleName,
22 | Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
23 | DisableFlagParsing: true,
24 | SuggestionsMinimumDistance: 2,
25 | RunE: client.ValidateCmd,
26 | }
27 |
28 | aggregatorTxCmd.AddCommand(flags.PostCommands(
29 | // this line is used by starport scaffolding # 1
30 | // TODO: Add tx based commands
31 | // GetCmd(cdc)
32 | )...)
33 |
34 | return aggregatorTxCmd
35 | }
36 |
37 | // Example:
38 | /*
39 | // GetCmd is the CLI command for doing
40 | func GetCmd(cdc *codec.Codec) *cobra.Command {
41 | return &cobra.Command{
42 | Use: "Describe your action cmd",
43 | Short: "Provide a short description on the cmd",
44 | Args: cobra.ExactArgs(2), // Does your request require arguments
45 | RunE: func(cmd *cobra.Command, args []string) error {
46 | cliCtx := context.NewCLIContext().WithCodec(cdc)
47 | inBuf := bufio.NewReader(cmd.InOrStdin())
48 | txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
49 |
50 | msg := types.NewMsg(Action params)
51 | err = msg.ValidateBasic()
52 | if err != nil {
53 | return err
54 | }
55 |
56 | return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
57 | },
58 | }
59 | }
60 | */
61 |
--------------------------------------------------------------------------------
/x/aggregator/client/rest/query.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/bluzelle/curium/x/aggregator/types"
10 | "github.com/cosmos/cosmos-sdk/client/context"
11 | "github.com/cosmos/cosmos-sdk/types/rest"
12 | )
13 |
14 | func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
15 | r.HandleFunc("/aggregator/latestValues", queryLatestValuesFn(cliCtx)).Methods("GET")
16 | r.HandleFunc("/aggregator/latestPair/{symbol}/{inSymbol}", queryLatestPairFn(cliCtx)).Methods("GET")
17 | }
18 |
19 | func queryLatestValuesFn(cliCtx context.CLIContext) http.HandlerFunc {
20 | return func(w http.ResponseWriter, r *http.Request) {
21 | route := fmt.Sprintf("custom/%s/getLatestValues", types.QuerierRoute)
22 | res, _, err := cliCtx.QueryWithData(route, nil)
23 |
24 | if err != nil {
25 | rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
26 | return
27 | }
28 | rest.PostProcessResponse(w, cliCtx, res)
29 | }
30 | }
31 |
32 | func queryLatestPairFn(cliCtx context.CLIContext) http.HandlerFunc {
33 | return func(w http.ResponseWriter, r *http.Request) {
34 | vars := mux.Vars(r)
35 | route := fmt.Sprintf("custom/%s/getLatestPair", types.QuerierRoute)
36 | args := types.RestLatestPairReq{Symbol: vars["symbol"], InSymbol: vars["inSymbol"]}
37 | data := types.ModuleCdc.MustMarshalBinaryBare(args)
38 | res, _, err := cliCtx.QueryWithData(route, data)
39 |
40 | if err != nil {
41 | rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
42 | return
43 | }
44 | rest.PostProcessResponse(w, cliCtx, res)
45 | }
46 | }
47 |
48 |
49 | func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
50 | return func(w http.ResponseWriter, r *http.Request) {
51 | cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
52 | if !ok {
53 | return
54 | }
55 |
56 | route := fmt.Sprintf("custom/%s/parameters", types.QuerierRoute)
57 |
58 | res, height, err := cliCtx.QueryWithData(route, nil)
59 | if err != nil {
60 | rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
61 | return
62 | }
63 |
64 | cliCtx = cliCtx.WithHeight(height)
65 | rest.PostProcessResponse(w, cliCtx, res)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/x/aggregator/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "github.com/gorilla/mux"
5 |
6 | "github.com/cosmos/cosmos-sdk/client/context"
7 | )
8 |
9 | // RegisterRoutes registers aggregator-related REST handlers to a router
10 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
11 | // this line is used by starport scaffolding # 1
12 | registerQueryRoutes(cliCtx, r)
13 | registerTxRoutes(cliCtx, r)
14 | }
15 |
--------------------------------------------------------------------------------
/x/aggregator/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | package rest
2 | // The packages below are commented out at first to prevent an error if this file isn't initially saved.
3 | import (
4 | // "bytes"
5 | // "net/http"
6 |
7 | "github.com/gorilla/mux"
8 |
9 | "github.com/cosmos/cosmos-sdk/client/context"
10 | // sdk "github.com/cosmos/cosmos-sdk/types"
11 | // "github.com/cosmos/cosmos-sdk/types/rest"
12 | // "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
13 | // "github.com/bluzelle/curium/x/aggregator/types"
14 | )
15 |
16 | func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
17 | // r.HandleFunc(
18 | // TODO: Define the Rest route ,
19 | // Call the function which should be executed for this route),
20 | // ).Methods("POST")
21 | }
22 |
23 | /*
24 | // Action TX body
25 | type Req struct {
26 | BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
27 | // TODO: Define more types if needed
28 | }
29 |
30 | func RequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
31 | return func(w http.ResponseWriter, r *http.Request) {
32 | var req Req
33 | vars := mux.Vars(r)
34 |
35 | baseReq := req.BaseReq.Sanitize()
36 | if !baseReq.ValidateBasic(w) {
37 | return
38 | }
39 |
40 | // TODO: Define the module tx logic for this action
41 |
42 | utils.WriteGenerateStdTxResponse(w, cliCtx, BaseReq, []sdk.Msg{msg})
43 | }
44 | }
45 | */
46 |
--------------------------------------------------------------------------------
/x/aggregator/genesis.go:
--------------------------------------------------------------------------------
1 | package aggregator
2 |
3 | import (
4 | "fmt"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | "github.com/bluzelle/curium/x/aggregator/types"
7 | "github.com/bluzelle/curium/x/aggregator/keeper"
8 | )
9 |
10 | // InitGenesis initialize default parameters
11 | // and the keeper's address to pubkey map
12 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) {
13 | fmt.Println("testing")
14 | }
15 |
16 | // ExportGenesis writes the current store values
17 | // to a genesis file, which can be imported again
18 | // with InitGenesis
19 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) (data types.GenesisState) {
20 | return types.NewGenesisState(
21 | k.DumpAggValues(ctx),
22 | k.DumpQueueItems(ctx),
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/x/aggregator/handler.go:
--------------------------------------------------------------------------------
1 | package aggregator
2 |
3 | import (
4 | "fmt"
5 | "github.com/bluzelle/curium/app/ante/gasmeter"
6 |
7 | "github.com/bluzelle/curium/x/aggregator/keeper"
8 | "github.com/bluzelle/curium/x/aggregator/types"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
11 | )
12 |
13 | // NewHandler creates an sdk.Handler for all the aggregator type messages
14 | func NewHandler(k keeper.Keeper) sdk.Handler {
15 | return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
16 | ctx = ctx.WithEventManager(sdk.NewEventManager()).WithGasMeter(gasmeter.NewFreeGasMeter(0))
17 | switch msg := msg.(type) {
18 | default:
19 | errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg)
20 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
21 | }
22 | }
23 | }
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/x/aggregator/keeper/Averager.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | type Averager struct {
6 | Sum sdk.Dec
7 | Count int64
8 | WeightSum int64
9 | }
10 |
11 | func NewAverager() Averager {
12 | return Averager{
13 | Sum: sdk.NewDec(0),
14 | WeightSum: 0,
15 | Count: 0,
16 | }
17 | }
18 |
19 | func (a *Averager) Add(dec sdk.Dec, weight int64) Averager {
20 | if a.Sum.IsNil() {
21 | a.Sum = dec.MulInt64(weight)
22 | } else {
23 | a.Sum = a.Sum.Add(dec.MulInt64(weight))
24 | }
25 | a.WeightSum = a.WeightSum + weight
26 | a.Count = a.Count + 1
27 | return *a
28 | }
29 |
30 | func (a Averager) CalculateAverage() sdk.Dec {
31 | if a.WeightSum == 0 {
32 | logger.Info("zero weight in average")
33 | return a.Sum.QuoInt64(a.Count)
34 | }
35 | return a.Sum.QuoInt64(a.WeightSum)
36 | }
37 |
--------------------------------------------------------------------------------
/x/aggregator/keeper/Averager_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/aggregator/keeper"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | "github.com/stretchr/testify/assert"
7 | "testing"
8 | )
9 |
10 | func TestAverager(t *testing.T) {
11 | t.Run("It should provide an average", func(t *testing.T) {
12 | x := keeper.NewAverager()
13 | x.Add(sdk.NewDec(10), 100)
14 | x.Add(sdk.NewDec(20), 100)
15 | x.Add(sdk.NewDec(30), 100)
16 | assert.True(t, x.CalculateAverage().Equal(sdk.NewDec(20)))
17 | })
18 | }
19 |
--------------------------------------------------------------------------------
/x/aggregator/keeper/keeper_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | //import (
4 | // bluzellechain "github.com/bluzelle/curium/types"
5 | // "github.com/bluzelle/curium/x/aggregator/keeper"
6 | // "github.com/bluzelle/curium/x/aggregator/types"
7 | // "github.com/bluzelle/curium/x/oracle"
8 | // "github.com/cosmos/cosmos-sdk/codec"
9 | // "github.com/cosmos/cosmos-sdk/server/mock"
10 | // storeTypes "github.com/cosmos/cosmos-sdk/store/types"
11 | // sdk "github.com/cosmos/cosmos-sdk/types"
12 | // abci "github.com/tendermint/tendermint/abci/types"
13 | // "testing"
14 | //)
15 | //
16 | //func getKeeper() (keeper.Keeper, sdk.AccAddress, sdk.Context) {
17 | // ms := mock.NewCommitMultiStore()
18 | // queueStoreKey := sdk.NewKVStoreKey(types.ValueQueueStoreKey)
19 | // valueStoreKey := sdk.NewKVStoreKey(types.AggValueStoreKey)
20 | //
21 | // ms.MountStoreWithDB(queueStoreKey, storeTypes.StoreTypeDB, nil)
22 | // ms.MountStoreWithDB(valueStoreKey, storeTypes.StoreTypeDB, nil)
23 | //
24 | // ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
25 | // config := sdk.GetConfig()
26 | // config.SetBech32PrefixForAccount(bluzellechain.Bech32PrefixAccAddr, bluzellechain.Bech32PrefixAccPub)
27 | // config.SetBech32PrefixForValidator(bluzellechain.Bech32PrefixValAddr, bluzellechain.Bech32PrefixValPub)
28 | // config.SetBech32PrefixForConsensusNode(bluzellechain.Bech32PrefixConsAddr, bluzellechain.Bech32PrefixConsPub)
29 | //
30 | // addr, _ := sdk.AccAddressFromBech32("bluzelle1t0ywtmrduldf6h4wqrnnpyp9wr6law2u5jwa23")
31 | // keeper := keeper.NewKeeper(codec.New(), oracle.Keeper{}, queueStoreKey, valueStoreKey, nil)
32 | //
33 | // return keeper, addr, ctx
34 | //}
35 | //
36 | //
37 | //func Test_GetAggValueBatches(t *testing.T) {
38 | // t.Run("It should set a default limit of 50", func(t *testing.T) {
39 | // keeper, _, ctx := getKeeper()
40 | // store := keeper.GetAggValueStore(ctx)
41 | //
42 | // for i := 0; i < 1000; i++ {
43 | // store.Set([]byte(string(i % 100)+ ">testing"), make([]byte, 0))
44 | // }
45 | //
46 | // // TODO: Finish here
47 | // //batches := keeper.GetAggValueBatches(ctx, "", 10, true)
48 | // //fmt.Println(batches)
49 | //
50 | //
51 | // })
52 | //}
--------------------------------------------------------------------------------
/x/aggregator/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | // TODO: Define if your module needs Parameters, if not this can be deleted
4 |
5 | import (
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/bluzelle/curium/x/aggregator/types"
8 | )
9 |
10 | // GetParams returns the total set of aggregator parameters.
11 | func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
12 | k.paramspace.GetParamSet(ctx, ¶ms)
13 | return params
14 | }
15 |
16 | // SetParams sets the aggregator parameters to the param space.
17 | func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
18 | k.paramspace.SetParamSet(ctx, ¶ms)
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/x/aggregator/spec/README.md:
--------------------------------------------------------------------------------
1 | # aggregator module specification
2 |
3 | ## Abstract
4 |
5 |
6 |
7 | ## Contents
8 |
9 | // TODO: Create the below files if they are needed.
10 | 1. **[Concepts](01_concepts.md)**
11 | 2. **[State](02_state.md)**
12 | 3. **[Messages](03_messages.md)**
13 | 4. **[Begin-Block](04_begin_block.md)**
14 | 5. **[End-Block](06_end_bloc.md)**
15 | 6. **[05_hooks](06_hooks.md)**
16 | 7. **[Events](07_events.md)**
17 | 8. **[Parameters](08_params.md)**
18 |
--------------------------------------------------------------------------------
/x/aggregator/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | )
6 |
7 | // RegisterCodec registers concrete types on codec
8 | func RegisterCodec(cdc *codec.Codec) {
9 | // this line is used by starport scaffolding # 1
10 | // TODO: Register the modules msgs
11 | }
12 |
13 | // ModuleCdc defines the module codec
14 | var ModuleCdc *codec.Codec
15 |
16 | func init() {
17 | ModuleCdc = codec.New()
18 | RegisterCodec(ModuleCdc)
19 | codec.RegisterCrypto(ModuleCdc)
20 | ModuleCdc.Seal()
21 | }
22 |
--------------------------------------------------------------------------------
/x/aggregator/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | _ "github.com/cosmos/cosmos-sdk/types/errors"
5 | )
6 |
7 | // TODO: Fill out some custom errors for the module
8 | // You can see how they are constructed below:
9 | var (
10 | // ErrInvalid = sdkerrors.Register(ModuleName, 1, "custom error message")
11 | )
12 |
--------------------------------------------------------------------------------
/x/aggregator/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // aggregator module event types
4 | const (
5 | // TODO: Create your event types
6 | // EventType = "action"
7 |
8 | // TODO: Create keys fo your events, the values will be derivided from the msg
9 | // AttributeKeyAddress = "address"
10 |
11 | // TODO: Some events may not have values for that reason you want to emit that something happened.
12 | // AttributeValueDoubleSign = "double_sign"
13 |
14 | AttributeValueCategory = ModuleName
15 | )
16 |
--------------------------------------------------------------------------------
/x/aggregator/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/params"
6 | )
7 |
8 | // ParamSubspace defines the expected Subspace interfcace
9 | type ParamSubspace interface {
10 | WithKeyTable(table params.KeyTable) params.Subspace
11 | Get(ctx sdk.Context, key []byte, ptr interface{})
12 | GetParamSet(ctx sdk.Context, ps params.ParamSet)
13 | SetParamSet(ctx sdk.Context, ps params.ParamSet)
14 | }
15 |
16 | /*
17 | When a module wishes to interact with another module, it is good practice to define what it will use
18 | as an interface so the module cannot use things that are not permitted.
19 | TODO: Create interfaces of what you expect the other keepers to have to be able to use this module.
20 | type BankKeeper interface {
21 | SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error)
22 | SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
23 | }
24 | */
25 |
--------------------------------------------------------------------------------
/x/aggregator/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // GenesisState - all aggregator state that must be provided at genesis
4 | type GenesisState struct {
5 | AggValues map[string]AggregatorValue
6 | QueueValues map[string]AggregatorQueueItem
7 | }
8 |
9 | // NewGenesisState creates a new GenesisState object
10 | func NewGenesisState(aggValues map[string]AggregatorValue, queueValues map[string]AggregatorQueueItem) GenesisState {
11 | return GenesisState{
12 | AggValues: aggValues,
13 | QueueValues: queueValues,
14 | }
15 | }
16 |
17 | // DefaultGenesisState - default GenesisState used by Cosmos Hub
18 | func DefaultGenesisState() GenesisState {
19 | return GenesisState{
20 | // TODO: Fill out according to your genesis state, these values will be initialized but empty
21 | }
22 | }
23 |
24 | // ValidateGenesis validates the aggregator genesis parameters
25 | func ValidateGenesis(data GenesisState) error {
26 | // TODO: Create a sanity check to make sure the state conforms to the modules needs
27 | return nil
28 | }
29 |
--------------------------------------------------------------------------------
/x/aggregator/types/keeper.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import "github.com/cosmos/cosmos-sdk/types"
4 |
5 | type AggregatorValue struct {
6 | Batch string
7 | Symbol string
8 | InSymbol string
9 | Value types.Dec
10 | Count int64
11 | Height int64
12 | }
13 |
14 | type AggregatorQueueItem struct {
15 | SourceName string
16 | Batch string
17 | Symbol string
18 | InSymbol string
19 | Value types.Dec
20 | Height int64
21 | Weight int64
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/x/aggregator/types/key.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | const (
10 | // ModuleName is the name of the module
11 | ModuleName = "aggregator"
12 |
13 | // StoreKey to be used when creating the KVStore
14 | StoreKey = ModuleName
15 |
16 | // RouterKey to be used for routing msgs
17 | RouterKey = ModuleName
18 |
19 | // QuerierRoute to be used for querier msgs
20 | QuerierRoute = ModuleName
21 |
22 | // Store prefixes for various records
23 | AggValueStorePrefix = "V"
24 | QueueStorePrefix = "Q"
25 |
26 |
27 | )
28 |
29 | type QueueItemKey struct {
30 | Height int64
31 | Batch string
32 | SourceName string
33 | }
34 |
35 | func (qik QueueItemKey) Bytes() []byte {
36 | blockStr := fmt.Sprintf("%020d", qik.Height)
37 | return []byte(QueueStorePrefix + blockStr + ">" + qik.Batch + ">" + qik.SourceName)
38 | }
39 |
40 | func QueueItemKeyFromBytes(bytes []byte) QueueItemKey {
41 | parts := strings.Split(string(bytes[1:]), ">")
42 | height, _ := strconv.ParseInt(parts[0], 10, 64)
43 | return QueueItemKey{
44 | Height: height,
45 | Batch: parts[1],
46 | SourceName: parts[2],
47 | }
48 | }
49 |
50 | type AggStoreKey struct {
51 | Batch string
52 | Symbol string
53 | InSymbol string
54 | }
55 |
56 | func (ask AggStoreKey) Bytes() []byte {
57 | return []byte(AggValueStorePrefix + ask.Batch + ">" + ask.Symbol + "-" + ask.InSymbol)
58 | }
59 |
60 | func AggStoreKeyFromBytes(bytes []byte) AggStoreKey {
61 | parts := strings.Split(string(bytes[1:]), ">")
62 | symbolParts := strings.Split(parts[1], "-")
63 | return AggStoreKey{
64 | Batch: parts[0],
65 | Symbol: symbolParts[0],
66 | InSymbol: symbolParts[1],
67 | }
68 | }
69 |
70 |
71 |
--------------------------------------------------------------------------------
/x/aggregator/types/key_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/aggregator/types"
5 | "github.com/magiconair/properties/assert"
6 | "testing"
7 | )
8 |
9 | func Test_QueueItemKey(t *testing.T) {
10 | t.Run("it should serialize and deserialize to bytes", func(t *testing.T) {
11 | bytes := types.QueueItemKey{
12 | Height: 100,
13 | Batch: "2021-03-22-08:13",
14 | SourceName: "something-blz-in-usdt",
15 | }.Bytes()
16 |
17 | key := types.QueueItemKeyFromBytes(bytes)
18 | assert.Equal(t, key.Height, int64(100))
19 | assert.Equal(t, key.Batch, "2021-03-22-08:13")
20 | assert.Equal(t, key.SourceName, "something-blz-in-usdt")
21 | })
22 | }
23 |
24 | func Test_AggStoreKey(t *testing.T) {
25 | bytes := types.AggStoreKey{
26 | Batch: "2021-03-22-08:13",
27 | Symbol: "blz",
28 | InSymbol: "btc",
29 | }.Bytes()
30 |
31 | key := types.AggStoreKeyFromBytes(bytes)
32 | assert.Equal(t, key.Batch, "2021-03-22-08:13")
33 | assert.Equal(t, key.Symbol, "blz")
34 | assert.Equal(t, key.InSymbol, "btc")
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/x/aggregator/types/msg.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | _ "github.com/cosmos/cosmos-sdk/types"
5 | _ "github.com/cosmos/cosmos-sdk/types/errors"
6 | )
7 |
8 | // TODO: Describe your actions, these will implment the interface of `sdk.Msg`
9 |
10 | // verify interface at compile time
11 | //var _ sdk.Msg = &Msg{}
12 |
13 | // Msg - struct for unjailing jailed validator
14 | /*
15 | type Msg struct {
16 | ValidatorAddr sdk.ValAddress `json:"address" yaml:"address"` // address of the validator operator
17 | }
18 | */
19 |
20 | // NewMsg creates a new Msg instance
21 | /*
22 | func NewMsg(validatorAddr sdk.ValAddress) Msg {
23 | return Msg{
24 | ValidatorAddr: validatorAddr,
25 | }
26 | }
27 | */
28 |
29 | // const Const = ""
30 |
31 | // nolint
32 | /*
33 | func (msg Msg) Route() string { return RouterKey }
34 | func (msg Msg) Type() string { return Const }
35 | func (msg Msg) GetSigners() []sdk.AccAddress {
36 | return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddr)}
37 | }
38 |
39 | // GetSignBytes gets the bytes for the message signer to sign on
40 | func (msg Msg) GetSignBytes() []byte {
41 | bz := ModuleCdc.MustMarshalJSON(msg)
42 | return sdk.MustSortJSON(bz)
43 | }
44 |
45 | // ValidateBasic validity check for the AnteHandler
46 | func (msg Msg) ValidateBasic() error {
47 | if msg.ValidatorAddr.Empty() {
48 | return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing validator address")
49 | }
50 | return nil
51 | }
52 | */
53 |
--------------------------------------------------------------------------------
/x/aggregator/types/params.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/x/params"
7 | )
8 |
9 | // Default parameter namespace
10 | const (
11 | DefaultParamspace = ModuleName
12 | // TODO: Define your default parameters
13 | )
14 |
15 | // Parameter store keys
16 | var (
17 | // TODO: Define your keys for the parameter store
18 | // KeyParamName = []byte("ParamName")
19 | )
20 |
21 | // ParamKeyTable for aggregator module
22 | func ParamKeyTable() params.KeyTable {
23 | return params.NewKeyTable().RegisterParamSet(&Params{})
24 | }
25 |
26 | // Params - used for initializing default parameter for aggregator at genesis
27 | type Params struct {
28 | // TODO: Add your Paramaters to the Paramter struct
29 | // KeyParamName string `json:"key_param_name"`
30 | }
31 |
32 | // NewParams creates a new Params object
33 | func NewParams(/* TODO: Pass in the paramters*/) Params {
34 | return Params{
35 | // TODO: Create your Params Type
36 | }
37 | }
38 |
39 | // String implements the stringer interface for Params
40 | func (p Params) String() string {
41 | return fmt.Sprintf(`
42 | // TODO: Return all the params as a string
43 | `, )
44 | }
45 |
46 | // ParamSetPairs - Implements params.ParamSet
47 | func (p *Params) ParamSetPairs() params.ParamSetPairs {
48 | return params.ParamSetPairs{
49 | // TODO: Pair your key with the param
50 | // params.NewParamSetPair(KeyParamName, &p.ParamName),
51 | }
52 | }
53 |
54 | // DefaultParams defines the parameters for this module
55 | func DefaultParams() Params {
56 | return NewParams( /* TODO: Pass in your default Params */ )
57 | }
58 |
--------------------------------------------------------------------------------
/x/aggregator/types/querier.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // Query endpoints supported by the aggregator querier
4 | const (
5 | QueryParams = "queryParams"
6 | QuerySearchValues = "searchValues"
7 | QuerySearchBatchKeys = "searchBatchKeys"
8 | QueryGetAggregatedValue = "getAggregatedValue"
9 | QueryGetPairValuesHistory = "getPairValuesHistory"
10 | QueryGetLatestValues = "getLatestValues"
11 | QueryGetPairValues = "getLatestPair"
12 | )
13 |
14 | type RestLatestPairReq struct {
15 | Symbol string
16 | InSymbol string
17 | }
18 |
19 | type QueryReqSearchValues struct {
20 | Prefix string
21 | Reverse bool
22 | Page uint
23 | Limit uint
24 | }
25 |
26 | type QueryReqGetAggregatorValue struct {
27 | Batch string
28 | Pair string
29 | }
30 |
31 | type QueryReqSearchBatches struct {
32 | PreviousBatch string
33 | Reverse bool
34 | Limit uint
35 | }
36 |
37 | type QueryReqGetPairValuesHistory struct {
38 | StartBatch string
39 | EndBatch string
40 | Step int64
41 | Symbol string
42 | InSymbol string
43 | }
--------------------------------------------------------------------------------
/x/crud/alias.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package crud
16 |
17 | import (
18 | "github.com/bluzelle/curium/x/crud/internal/keeper"
19 | "github.com/bluzelle/curium/x/crud/internal/types"
20 | )
21 |
22 | const (
23 | ModuleName = types.ModuleName
24 | RouterKey = types.RouterKey
25 | StoreKey = types.StoreKey
26 | LeaseKey = types.LeaseKey
27 | OwnerKey = types.OwnerKey
28 | )
29 |
30 | var (
31 | NewKeeper = keeper.NewKeeper
32 | NewQuerier = keeper.NewQuerier
33 | ModuleCdc = types.ModuleCdc
34 | RegisterCodec = types.RegisterCodec
35 | )
36 |
37 | type (
38 | Keeper = keeper.Keeper
39 | MaxKeeperSizes = keeper.MaxKeeperSizes
40 | MsgCreate = types.MsgCreate
41 | MsgRead = types.MsgRead
42 | MsgUpdate = types.MsgUpdate
43 | MsgDelete = types.MsgDelete
44 | QueryResultRead = types.QueryResultRead
45 | QueryResultHas = types.QueryResultHas
46 | )
47 |
--------------------------------------------------------------------------------
/x/crud/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 | import (
18 | "fmt"
19 | "github.com/cosmos/cosmos-sdk/client/context"
20 | "github.com/gorilla/mux"
21 | )
22 |
23 | // RegisterRoutes - Central function to define routes that get registered by the main application
24 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string) {
25 | r.HandleFunc("/abci-query", AbciQueryHandler(cliCtx)).Methods("POST")
26 | r.HandleFunc("/account-txs/{address}/{start}", AccountTxsHandler(cliCtx)).Methods("GET")
27 | r.HandleFunc(fmt.Sprintf("/%s/count/{UUID}", storeName), BlzQCountHandler(cliCtx, storeName)).Methods("GET")
28 | r.HandleFunc(fmt.Sprintf("/%s/getlease/{UUID}/{key}", storeName), BlzQGetLeaseHandler(cliCtx, storeName)).Methods("GET")
29 | r.HandleFunc(fmt.Sprintf("/%s/getnshortestleases/{UUID}/{N}", storeName), BlzQGetNShortestLeasesHandler(cliCtx, storeName)).Methods("GET")
30 | r.HandleFunc(fmt.Sprintf("/%s/has/{UUID}/{key}", storeName), BlzQHasHandler(cliCtx, storeName)).Methods("GET")
31 | r.HandleFunc(fmt.Sprintf("/%s/keys/{UUID}", storeName), BlzQKeysHandler(cliCtx, storeName)).Methods("GET")
32 | r.HandleFunc(fmt.Sprintf("/%s/search/{UUID}/{prefix}/{page}/{limit}/{direction}", storeName), BlzQSearchHandler(cliCtx, storeName)).Methods("GET")
33 | r.HandleFunc(fmt.Sprintf("/%s/keyvalues/{UUID}", storeName), BlzQKeyValuesHandler(cliCtx, storeName)).Methods("GET")
34 | r.HandleFunc(fmt.Sprintf("/%s/pread/{UUID}/{key}", storeName), BlzQProvenReadHandler(cliCtx, storeName)).Methods("GET")
35 | r.HandleFunc(fmt.Sprintf("/%s/read/{UUID}/{key}", storeName), BlzQReadHandler(cliCtx, storeName)).Methods("GET")
36 | r.HandleFunc(fmt.Sprintf("/%s/owner/{UUID}/{key}", storeName), BlzQOwnerHandler(cliCtx, storeName)).Methods("GET")
37 | r.HandleFunc(fmt.Sprintf("/%s/mykeys/{owner}/{UUID}", storeName), BlzQMyKeysHandler(cliCtx, storeName)).Methods("GET")
38 | }
39 |
--------------------------------------------------------------------------------
/x/crud/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 |
18 |
--------------------------------------------------------------------------------
/x/crud/gas_calculator.go:
--------------------------------------------------------------------------------
1 | package crud
2 |
3 | import "math"
4 |
5 | const (
6 | LeaseGasRateDefaultValue float64 = 1
7 | LeaseGasRateMaximumValue float64 = 3
8 | LeaseGasRateParamB float64 = 2.5
9 | LeaseGasRateParamC float64 = 75
10 | LeaseGasRateParamG float64 = 3
11 | )
12 |
13 | func CalculateGasForLease(lease int64, bytes int) uint64 {
14 | leaseDays := LeaseInDays(lease)
15 | gasRate := leaseGasRatePerByte(leaseDays)
16 | return uint64(math.Round(gasRate * leaseDays * math.Max(float64(bytes), 200000)))
17 | }
18 |
19 | func LeaseInDays(lease int64) float64 {
20 | return (float64(lease) / 24 / 60 / 60) * 5.5
21 | }
22 |
23 | func leaseGasRatePerByte(days float64) float64 {
24 | return LeaseGasRateDefaultValue + (LeaseGasRateMaximumValue-LeaseGasRateDefaultValue)/
25 | math.Pow(1.0+math.Pow(days/LeaseGasRateParamC, LeaseGasRateParamB), LeaseGasRateParamG)
26 | }
27 |
--------------------------------------------------------------------------------
/x/crud/gas_calculator_test.go:
--------------------------------------------------------------------------------
1 | package crud
2 |
3 | import (
4 | "github.com/stretchr/testify/assert"
5 | "math"
6 | "testing"
7 | )
8 |
9 | func daysToLease(days int64) int64 {
10 | return int64(math.Round(float64(days) * (24 * 60 * 60 / 5.5)))
11 | }
12 |
13 |
14 | func TestLeaseGasRatePerByte(t *testing.T) {
15 | assert.Equal(t, leaseGasRatePerByte(0), 3.0)
16 | assert.Equal(t, leaseGasRatePerByte(1), 2.999876836999191)
17 | assert.Equal(t, leaseGasRatePerByte(10), 2.961551101112777)
18 | assert.Equal(t, leaseGasRatePerByte(120), 1.0262720621151311)
19 |
20 |
21 | }
22 |
23 | func TestCalculateGasForLease(t *testing.T) {
24 |
25 | t.Run("Should work for partial day leases", func(t *testing.T) {
26 | assert.InDelta(t, uint64(5997), CalculateGasForLease(157, 20), 3)
27 |
28 | })
29 |
30 | t.Run("Smaller number of bytes should default to 200000 bytes", func(t *testing.T) {
31 | assert.InDelta(t, uint64(599975), CalculateGasForLease(daysToLease(1), 20), 3)
32 | assert.InDelta(t, uint64(599975), CalculateGasForLease(daysToLease(1), 150000), 3)
33 |
34 | defaultBytesGas := CalculateGasForLease(daysToLease(100), 200000)
35 | assert.Equal(t, CalculateGasForLease(daysToLease(100), 100), defaultBytesGas)
36 | })
37 |
38 |
39 | t.Run("Larger data should calculate the correct gas", func(t *testing.T) {
40 | assert.InDelta(t, uint64(2999876837), CalculateGasForLease( daysToLease(1), 1000 * 1000 * 1000), 17359)
41 | assert.Equal(t, uint64(94412671082), CalculateGasForLease(daysToLease(77), 1000 * 1000 * 1000))
42 | })
43 |
44 | t.Run("Larger number of days should calculate correct gas", func(t *testing.T) {
45 | assert.InDelta(t, uint64(17900418), CalculateGasForLease(daysToLease(50), 1), 2)
46 | assert.InDelta(t, uint64(89502092347), CalculateGasForLease(daysToLease(50), 1000000000), 7373)
47 | })
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/x/crud/genesis_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package crud
16 |
17 | import (
18 | "github.com/bluzelle/curium/x/crud/internal/types"
19 | "github.com/stretchr/testify/assert"
20 | "testing"
21 | )
22 |
23 |
24 | func TestValidateGenesis(t *testing.T) {
25 | var blzValues []types.BLZValue
26 |
27 | genesisState := NewGenesisState(blzValues)
28 |
29 | assert.Nil(t, ValidateGenesis(genesisState))
30 |
31 | blzValues = append(blzValues, types.BLZValue{Value: "test", Owner: []byte("notnilowner")})
32 |
33 | assert.Nil(t, ValidateGenesis(genesisState))
34 |
35 | blzValues = append(blzValues, types.BLZValue{Value: "test"})
36 |
37 | assert.Nil(t, ValidateGenesis(genesisState))
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/x/crud/internal/types/codec.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | import (
18 | "github.com/cosmos/cosmos-sdk/codec"
19 | )
20 |
21 | var ModuleCdc = codec.New()
22 |
23 | func init() {
24 | RegisterCodec(ModuleCdc)
25 | }
26 |
27 | func RegisterCodec(cdc *codec.Codec) {
28 | cdc.RegisterConcrete(MsgCount{}, "crud/count", nil)
29 | cdc.RegisterConcrete(MsgCreate{}, "crud/create", nil)
30 | cdc.RegisterConcrete(MsgDeleteAll{}, "crud/deleteall", nil)
31 | cdc.RegisterConcrete(MsgDelete{}, "crud/delete", nil)
32 | cdc.RegisterConcrete(MsgGetLease{}, "crud/getlease", nil)
33 | cdc.RegisterConcrete(MsgGetNShortestLeases{}, "crud/getnshortestleases", nil)
34 | cdc.RegisterConcrete(MsgHas{}, "crud/has", nil)
35 | cdc.RegisterConcrete(MsgKeyValues{}, "crud/keyvalues", nil)
36 | cdc.RegisterConcrete(MsgKeys{}, "crud/keys", nil)
37 | cdc.RegisterConcrete(MsgMultiUpdate{}, "crud/multiupdate", nil)
38 | cdc.RegisterConcrete(MsgRead{}, "crud/read", nil)
39 | cdc.RegisterConcrete(MsgRename{}, "crud/rename", nil)
40 | cdc.RegisterConcrete(MsgRenewLease{}, "crud/renewlease", nil)
41 | cdc.RegisterConcrete(MsgRenewLeaseAll{}, "crud/renewleaseall", nil)
42 | cdc.RegisterConcrete(MsgUpdate{}, "crud/update", nil)
43 | cdc.RegisterConcrete(MsgUpsert{}, "crud/upsert", nil)
44 | }
45 |
--------------------------------------------------------------------------------
/x/crud/internal/types/key.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | const (
18 | // module name
19 | ModuleName = "crud"
20 |
21 | // StoreKey to be used when creating the KVStore
22 | StoreKey = ModuleName
23 | LeaseKey = "crudLease"
24 | OwnerKey = "crudOwner"
25 | )
26 |
--------------------------------------------------------------------------------
/x/crud/internal/types/querier.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | type QueryResultRead struct {
18 | UUID string `json:"uuid"`
19 | Key string `json:"key"`
20 | Value string `json:"value"`
21 | }
22 |
23 | type QueryResultOwner struct {
24 | UUID string `json:"uuid"`
25 | Key string `json:"key"`
26 | Owner string `json:"owner"`
27 | }
28 |
29 | // for fmt.Stringer
30 | func (r QueryResultRead) String() string {
31 | return r.Value
32 | }
33 |
34 | type QueryResultHas struct {
35 | UUID string `json:"uuid"`
36 | Key string `json:"key"`
37 | Has bool `json:"has"`
38 | }
39 |
40 | // for fmt.Stringer
41 | func (r QueryResultHas) String() string {
42 | if r.Has {
43 | return "true"
44 | } else {
45 | return "false"
46 | }
47 | }
48 |
49 | type QueryResultKeys struct {
50 | UUID string `json:"uuid"`
51 | Keys []string `json:"keys"`
52 | }
53 |
54 | type QueryResultKeyValues struct {
55 | UUID string `json:"uuid"`
56 | KeyValues []KeyValue `json:"keyvalues"`
57 | }
58 |
59 | type QueryResultSearch struct {
60 | UUID string `json:"uuid"`
61 | KeyValues []KeyValue `json:"keyvalues"`
62 | }
63 |
64 | type QueryResultCount struct {
65 | UUID string `json:"uuid"`
66 | Count uint64 `json:"count,string"`
67 | }
68 |
69 | type QueryResultLease struct {
70 | UUID string `json:"uuid"`
71 | Key string `json:"key"`
72 | Lease int64 `json:"lease,string"`
73 | }
74 |
75 | type QueryResultNShortestLeaseKeys struct {
76 | UUID string `json:"uuid"`
77 | KeyLeases []KeyLease `json:"keyleases"`
78 | }
79 |
80 | type QueryResultMyKeys struct {
81 | UUID string `json:"uuid"`
82 | Keys []string `json:"keys"`
83 | }
84 |
--------------------------------------------------------------------------------
/x/crud/internal/types/querier_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | import (
18 | "github.com/magiconair/properties/assert"
19 | "testing"
20 | )
21 |
22 | func TestQueryResultRead_String(t *testing.T) {
23 | assert.Equal(t, QueryResultRead{UUID: "uuid", Key: "key", Value: "value"}.String(), "value")
24 | }
25 |
26 | func TestQueryResultHas_String(t *testing.T) {
27 | assert.Equal(t, QueryResultHas{UUID: "uuid", Key: "key", Has: false}.String(), "false")
28 | assert.Equal(t, QueryResultHas{UUID: "uuid", Key: "key", Has: true}.String(), "true")
29 | }
30 |
--------------------------------------------------------------------------------
/x/crud/internal/types/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | import (
18 | "fmt"
19 | cc "github.com/cosmos/cosmos-sdk/codec"
20 | sdk "github.com/cosmos/cosmos-sdk/types"
21 | "strings"
22 | )
23 |
24 | type BLZValue struct {
25 | Value string `json:"value"`
26 | Lease int64 `json:"lease"`
27 | Height int64 `json:"height"`
28 | Owner sdk.AccAddress `json:"owner"`
29 | }
30 |
31 | func (kv BLZValue) Unmarshal(b []byte) BLZValue {
32 | var cdc = cc.New()
33 | value := BLZValue{}
34 | _ = cdc.UnmarshalBinaryBare(b, &value)
35 | return value
36 | }
37 |
38 | func (kv BLZValue) String() string {
39 | if kv.Owner.Empty() {
40 | return strings.TrimSpace(fmt.Sprintf("Value: %s Owner: ", kv.Value))
41 | }
42 | return strings.TrimSpace(fmt.Sprintf("Value: %s Owner: %s", kv.Value, kv.Owner.String()))
43 | }
44 |
45 | type KeyValue struct {
46 | Key string `json:"key"`
47 | Value string `json:"value"`
48 | }
49 |
50 | type KeyLease struct {
51 | Key string `json:"key"`
52 | Lease int64 `json:"lease,string"`
53 | }
54 |
55 | type KeyLeases []KeyLease
56 |
57 | func (a KeyLeases) Len() int { return len(a) }
58 | func (a KeyLeases) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
59 | func (a KeyLeases) Less(i, j int) bool { return a[i].Lease < a[j].Lease }
60 |
--------------------------------------------------------------------------------
/x/crud/internal/types/types_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package types
16 |
17 | import (
18 | cc "github.com/cosmos/cosmos-sdk/codec"
19 | "github.com/stretchr/testify/assert"
20 | "reflect"
21 | "sort"
22 | "testing"
23 | )
24 |
25 | func TestBLZValue_Unmarshal(t *testing.T) {
26 | value := BLZValue{
27 | Value: "value",
28 | Owner: []byte("bluzelle1t0ywtmrduldf6h4wqrnnpyp9wr6law2u5jwa23"),
29 | }
30 |
31 | cdc := cc.New()
32 | b, _ := cdc.MarshalBinaryBare(value)
33 |
34 | resultValue := BLZValue{}
35 |
36 | assert.True(t, reflect.DeepEqual(value, resultValue.Unmarshal(b)))
37 | }
38 |
39 | func TestBLZValue_String(t *testing.T) {
40 | value := BLZValue{
41 | Value: "value",
42 | Owner: []byte("bluzelle1t0ywtmrduldf6h4wqrnnpyp9wr6law2u5jwa23"),
43 | }
44 | assert.Equal(t, value.String(), "Value: value Owner: cosmos1vfk827n9d3kx2vt5xpuhwardwfj82mryvcmxsdrhw9exumns09crjamjxekxzaejw56k5ampxgeslhg4h3")
45 |
46 | value = BLZValue{
47 | Value: "value",
48 | }
49 | assert.Equal(t, value.String(), "Value: value Owner: ")
50 | }
51 |
52 | func TestKeyLeases_Sort(t *testing.T) {
53 | keyLeases := KeyLeases{}
54 | keyLeases = append(keyLeases, KeyLease{
55 | Key: "three",
56 | Lease: 3,
57 | })
58 |
59 | keyLeases = append(keyLeases, KeyLease{
60 | Key: "one",
61 | Lease: 1,
62 | })
63 |
64 | keyLeases = append(keyLeases, KeyLease{
65 | Key: "zero",
66 | Lease: 0,
67 | })
68 |
69 | keyLeases = append(keyLeases, KeyLease{
70 | Key: "two",
71 | Lease: 2,
72 | })
73 |
74 | sort.Sort(keyLeases)
75 |
76 | assert.Equal(t, int64(0), keyLeases[0].Lease)
77 | assert.Equal(t, int64(3), keyLeases[len(keyLeases)-1].Lease)
78 | }
79 |
--------------------------------------------------------------------------------
/x/curium/alias.go:
--------------------------------------------------------------------------------
1 | package curium
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/curium/keeper"
5 | "github.com/bluzelle/curium/x/curium/types"
6 | )
7 |
8 | var (
9 | ModuleName = types.ModuleName
10 | StoreKey = types.StoreKey
11 | MemStoreKey = types.MemStoreKey
12 | NewKeeper = keeper.NewKeeper
13 | NewKeyringReader = keeper.NewKeyringReader
14 | )
15 | type (
16 | Keeper = keeper.Keeper
17 | MsgBroadcaster = keeper.MsgBroadcaster
18 | MsgBroadcasterResponse = keeper.MsgBroadcasterResponse
19 | KeyringReader = keeper.KeyringReader
20 | )
21 |
--------------------------------------------------------------------------------
/x/curium/client/cli/query.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/cosmos/cosmos-sdk/client"
8 | "github.com/cosmos/cosmos-sdk/codec"
9 |
10 | "github.com/bluzelle/curium/x/curium/types"
11 | )
12 |
13 | // GetQueryCmd returns the cli query commands for this module
14 | func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
15 | // Group oracle queries under a subcommand
16 | curiumQueryCmd := &cobra.Command{
17 | Use: types.ModuleName,
18 | Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
19 | DisableFlagParsing: true,
20 | SuggestionsMinimumDistance: 2,
21 | RunE: client.ValidateCmd,
22 | }
23 |
24 | return curiumQueryCmd
25 | }
26 |
27 |
28 |
--------------------------------------------------------------------------------
/x/curium/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/bluzelle/curium/x/curium/types"
8 | "github.com/cosmos/cosmos-sdk/client"
9 | _ "github.com/cosmos/cosmos-sdk/client/context"
10 | "github.com/cosmos/cosmos-sdk/codec"
11 | _ "github.com/cosmos/cosmos-sdk/types"
12 | _ "github.com/cosmos/cosmos-sdk/x/auth"
13 | _ "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
14 | )
15 |
16 | // GetTxCmd returns the transaction commands for this module
17 | func GetTxCmd(cdc *codec.Codec) *cobra.Command {
18 | curiumTxCmd := &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 | return curiumTxCmd
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/x/curium/client/rest/query.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 | import (
18 | "encoding/hex"
19 | "github.com/cosmos/cosmos-sdk/client/context"
20 | "github.com/cosmos/cosmos-sdk/types/rest"
21 | "io/ioutil"
22 | "net/http"
23 | )
24 |
25 |
26 | func AbciQueryHandler(cliCtx context.CLIContext) http.HandlerFunc {
27 |
28 | type queryReq struct {
29 | Path string
30 | Data string
31 | }
32 |
33 | return func(w http.ResponseWriter, r *http.Request) {
34 |
35 | cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
36 | if !ok {
37 | return
38 | }
39 |
40 | var req queryReq
41 |
42 | body, err := ioutil.ReadAll(r.Body)
43 | if err != nil {
44 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
45 | }
46 |
47 | err = cliCtx.Codec.UnmarshalJSON(body, &req)
48 | if err != nil {
49 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
50 | }
51 |
52 | bytes, err := hex.DecodeString(req.Data)
53 | if err != nil {
54 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
55 | }
56 | res, height, err := cliCtx.QueryWithData(req.Path, bytes)
57 | if err != nil {
58 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
59 | }
60 |
61 | cliCtx = cliCtx.WithHeight(height)
62 | rest.PostProcessResponse(w, cliCtx, res)
63 | }
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/x/curium/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 | import (
18 | "github.com/cosmos/cosmos-sdk/client/context"
19 | "github.com/gorilla/mux"
20 | )
21 |
22 | // RegisterRoutes - Central function to define routes that get registered by the main application
23 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
24 | r.HandleFunc("/abci-query", AbciQueryHandler(cliCtx)).Methods("POST")
25 | }
26 |
--------------------------------------------------------------------------------
/x/curium/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 |
18 |
--------------------------------------------------------------------------------
/x/curium/genesis.go:
--------------------------------------------------------------------------------
1 | package curium
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/curium/keeper"
5 | "github.com/bluzelle/curium/x/curium/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // InitGenesis initializes the capability module's state from a provided genesis
10 | // state.
11 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
12 | // this line is used by starport scaffolding # genesis/module/init
13 |
14 | }
15 |
16 | // ExportGenesis returns the capability module's exported genesis.
17 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
18 | genesis := types.DefaultGenesisState()
19 |
20 | return genesis
21 | }
22 |
--------------------------------------------------------------------------------
/x/curium/handler.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package curium
16 |
17 | import (
18 | "fmt"
19 | "github.com/bluzelle/curium/x/curium/keeper"
20 | sdk "github.com/cosmos/cosmos-sdk/types"
21 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
22 | )
23 |
24 | func NewHandler(keeper keeper.Keeper) sdk.Handler {
25 | return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
26 | switch msg := msg.(type) {
27 | default:
28 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, fmt.Sprintf("Unrecognized nft msg type: %v", msg.Type()))
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/x/curium/keeper/AccountInfo.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "github.com/bluzelle/curium/app/accountFetcher/types"
5 | )
6 |
7 | type AccountInfoItem struct {
8 | AccNum uint64
9 | Seq uint64
10 | }
11 |
12 | type AccountInfo struct {
13 | items map[string]AccountInfoItem
14 | acctFetcher types.AccountFetcherFn
15 | }
16 |
17 | func NewAccountInfo(acctFetcher types.AccountFetcherFn) *AccountInfo {
18 | return &AccountInfo{
19 | acctFetcher: acctFetcher,
20 | items: make(map[string]AccountInfoItem),
21 | }
22 | }
23 |
24 | func (ai *AccountInfo) SetAcctInfo(from string, item AccountInfoItem) *AccountInfo {
25 | ai.items[from] = item
26 | return ai
27 | }
28 |
29 | func (ai *AccountInfo) GetAcctInfo(from string) *AccountInfoItem {
30 | val, ok := ai.items[from]
31 | if ok {
32 | return &val
33 | }
34 | return nil
35 | }
36 |
37 | func (ai *AccountInfo) Next(from string) (*AccountInfoItem, error) {
38 | var err error
39 | if ai.Exists(from) {
40 | ai.IncrementSeq(from)
41 | } else {
42 | info, err := ai.acctFetcher(from)
43 | if err != nil {
44 | return nil, err
45 | }
46 | ai.SetAcctInfo(from, AccountInfoItem{
47 | AccNum: info.AccNum,
48 | Seq: info.Seq,
49 | })
50 | }
51 |
52 | return ai.GetAcctInfo(from), err
53 | }
54 |
55 | func (ai *AccountInfo) IncrementSeq(from string) uint64 {
56 | acct := ai.GetAcctInfo(from)
57 | ai.items[from] = AccountInfoItem{
58 | Seq: acct.Seq + 1,
59 | AccNum: acct.AccNum,
60 | }
61 | return acct.Seq + 1
62 | }
63 |
64 | func (ai *AccountInfo) Exists(from string) bool {
65 | return ai.GetAcctInfo(from) != nil
66 | }
67 |
--------------------------------------------------------------------------------
/x/curium/keeper/AccountInfo_test.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "github.com/stretchr/testify/assert"
5 | "testing"
6 | )
7 |
8 | func TestAccountInfo(t *testing.T) {
9 | t.Run("GetAccountInfo()", func(t *testing.T) {
10 | t.Run("should return the account info for a given key", func(t *testing.T) {
11 | info := NewAccountInfo()
12 | info.SetAcctInfo("scott", AccountInfoItem{
13 | Seq: 1,
14 | AccNum: 3,
15 | })
16 | assert.Equal(t, uint64(1), info.GetAcctInfo("scott").Seq)
17 | assert.Equal(t, uint64(3), info.GetAcctInfo("scott").AccNum)
18 | })
19 |
20 | t.Run("should return nil if no account exists", func(t *testing.T) {
21 | info := NewAccountInfo()
22 | assert.Nil(t, info.GetAcctInfo("fake"))
23 | })
24 | })
25 |
26 | t.Run("IncrementSeq()", func(t *testing.T) {
27 | t.Run("should increment the sequence number of an account", func(t *testing.T) {
28 | info := NewAccountInfo()
29 | info.SetAcctInfo("scott", AccountInfoItem{
30 | AccNum: 3,
31 | Seq: 1,
32 | })
33 | info.IncrementSeq("scott")
34 | assert.Equal(t, uint64(3), info.GetAcctInfo("scott").AccNum)
35 | assert.Equal(t, uint64(2), info.GetAcctInfo("scott").Seq)
36 | })
37 | })
38 | }
39 |
--------------------------------------------------------------------------------
/x/curium/keeper/GenesisReader.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/cosmos/cosmos-sdk/client/flags"
6 | "github.com/spf13/viper"
7 | "io/ioutil"
8 | )
9 |
10 | type genesisData struct {
11 | ChainId string `json:"chain_id"`
12 | }
13 |
14 | func readGenesisJson() (*genesisData, error) {
15 | fileName := viper.GetString(flags.FlagHome) + "/config/genesis.json"
16 | bz, err := ioutil.ReadFile(fileName)
17 | if err != nil {
18 | return nil, err
19 | }
20 | var data = genesisData{}
21 | json.Unmarshal(bz, &data)
22 | return &data, nil
23 |
24 | }
25 |
26 | func readChainId() (string, error) {
27 | g, err := readGenesisJson()
28 | if (err != nil) {
29 | return "", err
30 | }
31 | return g.ChainId, nil
32 | }
--------------------------------------------------------------------------------
/x/curium/keeper/MsgBroadcastQueue.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | type MsgBroadcastQueueItem struct {
6 | Msgs []sdk.Msg
7 | From string
8 | RetryCount int
9 | Resp chan *MsgBroadcasterResponse
10 | }
11 |
12 | func (mqi *MsgBroadcastQueueItem) IncrementRetry() {
13 | mqi.RetryCount = mqi.RetryCount + 1
14 | }
15 |
16 | type MsgBroadcastQueue struct {
17 | queue []*MsgBroadcastQueueItem
18 | }
19 |
20 | func NewMsgBroadcastQueue() *MsgBroadcastQueue {
21 | return &MsgBroadcastQueue{}
22 | }
23 |
24 | func (mq *MsgBroadcastQueue) Push(item *MsgBroadcastQueueItem) {
25 | mq.queue = append(mq.queue, item)
26 | }
27 |
28 | func (mq *MsgBroadcastQueue) Size() int {
29 | return len(mq.queue)
30 | }
31 |
32 | func (mq *MsgBroadcastQueue) Pop() *MsgBroadcastQueueItem {
33 | if !mq.IsEmpty() {
34 | item := mq.queue[0]
35 | mq.queue = mq.queue[1:]
36 | return item
37 | }
38 | return nil
39 | }
40 |
41 | func (mq *MsgBroadcastQueue) IsEmpty() bool {
42 | return len(mq.queue) == 0
43 | }
--------------------------------------------------------------------------------
/x/curium/keeper/MsgBroadcastQueue_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/curium/keeper"
5 | "github.com/stretchr/testify/assert"
6 | "testing"
7 | )
8 |
9 | func TestMsgBroadcastQueue(t *testing.T) {
10 | t.Run("IsEmpty()", func(t *testing.T) {
11 | t.Run("should return true if queue is empty", func(t *testing.T) {
12 | assert.True(t, keeper.NewMsgBroadcastQueue().IsEmpty())
13 | })
14 | })
15 |
16 | t.Run("Push()", func(t *testing.T) {
17 | t.Run("should add an item to the queue", func(t *testing.T) {
18 | queue := keeper.NewMsgBroadcastQueue()
19 | queue.Push(&keeper.MsgBroadcastQueueItem{})
20 | assert.Equal(t, 1, queue.Size())
21 | queue.Push(&keeper.MsgBroadcastQueueItem{})
22 | assert.Equal(t, 2, queue.Size())
23 | })
24 | })
25 |
26 | t.Run("Pop()", func(t *testing.T) {
27 | t.Run("should remove the first item from the queue", func(t *testing.T) {
28 | queue := keeper.NewMsgBroadcastQueue()
29 | queue.Push(&keeper.MsgBroadcastQueueItem{
30 | From: "item1",
31 | })
32 | queue.Push(&keeper.MsgBroadcastQueueItem{
33 | From: "item2",
34 | })
35 | queue.Push(&keeper.MsgBroadcastQueueItem{
36 | From: "item3",
37 | })
38 | assert.Equal(t, "item1", queue.Pop().From)
39 | assert.Equal(t, "item2", queue.Pop().From)
40 | assert.Equal(t, "item3", queue.Pop().From)
41 | assert.Nil(t, queue.Pop())
42 | })
43 | })
44 | }
45 |
--------------------------------------------------------------------------------
/x/curium/keeper/querier.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | // this line is used by starport scaffolding # 1
5 | abci "github.com/tendermint/tendermint/abci/types"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
9 | )
10 |
11 | // NewQuerier creates a new querier for curium clients.
12 | func NewQuerier(k Keeper) sdk.Querier {
13 | return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
14 | switch path[0] {
15 | default:
16 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown curium query endpoint")
17 | }
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/x/curium/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | )
6 |
7 | // RegisterCodec registers concrete types on codec
8 | func RegisterCodec(cdc *codec.Codec) {
9 |
10 | }
11 |
12 | // ModuleCdc defines the module codec
13 | var ModuleCdc *codec.Codec
14 |
15 | func init() {
16 | ModuleCdc = codec.New()
17 | RegisterCodec(ModuleCdc)
18 | codec.RegisterCrypto(ModuleCdc)
19 | ModuleCdc.Seal()
20 | }
21 |
--------------------------------------------------------------------------------
/x/curium/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type GenesisState struct {
4 | }
5 |
6 | // DefaultIndex is the default capability global index
7 | const DefaultIndex uint64 = 1
8 |
9 | // DefaultGenesisState returns the default Capability genesis state
10 | func DefaultGenesisState() *GenesisState {
11 | return &GenesisState{
12 | }
13 | }
14 |
15 | // ValidateGenesis performs basic genesis state validation returning an error upon any
16 | // failure.
17 | func (gs GenesisState) ValidateGenesis() error {
18 |
19 | return nil
20 | }
21 |
--------------------------------------------------------------------------------
/x/curium/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName defines the module name
5 | ModuleName = "curium"
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_capability"
18 | )
19 |
--------------------------------------------------------------------------------
/x/curium/types/types.go:
--------------------------------------------------------------------------------
1 | package types
--------------------------------------------------------------------------------
/x/nft/alias.go:
--------------------------------------------------------------------------------
1 | package nft
2 |
3 | import (
4 | keeper "github.com/bluzelle/curium/x/nft/keeper"
5 | types "github.com/bluzelle/curium/x/nft/types"
6 | )
7 |
8 | var (
9 | ModuleName = types.ModuleName
10 | StoreKey = types.StoreKey
11 | MemStoreKey = types.MemStoreKey
12 | NewKeeper = keeper.NewKeeper
13 |
14 | )
15 | type (
16 | Keeper = keeper.Keeper
17 | )
18 |
--------------------------------------------------------------------------------
/x/nft/client/cli/query.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/cosmos/cosmos-sdk/client"
8 | "github.com/cosmos/cosmos-sdk/codec"
9 |
10 | "github.com/bluzelle/curium/x/oracle/types"
11 | )
12 |
13 | // GetQueryCmd returns the cli query commands for this module
14 | func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
15 | // Group oracle queries under a subcommand
16 | nftQueryCmd := &cobra.Command{
17 | Use: types.ModuleName,
18 | Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
19 | DisableFlagParsing: true,
20 | SuggestionsMinimumDistance: 2,
21 | RunE: client.ValidateCmd,
22 | }
23 |
24 | return nftQueryCmd
25 | }
26 |
27 |
28 |
--------------------------------------------------------------------------------
/x/nft/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/cobra"
6 |
7 | "github.com/bluzelle/curium/x/oracle/types"
8 | "github.com/cosmos/cosmos-sdk/client"
9 | _ "github.com/cosmos/cosmos-sdk/client/context"
10 | "github.com/cosmos/cosmos-sdk/codec"
11 | _ "github.com/cosmos/cosmos-sdk/types"
12 | _ "github.com/cosmos/cosmos-sdk/x/auth"
13 | _ "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
14 | )
15 |
16 | // GetTxCmd returns the transaction commands for this module
17 | func GetTxCmd(cdc *codec.Codec) *cobra.Command {
18 | nftTxCmd := &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 | return nftTxCmd
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/x/nft/client/rest/getNftByVendorHandler.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/cosmos/cosmos-sdk/client/context"
6 | "github.com/cosmos/cosmos-sdk/types/rest"
7 | "github.com/gorilla/mux"
8 | "io"
9 | "io/ioutil"
10 | "net/http"
11 | "os"
12 |
13 | )
14 |
15 | func getNftByVendorHandler(clientCtx context.CLIContext) http.HandlerFunc {
16 | return func(w http.ResponseWriter, r *http.Request) {
17 | id := mux.Vars(r)["id"]
18 | vendor := mux.Vars(r)["vendor"]
19 | nftDirRes, _, err := clientCtx.Query("custom/nft/get-nft-dir")
20 |
21 | nftDir := string(nftDirRes)
22 | filename := vendor + "-" + id
23 |
24 | location := nftDir + "/" + filename
25 | infoLocation := nftDir + "/" + filename + ".info"
26 | if _, err := os.Stat(location); os.IsNotExist(err) {
27 | rest.WriteErrorResponse(w, http.StatusNotFound, "File does not exist")
28 | return
29 | }
30 |
31 | if _, err := os.Stat(infoLocation); os.IsNotExist(err) {
32 | rest.WriteErrorResponse(w, http.StatusNotFound, "File information does not exist")
33 | return
34 | }
35 |
36 |
37 | var info map[string]interface{}
38 |
39 | infoBytes, err := ioutil.ReadFile(infoLocation)
40 | if err != nil {
41 | rest.WriteErrorResponse(w, http.StatusNotFound, "Unable to read info file")
42 | }
43 |
44 | json.Unmarshal(infoBytes, &info)
45 |
46 | w.Header().Set("content-type", info["Mime"].(string))
47 |
48 | reader, err := os.Open(location)
49 | if err != nil {
50 | rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
51 | return
52 | }
53 | io.Copy(w, reader)
54 | }
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/x/nft/client/rest/getNftHandler.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/cosmos/cosmos-sdk/client/context"
6 | "github.com/cosmos/cosmos-sdk/types/rest"
7 | "github.com/gorilla/mux"
8 | "io"
9 | "io/ioutil"
10 | "net/http"
11 | "os"
12 | )
13 | func getNftHandler(clientCtx context.CLIContext) http.HandlerFunc {
14 | return func(w http.ResponseWriter, r *http.Request) {
15 | hash := mux.Vars(r)["hash"]
16 |
17 | nftDirRes, _, err := clientCtx.Query("custom/nft/get-nft-dir")
18 |
19 | nftDir := string(nftDirRes)
20 |
21 | location := nftDir + "/" + hash
22 | infoLocation := nftDir + "/" + hash + ".info"
23 | if _, err := os.Stat(location); os.IsNotExist(err) {
24 | rest.WriteErrorResponse(w, http.StatusNotFound, hash)
25 | rest.WriteErrorResponse(w, http.StatusNotFound, "File does not exist")
26 | return
27 | }
28 |
29 | if _, err := os.Stat(infoLocation); os.IsNotExist(err) {
30 | rest.WriteErrorResponse(w, http.StatusNotFound, "File information does not exist")
31 | return
32 | }
33 |
34 |
35 | var info map[string]interface{}
36 |
37 | infoBytes, err := ioutil.ReadFile(infoLocation)
38 | if err != nil {
39 | rest.WriteErrorResponse(w, http.StatusNotFound, "Unable to read info file")
40 | }
41 |
42 | json.Unmarshal(infoBytes, &info)
43 |
44 | w.Header().Set("content-type", info["Mime"].(string))
45 |
46 | reader, err := os.Open(location)
47 | if err != nil {
48 | rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
49 | return
50 | }
51 | io.Copy(w, reader)
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/x/nft/client/rest/query.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 | import (
18 | "encoding/hex"
19 | "github.com/cosmos/cosmos-sdk/client/context"
20 | "github.com/cosmos/cosmos-sdk/types/rest"
21 | "io/ioutil"
22 | "net/http"
23 | )
24 |
25 |
26 | func AbciQueryHandler(cliCtx context.CLIContext) http.HandlerFunc {
27 |
28 | type queryReq struct {
29 | Path string
30 | Data string
31 | }
32 |
33 | return func(w http.ResponseWriter, r *http.Request) {
34 |
35 | cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
36 | if !ok {
37 | return
38 | }
39 |
40 | var req queryReq
41 |
42 | body, err := ioutil.ReadAll(r.Body)
43 | if err != nil {
44 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
45 | }
46 |
47 | err = cliCtx.Codec.UnmarshalJSON(body, &req)
48 | if err != nil {
49 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
50 | }
51 |
52 | bytes, err := hex.DecodeString(req.Data)
53 | if err != nil {
54 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
55 | }
56 | res, height, err := cliCtx.QueryWithData(req.Path, bytes)
57 | if err != nil {
58 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
59 | }
60 |
61 | cliCtx = cliCtx.WithHeight(height)
62 | rest.PostProcessResponse(w, cliCtx, res)
63 | }
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/x/nft/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 | import (
18 | "github.com/cosmos/cosmos-sdk/client/context"
19 | "github.com/gorilla/mux"
20 | )
21 |
22 | // RegisterRoutes - Central function to define routes that get registered by the main application
23 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
24 | r.HandleFunc("/abci-query", AbciQueryHandler(cliCtx)).Methods("POST")
25 | r.HandleFunc("/nft/upload/{vendor}/{hash}/{chunkNum}", uploadNftHandler(cliCtx)).Methods("POST")
26 | r.HandleFunc("/nft/{hash}", getNftHandler(cliCtx)).Methods("GET")
27 | r.HandleFunc("/nft/{vendor}/{id}", getNftByVendorHandler(cliCtx)).Methods("GET")
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/x/nft/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2020 Bluzelle
2 | //
3 | // This program is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU Affero General Public License, version 3,
5 | // as published by the Free Software Foundation.
6 | //
7 | // This program is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU Affero General Public License for more details.
11 | //
12 | // You should have received a copy of the GNU Affero General Public License
13 | // along with this program. If not, see .
14 |
15 | package rest
16 |
17 |
18 |
--------------------------------------------------------------------------------
/x/nft/client/rest/uploadNftHandler.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "fmt"
5 | "github.com/bluzelle/curium/x/nft/keeper"
6 | "github.com/bluzelle/curium/x/nft/types"
7 | "github.com/cosmos/cosmos-sdk/client/context"
8 | "github.com/cosmos/cosmos-sdk/types/rest"
9 | "github.com/ethereum/go-ethereum/common/math"
10 | "github.com/gorilla/mux"
11 | "io"
12 | "net/http"
13 | "os"
14 | "strings"
15 | )
16 | func uploadNftHandler(clientCtx context.CLIContext) http.HandlerFunc {
17 | return func(w http.ResponseWriter, r *http.Request) {
18 | hash := mux.Vars(r)["hash"]
19 | chunkNum := mux.Vars(r)["chunkNum"]
20 | vendor := mux.Vars(r)["vendor"]
21 | auth := r.Header.Get("Authorization")
22 |
23 | token := strings.Split(auth, " ")[1]
24 |
25 | bz, _, err := clientCtx.QueryWithData("custom/nft/is-auth-valid", []byte(token))
26 | var isValid bool
27 | clientCtx.Codec.MustUnmarshalJSON(bz, &isValid)
28 |
29 | if err != nil {
30 | rest.WriteErrorResponse(w, http.StatusBadRequest, "unable to read chunk number")
31 | return
32 | }
33 |
34 | if !isValid {
35 | rest.WriteErrorResponse(w, http.StatusForbidden, "auth invalid")
36 | return
37 | }
38 |
39 |
40 | uploadDirRes, _, err := clientCtx.Query("custom/nft/get-nft-upload-dir")
41 |
42 | uploadDir := string(uploadDirRes)
43 |
44 | uploadPath := uploadDir + "/" + vendor
45 |
46 | os.MkdirAll(uploadPath, os.ModePerm)
47 |
48 | chunkInt, ok := math.ParseUint64(chunkNum)
49 | if !ok {
50 | rest.WriteErrorResponse(w, http.StatusBadRequest, "unable to read chunk number")
51 | return
52 | }
53 | filename := fmt.Sprintf("%s/%s-%04d", uploadPath, hash, chunkInt)
54 | fileWriter, err := os.Create(filename)
55 | defer fileWriter.Close()
56 | if err != nil {
57 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
58 | return
59 | }
60 | io.Copy(fileWriter, r.Body)
61 | w.Write([]byte("ok"))
62 |
63 | checkUploadCompleteReq := types.QueryCheckUploadCompleteReq{
64 | Hash: hash,
65 | Size: uint64(r.ContentLength),
66 | }
67 |
68 | bz, err = clientCtx.Codec.MarshalBinaryBare(&checkUploadCompleteReq)
69 | if err != nil {
70 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
71 | return
72 | }
73 |
74 | bz, _, err = clientCtx.QueryWithData("custom/nft/" + keeper.QueryCheckUploadComplete, bz)
75 |
76 | if err != nil {
77 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
78 | return
79 | }
80 | }
81 | }
82 |
83 |
84 |
--------------------------------------------------------------------------------
/x/nft/demo/demo.ts:
--------------------------------------------------------------------------------
1 | import {bluzelle, uploadNft} from "bluzelle";
2 | import {sha256} from "js-sha256";
3 | import {readFile} from 'fs/promises'
4 |
5 | process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = '0';
6 |
7 | readFile(`${__dirname}/image.jpg`)
8 | .then(data => ({
9 | bz: bluzelle({
10 | mnemonic: "mnemonic provided by bluzelle",
11 | endpoint: 'https://client.sentry.bluzellenet.bluzelle.com:1317',
12 | uuid: ''
13 | }),
14 | data,
15 | id: 'any-id-1'
16 | }))
17 | .then(ctx => ({...ctx, hash: sha256(ctx.data)}))
18 | .then(ctx =>
19 | ctx.bz.createNft({
20 | id: ctx.id,
21 | hash: ctx.hash,
22 | vendor: 'provided_by_bluzelle', // replace with your id provided to you by Bluzelle
23 | userId: 'user-id',
24 | mime: 'image/jpeg',
25 | meta: 'meta',
26 | size: ctx.data.byteLength,
27 | gasInfo: {max_gas: 100_000_000, gas_price: 0.002}
28 | })
29 | .then(resp => ({...ctx, token: resp.token}))
30 | )
31 | .then(
32 | ctx => uploadNft(ctx.bz.url, ctx.data, ctx.token, 'provided_by_bluzelle')
33 | .then(() => ctx)
34 | ).then(ctx => console.log('HASH:',ctx.hash))
35 | .catch(e => console.log('ERROR:', e))
36 |
37 | /*************************************
38 | * To use this code
39 | *
40 | * 1) obtain a mnemonic from Bluzelle and insert into the mnemonic field above
41 | * 3) run this code
42 | * 4) open https://client.sentry.testnet.public.bluzelle.com:1317/nft/customer/any-id-3 in a browser to see the result
43 | * 5) to verify replication go to https://[x].client.sentry.bluzellenet.bluzelle.com:1317/nft/[customer]/any-id-1
44 | * replacing x with 'a', 'b' or 'c'
45 | *
46 | * Feel free to change any of the fields above, especially the content of the file (the 'data' field), the id or the 'vendor'.
47 | * The max size of the data field is 100MB.
48 | */
--------------------------------------------------------------------------------
/x/nft/demo/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bluzelle/curium/78dfebcb9eec9445edbf40af11c4239a374c2ce1/x/nft/demo/image.jpg
--------------------------------------------------------------------------------
/x/nft/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "@types/node": "^16.7.6",
8 | "bluzelle": "^3.0.9",
9 | "js-sha256": "^0.9.0",
10 | "ts-node": "^10.2.1",
11 | "typescript": "^4.4.2"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/x/nft/genesis.go:
--------------------------------------------------------------------------------
1 | package nft
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/nft/keeper"
5 | "github.com/bluzelle/curium/x/nft/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // InitGenesis initializes the capability module's state from a provided genesis
10 | // state.
11 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
12 | // this line is used by starport scaffolding # genesis/module/init
13 | // Set all the nft
14 | for _, elem := range genState.NftList {
15 | k.SetNft(ctx, *elem)
16 | }
17 |
18 | // this line is used by starport scaffolding # ibc/genesis/init
19 | }
20 |
21 | // ExportGenesis returns the capability module's exported genesis.
22 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
23 | genesis := types.DefaultGenesisState()
24 |
25 | // this line is used by starport scaffolding # genesis/module/export
26 | // Get all nft
27 | nftList := k.GetAllNft(ctx)
28 | for _, elem := range nftList {
29 | elem := elem
30 | genesis.NftList = append(genesis.NftList, &elem)
31 | }
32 |
33 | // this line is used by starport scaffolding # ibc/genesis/export
34 |
35 | return genesis
36 | }
37 |
--------------------------------------------------------------------------------
/x/nft/keeper/createNft.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 | "github.com/anacrolix/torrent/metainfo"
6 | "github.com/bluzelle/curium/x/nft/types"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/zeebo/bencode"
9 | "io/ioutil"
10 | "os"
11 | "path/filepath"
12 | "regexp"
13 | )
14 |
15 |
16 |
17 | func (k Keeper) SeedFile(metainfo *metainfo.MetaInfo) error {
18 | err := k.GetBtClient().SeedFile(metainfo)
19 | if err != nil {
20 | return err
21 | }
22 | return nil
23 | }
24 |
25 | func (k Keeper) BroadcastPublishFile(ctx sdk.Context, id string, vendor string, userId string, hash string, mime string, metainfo *metainfo.MetaInfo) error{
26 | metaBytes, err := bencode.EncodeBytes(metainfo)
27 | if err != nil {
28 | return err
29 | }
30 |
31 | addr, err := k.KeyringReader.GetAddress(k.NftUsername)
32 | if err != nil {
33 | return err
34 | }
35 |
36 | publishMsg := types.MsgPublishFile{
37 | Creator: addr.String(),
38 | Id: id,
39 | Vendor: vendor,
40 | Metainfo: metaBytes,
41 | }
42 |
43 | result := <- k.MsgBroadcaster([]sdk.Msg{&publishMsg}, k.NftUsername)
44 | if result.Error != nil {
45 | return result.Error
46 | }
47 | return nil
48 |
49 | }
50 |
51 |
52 | func (k Keeper) AssembleNftFile(uploadDir string, nftDir string, hash string) error {
53 |
54 | uploadRegEx, err := regexp.Compile(fmt.Sprintf("^%s-", hash))
55 | if err != nil {
56 | return err
57 | }
58 |
59 | // Delete upload file if already exists in nft dir and stop
60 | _, err = os.Stat(nftDir + "/" + hash)
61 |
62 | if err == nil {
63 | walkError := filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error {
64 | if err == nil && uploadRegEx.MatchString(info.Name()) {
65 | err = os.Remove(path)
66 | if err != nil {
67 | return err
68 | }
69 | }
70 | return nil
71 | })
72 |
73 | if walkError != nil {
74 | return walkError
75 | }
76 |
77 | return nil
78 | }
79 |
80 | err = filepath.Walk(uploadDir, func(path string, info os.FileInfo, err error) error {
81 | if err == nil && uploadRegEx.MatchString(info.Name()) {
82 | fmt.Println(path)
83 | if path != uploadDir {
84 | data, err := ioutil.ReadFile(path)
85 | if err != nil {
86 | return err
87 | }
88 | err = os.MkdirAll(nftDir, 0755)
89 | if err != nil {
90 | return err
91 | }
92 | f, err := os.OpenFile(nftDir+"/"+hash, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0744)
93 | if err != nil {
94 | return err
95 | }
96 | defer f.Close()
97 | _, err = f.Write(data)
98 | if err != nil {
99 | return err
100 | }
101 | err = os.Remove(path)
102 | if err != nil {
103 | return err
104 | }
105 | }
106 | }
107 | return nil
108 | })
109 | if err != nil {
110 | return err
111 | }
112 | return nil
113 | }
--------------------------------------------------------------------------------
/x/nft/keeper/nft.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/nft/types"
5 | "github.com/cosmos/cosmos-sdk/store/prefix"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // AppendNft appends a nft in the store with a new id and update the count
10 | func (k Keeper) AppendNft(
11 | ctx sdk.Context,
12 | creator string,
13 | id string,
14 | hash string,
15 | vendor string,
16 | userId string,
17 | meta string,
18 | mime string,
19 | size uint64,
20 | ) {
21 | // Create the nft
22 | var nft = types.Nft{
23 | Creator: creator,
24 | Id: id,
25 | Vendor: vendor,
26 | UserId: userId,
27 | Hash: hash,
28 | Meta: meta,
29 | Mime: mime,
30 | Size: size,
31 | }
32 |
33 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
34 | value := k.Cdc.MustMarshalBinaryBare(&nft)
35 | store.Set(GetNftHashBytes(nft.Hash), value)
36 | }
37 |
38 | // SetNft set a specific nft in the store
39 | func (k Keeper) SetNft(ctx sdk.Context, nft types.Nft) {
40 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
41 | b := k.Cdc.MustMarshalBinaryBare(&nft)
42 | store.Set(GetNftHashBytes(nft.Hash), b)
43 | }
44 |
45 | func (k Keeper) GetNft(ctx sdk.Context, hash string) types.Nft {
46 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
47 | var nft types.Nft
48 | k.Cdc.MustUnmarshalBinaryBare(store.Get(GetNftHashBytes(hash)), &nft)
49 | return nft
50 | }
51 |
52 | // HasNft checks if the nft exists in the store
53 | func (k Keeper) HasNft(ctx sdk.Context, hash string) bool {
54 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
55 | return store.Has(GetNftHashBytes(hash))
56 | }
57 |
58 | // GetNftOwner returns the creator of the nft
59 | func (k Keeper) GetNftOwner(ctx sdk.Context, hash string) string {
60 | return k.GetNft(ctx, hash).Creator
61 | }
62 |
63 | // RemoveNft removes a nft from the store
64 | func (k Keeper) RemoveNft(ctx sdk.Context, hash string) {
65 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
66 | store.Delete(GetNftHashBytes(hash))
67 | }
68 |
69 | // GetAllNft returns all nft
70 | func (k Keeper) GetAllNft(ctx sdk.Context) (list []types.Nft) {
71 | store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.NftKey))
72 | iterator := sdk.KVStorePrefixIterator(store, []byte{})
73 |
74 | defer iterator.Close()
75 |
76 | for ; iterator.Valid(); iterator.Next() {
77 | var val types.Nft
78 | k.Cdc.MustUnmarshalBinaryBare(iterator.Value(), &val)
79 | list = append(list, val)
80 | }
81 |
82 | return
83 | }
84 |
85 | func GetNftHashBytes(hash string) []byte {
86 | return []byte(hash)
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/x/nft/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | )
6 |
7 | // RegisterCodec registers concrete types on codec
8 | func RegisterCodec(cdc *codec.Codec) {
9 | // this line is used by starport scaffolding # 1
10 | cdc.RegisterConcrete(&MsgCreateNft{}, "nft/CreateNft", nil)
11 | cdc.RegisterConcrete(&MsgPublishFile{}, "nft/PublishFile", nil)
12 | cdc.RegisterConcrete(&MsgRegisterPeer{}, "nft/RegisterPeer", nil)
13 | }
14 |
15 | // ModuleCdc defines the module codec
16 | var ModuleCdc *codec.Codec
17 |
18 | func init() {
19 | ModuleCdc = codec.New()
20 | RegisterCodec(ModuleCdc)
21 | codec.RegisterCrypto(ModuleCdc)
22 | ModuleCdc.Seal()
23 | }
24 |
--------------------------------------------------------------------------------
/x/nft/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import "fmt"
4 |
5 | type GenesisState struct {
6 | NftList []*Nft
7 | }
8 |
9 | // DefaultIndex is the default capability global index
10 | const DefaultIndex uint64 = 1
11 |
12 | // DefaultGenesisState returns the default Capability genesis state
13 | func DefaultGenesisState() *GenesisState {
14 | return &GenesisState{
15 | // this line is used by starport scaffolding # ibc/genesistype/default
16 | // this line is used by starport scaffolding # genesis/types/default
17 | NftList: []*Nft{},
18 | }
19 | }
20 |
21 | // ValidateGenesis performs basic genesis state validation returning an error upon any
22 | // failure.
23 | func (gs GenesisState) ValidateGenesis() error {
24 |
25 | // this line is used by starport scaffolding # genesis/types/validate
26 | // Check for duplicated ID in nft
27 | nftIdMap := make(map[string]bool)
28 |
29 | for _, elem := range gs.NftList {
30 | if _, ok := nftIdMap[elem.Id]; ok {
31 | return fmt.Errorf("duplicated id for nft")
32 | }
33 | nftIdMap[elem.Id] = true
34 | }
35 |
36 | return nil
37 | }
38 |
--------------------------------------------------------------------------------
/x/nft/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName defines the module name
5 | ModuleName = "nft"
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_capability"
18 |
19 | // this line is used by starport scaffolding # ibc/keys/name
20 | )
21 |
22 | // this line is used by starport scaffolding # ibc/keys/port
23 |
24 | func KeyPrefix(p string) []byte {
25 | return []byte(p)
26 | }
27 |
28 | const (
29 | NftKey = "Nft-"
30 | FileKey = "file-"
31 | PeerKey = "peer-"
32 | )
33 |
--------------------------------------------------------------------------------
/x/nft/types/msgCreateNft.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 UPLOAD_MAX_SIZE = uint64(150)
9 |
10 |
11 | type MsgCreateNft struct {
12 | Id string
13 | Hash string
14 | Vendor string
15 | UserId string
16 | Creator string
17 | Mime string
18 | Meta string
19 | Size uint64
20 | }
21 |
22 | type MsgCreateNftResponse struct {
23 | Id string `json:"id"`
24 | Token string `json:"token"`
25 | }
26 |
27 |
28 | func (msg *MsgCreateNft) Route() string {
29 | return RouterKey
30 | }
31 |
32 | func (msg *MsgCreateNft) Type() string {
33 | return "CreateNft"
34 | }
35 |
36 | func (msg *MsgCreateNft) GetSigners() []sdk.AccAddress {
37 | creator, err := sdk.AccAddressFromBech32(msg.Creator)
38 | if err != nil {
39 | panic(err)
40 | }
41 | return []sdk.AccAddress{creator}
42 | }
43 |
44 | func (msg *MsgCreateNft) GetSignBytes() []byte {
45 | bz := ModuleCdc.MustMarshalJSON(msg)
46 | return sdk.MustSortJSON(bz)
47 | }
48 |
49 | func (msg *MsgCreateNft) ValidateBasic() error {
50 | _, err := sdk.AccAddressFromBech32(msg.Creator)
51 | if err != nil {
52 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
53 | }
54 |
55 | if msg.Size > UPLOAD_MAX_SIZE * 1024 * 1024 {
56 | return sdkerrors.New("nft", 2, "upload too large")
57 | }
58 |
59 | return nil
60 | }
--------------------------------------------------------------------------------
/x/nft/types/msgPublishFile.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/anacrolix/torrent/metainfo"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
7 | "github.com/zeebo/bencode"
8 | )
9 |
10 | type MsgPublishFile struct {
11 | Creator string `json:"creator,omitempty"`
12 | Id string `json:"id,omitempty"`
13 | Vendor string `json:"vendor,omitempty"`
14 | Metainfo []byte `json:"metainfo,omitempty"`
15 | }
16 |
17 | type MsgPublishFileResponse struct {
18 |
19 | }
20 |
21 | func (msg *MsgPublishFile) Route() string {
22 | return RouterKey
23 | }
24 |
25 | func (msg *MsgPublishFile) Type() string {
26 | return "PublishFile"
27 | }
28 |
29 | func (msg *MsgPublishFile) GetSigners() []sdk.AccAddress {
30 | creator, err := sdk.AccAddressFromBech32(msg.Creator)
31 | if err != nil {
32 | panic(err)
33 | }
34 | return []sdk.AccAddress{creator}
35 | }
36 |
37 | func (msg *MsgPublishFile) GetSignBytes() []byte {
38 | bz := ModuleCdc.MustMarshalJSON(msg)
39 | return sdk.MustSortJSON(bz)
40 | }
41 |
42 | func (msg *MsgPublishFile) ValidateBasic() error {
43 | _, err := sdk.AccAddressFromBech32(msg.Creator)
44 | if err != nil {
45 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
46 | }
47 |
48 | var metaInfo metainfo.MetaInfo
49 | err = bencode.DecodeBytes(msg.Metainfo, &metaInfo)
50 | if err != nil {
51 | return err
52 | }
53 |
54 | if len(metaInfo.Announce) > 0 ||
55 | metaInfo.AnnounceList != nil ||
56 | metaInfo.Nodes != nil ||
57 | metaInfo.UrlList != nil {
58 | return sdkerrors.New("nft", 2, "Invalid torrent metainfo in publish")
59 | }
60 |
61 | return nil
62 | }
63 |
--------------------------------------------------------------------------------
/x/nft/types/msgRegisterPeer.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 | type MsgRegisterPeer struct {
9 | Creator string `json:"creator,omitempty"`
10 | Id string `json:"id,omitempty"`
11 | Address string `json:"address,omitempty"`
12 | Port uint64 `json:"port,omitempty"`
13 | }
14 |
15 | type MsgRegisterPeerResponse struct {
16 |
17 | }
18 |
19 | func (msg *MsgRegisterPeer) Route() string {
20 | return RouterKey
21 | }
22 |
23 | func (msg *MsgRegisterPeer) Type() string {
24 | return "RegisterPeer"
25 | }
26 |
27 | func (msg *MsgRegisterPeer) GetSigners() []sdk.AccAddress {
28 | creator, err := sdk.AccAddressFromBech32(msg.Creator)
29 | if err != nil {
30 | panic(err)
31 | }
32 | return []sdk.AccAddress{creator}
33 | }
34 |
35 | func (msg *MsgRegisterPeer) GetSignBytes() []byte {
36 | bz := ModuleCdc.MustMarshalJSON(msg)
37 | return sdk.MustSortJSON(bz)
38 | }
39 |
40 | func (msg *MsgRegisterPeer) ValidateBasic() error {
41 | _, err := sdk.AccAddressFromBech32(msg.Creator)
42 | if err != nil {
43 | return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err)
44 | }
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/x/nft/types/nft.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type Nft struct {
4 | Creator string
5 | Id string
6 | Vendor string
7 | UserId string
8 | Hash string
9 | Mime string
10 | Meta string
11 | Size uint64
12 | }
13 |
14 | type NftInfo struct {
15 | Id string
16 | Vendor string
17 | UserId string
18 | Mime string
19 | Size uint64
20 | }
21 |
--------------------------------------------------------------------------------
/x/nft/types/peer.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type Peer struct {
4 | Id string `json:"id,omitempty"`
5 | Address string `json:"address,omitempty"`
6 | Port uint64 `json:"port,omitempty"`
7 | }
8 |
--------------------------------------------------------------------------------
/x/nft/types/querier.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | type QueryResultGetNft struct {
4 | Nft *Nft `json:"Nft,omitempty"`
5 | }
6 |
7 | type QueryCheckUploadCompleteReq struct {
8 | Hash string `json:"hash"`
9 | Size uint64 `json:"size"`
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/x/nft/types/uploadTokenManager.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/types"
5 | "sync"
6 | )
7 |
8 | type UploadToken struct {
9 | Value string
10 | Hash string
11 | Size uint64
12 | Uploaded uint64
13 | Owner types.AccAddress
14 | ExpireBlock int64
15 | }
16 |
17 | type UploadTokenManager struct {
18 | Tokens sync.Map
19 | }
20 |
21 |
22 |
23 | func NewUploadTokenManager() *UploadTokenManager {
24 | return &UploadTokenManager{}
25 | }
26 |
27 | func (tt *UploadTokenManager) ExpireTokens(block int64) []*UploadToken {
28 | var expiredTokens []*UploadToken
29 | tt.Tokens.Range(func (hash interface{}, token interface{}) bool {
30 | if token.(*UploadToken).ExpireBlock <= block {
31 | tt.Tokens.Delete(hash)
32 | expiredTokens = append(expiredTokens, token.(*UploadToken))
33 | }
34 | return true
35 | })
36 | return expiredTokens
37 | }
38 |
39 | func (tt *UploadTokenManager) InvalidateToken(hash string) {
40 | tt.Tokens.Delete(hash)
41 | }
42 |
43 | func (tt *UploadTokenManager) ReportUpload(hash string, size uint64) {
44 | token := tt.GetToken(hash)
45 | if token != nil {
46 | token.Uploaded = token.Uploaded + size
47 | }
48 | }
49 |
50 | func (tt *UploadTokenManager) IsUploadComplete(hash string) bool {
51 | token := tt.GetToken(hash)
52 | if token == nil {
53 | return true
54 | }
55 | if token.Uploaded >= token.Size {
56 | tt.InvalidateToken(hash)
57 | return true
58 | }
59 | return false
60 | }
61 |
62 | func (tt *UploadTokenManager) GetToken(hash string) *UploadToken {
63 | token, ok := tt.Tokens.Load(hash)
64 | if ok {
65 | return token.(*UploadToken)
66 | }
67 | return nil
68 | }
69 |
70 | func (tt *UploadTokenManager) IsTokenValid(hash string) bool {
71 | return tt.GetToken(hash) != nil
72 | }
73 |
74 | func (tt *UploadTokenManager) NewUploadToken(hash string, size uint64, owner types.AccAddress, expire int64) *UploadToken {
75 | token := &UploadToken{
76 | Value: hash,
77 | Hash: hash,
78 | Size: size,
79 | Owner: owner,
80 | ExpireBlock: expire,
81 | }
82 | tt.Tokens.Store(hash, token)
83 | return token
84 | }
85 |
--------------------------------------------------------------------------------
/x/nft/types/uploadTokenManager_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/stretchr/testify/assert"
5 | "testing"
6 | )
7 |
8 | func Test(t *testing.T) {
9 | t.Run("NewUploadToken()", func(t *testing.T) {
10 | t.Run("Should create a new token with a value", func(t *testing.T) {
11 | manager := NewUploadTokenManager()
12 | token := manager.NewUploadToken("my-hash", uint64(1000), nil, int64(1))
13 | assert.Equal(t, 48, len(token.Value))
14 | assert.Equal(t, "my-hash", token.Hash)
15 | assert.Equal(t, uint64(1000), token.Size)
16 | })
17 | })
18 |
19 | t.Run("Should expire tokens given a block greater than the expiry", func(t *testing.T) {
20 | manager := NewUploadTokenManager()
21 | manager.NewUploadToken("hash1", 1000, nil, int64(5))
22 | manager.NewUploadToken("hash2", 1000, nil, int64(10))
23 |
24 | manager.ExpireTokens(4)
25 | assert.True(t, manager.IsTokenValid("hash1"))
26 | assert.True(t, manager.IsTokenValid("hash2"))
27 |
28 | manager.ExpireTokens(5)
29 | assert.False(t, manager.IsTokenValid("hash1"))
30 | assert.True(t, manager.IsTokenValid("hash2"))
31 |
32 | manager.ExpireTokens(11)
33 | assert.False(t, manager.IsTokenValid("hash1"))
34 | assert.False(t, manager.IsTokenValid("hash2"))
35 | })
36 |
37 | t.Run("InvalidateTokens()", func(t *testing.T) {
38 | t.Run("Should invalidate a token", func(t *testing.T) {
39 | manager := NewUploadTokenManager()
40 | manager.NewUploadToken("hash1", 1000, nil, int64(5))
41 | manager.NewUploadToken("hash2", 1000, nil, int64(10))
42 | manager.InvalidateToken("hash2")
43 | assert.True(t, manager.IsTokenValid("hash1"))
44 | assert.False(t, manager.IsTokenValid("hash2"))
45 | })
46 | })
47 |
48 | t.Run("GetToken()", func(t *testing.T) {
49 | t.Run("Should return a token from the store", func(t *testing.T) {
50 | manager := NewUploadTokenManager()
51 | token := manager.NewUploadToken("hash1", 1000, nil, int64(5))
52 | assert.Equal(t, token, manager.GetToken("hash1"))
53 | })
54 |
55 | t.Run("Should return nil if no token in store", func(t *testing.T) {
56 | manager := NewUploadTokenManager()
57 | assert.Nil(t, manager.GetToken("hash"))
58 | })
59 | })
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/x/oracle/abci.go:
--------------------------------------------------------------------------------
1 | package oracle
2 |
3 | import (
4 | "github.com/bluzelle/curium/app/ante/gasmeter"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | abci "github.com/tendermint/tendermint/abci/types"
7 | "sync"
8 | )
9 |
10 | // BeginBlocker check for infraction evidence or downtime of validators
11 | // on every begin block
12 | func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) {
13 | ctx = ctx.WithGasMeter(gasmeter.NewFreeGasMeter(0))
14 | currCtx = &ctx
15 | }
16 |
17 | var once sync.Once
18 |
19 | // EndBlocker called every block, process inflation, update validator set.
20 | func EndBlocker(ctx sdk.Context, am AppModule) {
21 | once.Do(func () {
22 | go StartFeeder(am.keeper)
23 | })
24 | }
--------------------------------------------------------------------------------
/x/oracle/alias.go:
--------------------------------------------------------------------------------
1 | package oracle
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/oracle/keeper"
5 | "github.com/bluzelle/curium/x/oracle/types"
6 | )
7 |
8 | const (
9 | ModuleName = types.ModuleName
10 | StoreKey = types.StoreKey
11 | )
12 |
13 |
14 | var (
15 | NewKeeper = keeper.NewKeeper
16 | NewQuerier = keeper.NewQuerier
17 | ModuleCdc = types.ModuleCdc
18 | RegisterCodec = types.RegisterCodec
19 | )
20 |
21 | type (
22 | Keeper = keeper.Keeper
23 | SourceValue = types.SourceValue
24 | )
25 |
--------------------------------------------------------------------------------
/x/oracle/client/rest/query.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "github.com/gorilla/mux"
5 |
6 | "github.com/cosmos/cosmos-sdk/client/context"
7 | )
8 |
9 | func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
10 | }
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/x/oracle/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "github.com/gorilla/mux"
5 |
6 | "github.com/cosmos/cosmos-sdk/client/context"
7 | )
8 |
9 | // RegisterRoutes registers oracle-related REST handlers to a router
10 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
11 | // this line is used by starport scaffolding # 1
12 | registerQueryRoutes(cliCtx, r)
13 | registerTxRoutes(cliCtx, r)
14 | }
15 |
--------------------------------------------------------------------------------
/x/oracle/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | package rest
2 | // The packages below are commented out at first to prevent an error if this file isn't initially saved.
3 | import (
4 | "github.com/gorilla/mux"
5 | "github.com/cosmos/cosmos-sdk/client/context"
6 | )
7 |
8 | func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/x/oracle/docs/arch.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | The feeder and processor in the oracle runs as a Cosmos module that encompasses both functions.
4 |
5 | ### Feeder
6 |
7 | A feeder is responsible to fetch the data from remote sources and send the resulting data to the processor
8 |
9 | ### Processor
10 |
11 | A processor is responsible for combining and filtering votes to produce a single value that it writes to the DB.
12 |
13 | # Oracle flow
14 |
15 | ### Feeders
16 |
17 | * Feeders start and read their configuration from the CRUD module
18 |
19 | * Feeders then request information from the sources provided in the configuration
20 |
21 | * For each source a preflight vote proof is generated and put on the blockchain
22 |
23 | The preflight consists of the vote hashed with the address of the validator (to prevent free-riders). The preflight hash includes a signature, signed with the validator's consensus key.
24 |
25 | * For each source at 20 seconds past the minute a vote is cast on the blockchain that matches the value in the preflight proof. Each vote includes with it a signature, signed with the validator's consensus key.
26 |
27 | ### Processors
28 |
29 | * Listens for preflight proofs and votes on the blockchain
30 | * When a vote is received it is compared with the preflight proof - if the proof does not match, the vote is discarded. If the signatures (of both the preflight proof and the vote itself) does not match the signer, the vote is discarded.
31 | * Votes are then compared and combined using a combination of weights and elimination rules.
32 | * A single (blended) value is written to the DB for each source along with the votes and associated metadata that led to the single blended value.
33 |
--------------------------------------------------------------------------------
/x/oracle/genesis.go:
--------------------------------------------------------------------------------
1 | package oracle
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | "github.com/bluzelle/curium/x/oracle/types"
6 | "github.com/bluzelle/curium/x/oracle/keeper"
7 | )
8 |
9 | // InitGenesis initialize default parameters
10 | // and the keeper's address to pubkey map
11 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, data types.GenesisState) {
12 | k.SetAdminAddress(ctx, data.Config.AdminAddress)
13 | }
14 |
15 | // ExportGenesis writes the current store values
16 | // to a genesis file, which can be imported again
17 | // with InitGenesis
18 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) (data types.GenesisState) {
19 | return types.NewGenesisState(
20 | k.DumpGlobalConfig(ctx),
21 | k.DumpSources(ctx),
22 | k.DumpVotes(ctx),
23 | k.DumpSourceValues(ctx),
24 | )
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 | curium "github.com/bluzelle/curium/x/curium/keeper"
6 | "github.com/bluzelle/curium/x/oracle/types"
7 | "github.com/cosmos/cosmos-sdk/client/flags"
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | "github.com/cosmos/cosmos-sdk/x/staking"
11 | "github.com/spf13/viper"
12 | "github.com/tendermint/tendermint/libs/log"
13 | "github.com/tendermint/tendermint/privval"
14 | "os"
15 | )
16 |
17 | var logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
18 |
19 | var valueUpdateListeners []types.ValueUpdateListener = make([]types.ValueUpdateListener, 0)
20 |
21 |
22 | // Keeper of the oracle store
23 | type Keeper struct {
24 | storeKey sdk.StoreKey
25 | stakingKeeper staking.Keeper
26 | MsgBroadcaster curium.MsgBroadcaster
27 | KeyringReader *curium.KeyringReader
28 | cdc *codec.Codec
29 | paramspace types.ParamSubspace
30 | }
31 |
32 | // NewKeeper creates a oracle keeper
33 | func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, stakingKeeper staking.Keeper, msgBroadcaster curium.MsgBroadcaster, keyringReader *curium.KeyringReader, paramspace types.ParamSubspace) Keeper {
34 | keeper := Keeper{
35 | storeKey: storeKey,
36 | stakingKeeper: stakingKeeper,
37 | MsgBroadcaster: msgBroadcaster,
38 | KeyringReader: keyringReader,
39 | cdc: cdc,
40 | // paramspace: paramspace.WithKeyTable(types.ParamKeyTable()),
41 | }
42 | return keeper
43 | }
44 |
45 | func (k Keeper) GetStore(ctx sdk.Context) sdk.KVStore {
46 | return ctx.KVStore(k.storeKey)
47 | }
48 |
49 |
50 | // Logger returns a module-specific logger.
51 | func (k Keeper) Logger(ctx sdk.Context) log.Logger {
52 | return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
53 | }
54 |
55 | func (k Keeper) GetValidator(ctx sdk.Context, valcons string) (validator staking.Validator, found bool) {
56 | consAddr, _ := sdk.ConsAddressFromBech32(valcons)
57 | return k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
58 | }
59 |
60 | func (k Keeper) IsValidator(ctx sdk.Context) bool {
61 | valcons := GetValconsAddress()
62 | validator, _ := k.GetValidator(ctx, valcons)
63 | return !validator.DelegatorShares.IsNil() && !validator.DelegatorShares.IsZero()
64 | }
65 |
66 | func GetPrivateValidator() *privval.FilePV {
67 | homedir := viper.GetString(flags.FlagHome)
68 | return privval.LoadFilePV(homedir+"/config/priv_validator_key.json", homedir+"/data/priv_validator_state.json")
69 | }
70 |
71 | func GetValconsAddress() string {
72 | validator := GetPrivateValidator()
73 | address := validator.GetAddress()
74 | consAddress := (sdk.ConsAddress)(address)
75 | addressString := consAddress.String()
76 | return addressString
77 | }
78 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper_global_config.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/oracle/types"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | )
7 |
8 |
9 | func (k Keeper) DumpGlobalConfig(ctx sdk.Context) types.GlobalOracleConfig {
10 | return types.GlobalOracleConfig{
11 | AdminAddress: k.GetAdminAddress(ctx),
12 | }
13 | }
14 |
15 | func (k Keeper) SetAdminAddress(ctx sdk.Context, admin sdk.AccAddress) {
16 | store := k.GetStore(ctx)
17 | store.Set([]byte(types.ConfigStorePrefix + "admin-address"), admin)
18 | }
19 |
20 | func (k Keeper) GetAdminAddress(ctx sdk.Context) sdk.AccAddress{
21 | store := k.GetStore(ctx)
22 | return store.Get([]byte(types.ConfigStorePrefix + "admin-address"))
23 | }
24 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper_proof.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "encoding/hex"
5 | "github.com/bluzelle/curium/x/oracle/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | var voteProofs map[string]types.MsgOracleVoteProof
10 |
11 | func (k Keeper) GetVoteProof(ctx sdk.Context, sourceName string, valcons string) types.MsgOracleVoteProof {
12 | var msg types.MsgOracleVoteProof
13 | proofStore := k.GetStore(ctx)
14 | proof := proofStore.Get([]byte(types.ProofStorePrefix + sourceName + valcons))
15 | k.cdc.MustUnmarshalBinaryBare(proof, &msg)
16 | return msg
17 | }
18 |
19 | func CalculateProofSig(value string) string {
20 | v := GetPrivateValidator()
21 | s, _ := v.Key.PrivKey.Sign([]byte(value))
22 | return hex.EncodeToString(s)
23 | }
24 |
25 | func (k Keeper) StoreVoteProof(ctx sdk.Context, msg types.MsgOracleVoteProof) {
26 | proofStore := k.GetStore(ctx)
27 | proofStore.Set([]byte(types.ProofStorePrefix + msg.SourceName + msg.ValidatorAddr), k.cdc.MustMarshalBinaryBare(msg))
28 | }
29 |
30 | func (k Keeper) IsVoteValid(ctx sdk.Context, msg types.MsgOracleVote) bool {
31 | validator, found := k.GetValidator(ctx, msg.Valcons)
32 |
33 | if validator.Jailed {
34 | logger.Info("Oracle vote received from jailed validator", "name", msg.SourceName, "valcons", msg.Valcons)
35 | return false
36 | }
37 |
38 | if !found {
39 | logger.Info("Oracle vote received from unknown validator", "name", msg.SourceName, "valcons", msg.Valcons)
40 | }
41 |
42 | if found {
43 | proofSignatureString := k.GetVoteProof(ctx, msg.SourceName, msg.Valcons).VoteSig
44 | proofSignature, _ := hex.DecodeString(proofSignatureString)
45 | isGood := validator.ConsPubKey.VerifyBytes([]byte(msg.Value), proofSignature)
46 |
47 | if !isGood {
48 | logger.Info("Oracle vote/proof mismatch", "name", msg.SourceName, "valcons", msg.Valcons)
49 | }
50 |
51 | return isGood
52 | }
53 | return false
54 | }
55 |
56 | func (k Keeper) SearchVoteProofs(ctx sdk.Context, prefix string) []types.MsgOracleVoteProof {
57 | iterator := sdk.KVStorePrefixIterator(k.GetStore(ctx), []byte(types.ProofStorePrefix + prefix))
58 | defer iterator.Close()
59 | proofs := make([]types.MsgOracleVoteProof, 0)
60 |
61 | for ;iterator.Valid(); iterator.Next() {
62 | if ctx.GasMeter().IsPastLimit() {
63 | break
64 | }
65 |
66 | var v types.MsgOracleVoteProof
67 | value := iterator.Value()
68 | k.cdc.MustUnmarshalBinaryBare(value, &v)
69 | proofs = append(proofs, v)
70 | }
71 | return proofs
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper_source.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/oracle/types"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | )
7 |
8 | func (k Keeper) AddSource(ctx sdk.Context, name string, source types.Source) {
9 | store := k.GetStore(ctx)
10 | store.Set([]byte(types.SourceStorePrefix + name), k.cdc.MustMarshalBinaryBare(source))
11 | }
12 |
13 | func (k Keeper) GetSource(ctx sdk.Context, name string) (types.Source, error) {
14 | store := k.GetStore(ctx)
15 | var source types.Source
16 | err := k.cdc.UnmarshalBinaryBare(store.Get([]byte(types.SourceStorePrefix + name)), &source)
17 | return source, err
18 | }
19 |
20 | func (k Keeper) DeleteSource(ctx sdk.Context, name string) error {
21 | store := k.GetStore(ctx)
22 | store.Delete([]byte(types.SourceStorePrefix + name))
23 | return nil
24 | }
25 |
26 | func (k Keeper) ListSources(ctx sdk.Context) ([]types.Source, error) {
27 | store := k.GetStore(ctx)
28 | iterator := sdk.KVStorePrefixIterator(store, []byte(types.SourceStorePrefix))
29 | defer iterator.Close()
30 | var sources = make([]types.Source, 0)
31 | for ; iterator.Valid(); iterator.Next() {
32 | var source types.Source
33 | value := iterator.Value()
34 | k.cdc.UnmarshalBinaryBare(value, &source)
35 | sources = append(sources, source)
36 | }
37 | return sources, nil
38 | }
39 |
40 | func (k Keeper) DumpSources(ctx sdk.Context) map[string] types.Source {
41 | store := k.GetStore(ctx)
42 | var results = make(map[string]types.Source)
43 | iterator := sdk.KVStorePrefixIterator(store, []byte(types.SourceStorePrefix))
44 | for ; iterator.Valid(); iterator.Next() {
45 | var source types.Source
46 | k.cdc.UnmarshalBinaryBare(iterator.Value(), &source)
47 | results[string(iterator.Key())] = source
48 | }
49 | return results
50 | }
51 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 |
4 |
--------------------------------------------------------------------------------
/x/oracle/keeper/keeper_vote.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 | types "github.com/bluzelle/curium/x/oracle/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 |
10 | type VoteKey struct {
11 | Batch string
12 | SourceName string
13 | Valcons string
14 | }
15 |
16 | func voteToVoteKey(vote types.Vote) VoteKey {
17 | return VoteKey{
18 | Batch: vote.Batch,
19 | SourceName: vote.SourceName,
20 | Valcons: vote.Valcons,
21 | }
22 | }
23 |
24 | func (vk VoteKey) Bytes() []byte {
25 | return []byte(fmt.Sprintf("%s%s>%s>%s", types.VoteStorePrefix, vk.Batch, vk.SourceName, vk.Valcons))
26 | }
27 |
28 | func (k Keeper) StoreVote(ctx sdk.Context, vote types.Vote) {
29 | key := voteToVoteKey(vote).Bytes()
30 | store := k.GetStore(ctx)
31 | store.Set(key, k.cdc.MustMarshalBinaryBare(vote))
32 | }
33 |
34 | func (k Keeper) DeleteVotes(ctx sdk.Context, prefix string) int {
35 | keys := k.SearchVoteKeys(ctx, prefix)
36 | store := k.GetStore(ctx)
37 | for _, key := range keys {
38 | store.Delete([]byte(key))
39 | }
40 | return len(keys)
41 | }
42 |
43 | func (k Keeper) SearchVoteKeys(ctx sdk.Context, prefix string) []string {
44 | iterator := sdk.KVStorePrefixIterator(k.GetStore(ctx), []byte(types.VoteStorePrefix + prefix))
45 | defer iterator.Close()
46 | keys := make([]string, 0)
47 |
48 | for ;iterator.Valid(); iterator.Next() {
49 | if ctx.GasMeter().IsPastLimit() {
50 | break
51 | }
52 |
53 | key := iterator.Key()
54 | keys = append(keys, string(key))
55 | }
56 | return keys
57 |
58 | }
59 |
60 | func makeSearchVotePrefix(batch string, sourceName string) string {
61 | return fmt.Sprintf("%s>%s", batch, sourceName)
62 | }
63 |
64 | func (k Keeper) SearchVotes(ctx sdk.Context, prefix string) []types.Vote {
65 | iterator := sdk.KVStorePrefixIterator(k.GetStore(ctx), []byte(types.VoteStorePrefix + prefix))
66 | defer iterator.Close()
67 | votes := make([]types.Vote, 0)
68 |
69 | for ;iterator.Valid(); iterator.Next() {
70 | if ctx.GasMeter().IsPastLimit() {
71 | break
72 | }
73 |
74 | var v types.Vote
75 | value := iterator.Value()
76 | k.cdc.MustUnmarshalBinaryBare(value, &v)
77 | votes = append(votes, v)
78 | }
79 | return votes
80 | }
81 |
82 | func (k Keeper) DumpVotes(ctx sdk.Context) map[string] types.Vote {
83 | store := k.GetStore(ctx)
84 | var results = make(map[string]types.Vote)
85 | iterator := sdk.KVStorePrefixIterator(store, []byte(types.VoteStorePrefix))
86 | for ; iterator.Valid(); iterator.Next() {
87 | var vote types.Vote
88 | k.cdc.UnmarshalBinaryBare(iterator.Value(), &vote)
89 | results[string(iterator.Key())] = vote
90 | }
91 | return results
92 | }
93 |
94 |
95 |
--------------------------------------------------------------------------------
/x/oracle/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | // TODO: Define if your module needs Parameters, if not this can be deleted
4 |
5 | import (
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/bluzelle/curium/x/oracle/types"
8 | )
9 |
10 | // GetParams returns the total set of oracle parameters.
11 | func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
12 | k.paramspace.GetParamSet(ctx, ¶ms)
13 | return params
14 | }
15 |
16 | // SetParams sets the oracle parameters to the param space.
17 | func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
18 | k.paramspace.SetParamSet(ctx, ¶ms)
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/x/oracle/spec/README.md:
--------------------------------------------------------------------------------
1 | # oracle module specification
2 |
3 | ## Abstract
4 |
5 |
6 |
7 | ## Contents
8 |
9 | // TODO: Create the below files if they are needed.
10 | 1. **[Concepts](01_concepts.md)**
11 | 2. **[State](02_state.md)**
12 | 3. **[Messages](03_messages.md)**
13 | 4. **[Begin-Block](04_begin_block.md)**
14 | 5. **[End-Block](06_end_bloc.md)**
15 | 6. **[05_hooks](06_hooks.md)**
16 | 7. **[Events](07_events.md)**
17 | 8. **[Parameters](08_params.md)**
18 |
--------------------------------------------------------------------------------
/x/oracle/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | )
6 |
7 | // RegisterCodec registers concrete types on codec
8 | func RegisterCodec(cdc *codec.Codec) {
9 | // this line is used by starport scaffolding # 1
10 | cdc.RegisterConcrete(MsgOracleAddSource{}, "oracle/MsgAddSource", nil)
11 | cdc.RegisterConcrete(MsgOracleDeleteSource{}, "oracle/MsgDeleteSource", nil)
12 | cdc.RegisterConcrete(MsgOracleVoteProof{}, "oracle/MsgVoteProof", nil)
13 | cdc.RegisterConcrete(MsgOracleVote{}, "oracle/MsgVote", nil)
14 | cdc.RegisterConcrete(MsgOracleDeleteVotes{}, "oracle/MsgDeleteVotes", nil)
15 | cdc.RegisterConcrete(MsgOracleSetAdmin{}, "oracle/MsgSetAdmin", nil)
16 | }
17 |
18 | // ModuleCdc defines the module codec
19 | var ModuleCdc *codec.Codec
20 |
21 | func init() {
22 | ModuleCdc = codec.New()
23 | RegisterCodec(ModuleCdc)
24 | codec.RegisterCrypto(ModuleCdc)
25 | ModuleCdc.Seal()
26 | }
27 |
--------------------------------------------------------------------------------
/x/oracle/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | _ "github.com/cosmos/cosmos-sdk/types/errors"
5 | )
6 |
7 | // TODO: Fill out some custom errors for the module
8 | // You can see how they are constructed below:
9 | var (
10 | // ErrInvalid = sdkerrors.Register(ModuleName, 1, "custom error message")
11 | )
12 |
--------------------------------------------------------------------------------
/x/oracle/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // oracle module event types
4 | const (
5 | // TODO: Create your event types
6 | // EventType = "action"
7 |
8 | // TODO: Create keys fo your events, the values will be derivided from the msg
9 | // AttributeKeyAddress = "address"
10 |
11 | // TODO: Some events may not have values for that reason you want to emit that something happened.
12 | // AttributeValueDoubleSign = "double_sign"
13 |
14 | AttributeValueCategory = ModuleName
15 | )
16 |
--------------------------------------------------------------------------------
/x/oracle/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/params"
6 | )
7 |
8 | // ParamSubspace defines the expected Subspace interfcace
9 | type ParamSubspace interface {
10 | WithKeyTable(table params.KeyTable) params.Subspace
11 | Get(ctx sdk.Context, key []byte, ptr interface{})
12 | GetParamSet(ctx sdk.Context, ps params.ParamSet)
13 | SetParamSet(ctx sdk.Context, ps params.ParamSet)
14 | }
15 |
16 | /*
17 | When a module wishes to interact with another module, it is good practice to define what it will use
18 | as an interface so the module cannot use things that are not permitted.
19 | TODO: Create interfaces of what you expect the other keepers to have to be able to use this module.
20 | type BankKeeper interface {
21 | SubtractCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Coins, error)
22 | SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
23 | }
24 | */
25 |
--------------------------------------------------------------------------------
/x/oracle/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/types/errors"
5 | )
6 |
7 | // GenesisState - all oracle state that must be provided at genesis
8 | type GenesisState struct {
9 | Config GlobalOracleConfig
10 | Sources map[string] Source
11 | Votes map[string] Vote
12 | SourceValues map[string] SourceValue
13 | }
14 |
15 | // NewGenesisState creates a new GenesisState object
16 | func NewGenesisState(config GlobalOracleConfig, sources map[string] Source, votes map[string] Vote, values map[string] SourceValue) GenesisState {
17 | return GenesisState{
18 | Config: config,
19 | Sources: sources,
20 | Votes: votes,
21 | SourceValues: values,
22 | }
23 | }
24 |
25 | // DefaultGenesisState - default GenesisState used by Cosmos Hub
26 | func DefaultGenesisState() GenesisState {
27 | return GenesisState{
28 | Config: GlobalOracleConfig{},
29 | Sources: map[string] Source{},
30 | }
31 | }
32 |
33 | // ValidateGenesis validates the oracle genesis parameters
34 | func ValidateGenesis(data GenesisState) error {
35 | if data.Config.AdminAddress == nil {
36 | return errors.New("oracle", 1, "Genesis missing oracle admin address")
37 | }
38 | return nil
39 | }
40 |
--------------------------------------------------------------------------------
/x/oracle/types/keeper.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import "github.com/cosmos/cosmos-sdk/types"
4 |
5 | type GlobalOracleConfig struct {
6 | AdminAddress types.AccAddress
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/x/oracle/types/key.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 |
4 |
5 |
6 | const (
7 | // ModuleName is the name of the module
8 | ModuleName = "oracle"
9 |
10 | // StoreKey to be used when creating the KVStore
11 | StoreKey = ModuleName
12 |
13 | // RouterKey to be used for routing msgs
14 | RouterKey = ModuleName
15 |
16 | // QuerierRoute to be used for querier msgs
17 | QuerierRoute = ModuleName
18 |
19 | // Store prefixes
20 | SourceStorePrefix = "SO"
21 | ProofStorePrefix = "PR"
22 | VoteStorePrefix = "VO"
23 | ValueStorePrefix = "VA"
24 | ConfigStorePrefix = "CO"
25 | )
26 |
--------------------------------------------------------------------------------
/x/oracle/types/params.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/x/params"
7 | )
8 |
9 | // Default parameter namespace
10 | const (
11 | DefaultParamspace = ModuleName
12 | // TODO: Define your default parameters
13 | )
14 |
15 | // Parameter store keys
16 | var (
17 | // TODO: Define your keys for the parameter store
18 | // KeyParamName = []byte("ParamName")
19 | )
20 |
21 | // ParamKeyTable for oracle module
22 | func ParamKeyTable() params.KeyTable {
23 | return params.NewKeyTable().RegisterParamSet(&Params{})
24 | }
25 |
26 | // Params - used for initializing default parameter for oracle at genesis
27 | type Params struct {
28 | // TODO: Add your Paramaters to the Paramter struct
29 | // KeyParamName string `json:"key_param_name"`
30 | }
31 |
32 | // NewParams creates a new Params object
33 | func NewParams(/* TODO: Pass in the paramters*/) Params {
34 | return Params{
35 | // TODO: Create your Params Type
36 | }
37 | }
38 |
39 | // String implements the stringer interface for Params
40 | func (p Params) String() string {
41 | return fmt.Sprintf(`
42 | // TODO: Return all the params as a string
43 | `, )
44 | }
45 |
46 | // ParamSetPairs - Implements params.ParamSet
47 | func (p *Params) ParamSetPairs() params.ParamSetPairs {
48 | return params.ParamSetPairs{
49 | // TODO: Pair your key with the param
50 | // params.NewParamSetPair(KeyParamName, &p.ParamName),
51 | }
52 | }
53 |
54 | // DefaultParams defines the parameters for this module
55 | func DefaultParams() Params {
56 | return NewParams( /* TODO: Pass in your default Params */ )
57 | }
58 |
--------------------------------------------------------------------------------
/x/oracle/types/querier.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | const (
6 | QueryListSources = "listsources"
7 | QuerySearchVotes = "searchvotes"
8 | QuerySearchVoteProofs = "searchProofs"
9 | QuerySearchVoteKeys = "searchvotekeys"
10 | QuerySearchSourceValues = "searchSourceValues"
11 | QueryConfig = "getConfig"
12 | QueryValidatorByValcons = "validatorByValcons"
13 | )
14 |
15 | type QueryResultListSources = []struct{
16 | Name string
17 | Url string
18 | Property string
19 | Owner sdk.AccAddress
20 | }
21 |
22 | type QueryResultConfig = struct{
23 | AdminAddress sdk.AccAddress
24 | }
25 |
26 | type ValidatorByValconsQueryRequest = struct {
27 | Valcons string
28 | }
29 |
30 | type SearchVotesQueryRequest = struct{
31 | Prefix string
32 | }
33 |
34 | type SearchVoteProofsQueryRequest = struct {
35 | Prefix string
36 | }
37 |
38 | type SearchSourceValuesQueryRequest = struct{
39 | Prefix string
40 | Reverse bool
41 | Page uint
42 | Limit uint
43 | }
44 |
45 |
46 | type CalculateProofSigQueryRequest = struct {
47 | Valcons string
48 | Value string
49 | }
--------------------------------------------------------------------------------
/x/oracle/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/types"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | )
7 |
8 |
9 | type Source struct {
10 | Name string
11 | Url string
12 | Property string
13 | Owner types.AccAddress
14 | Weight int64
15 | }
16 |
17 | type Vote struct {
18 | SourceName string
19 | Batch string
20 | Value types.Dec
21 | Valcons string
22 | Owner types.AccAddress
23 | Weight types.Dec
24 | }
25 |
26 | type SourceValue struct {
27 | SourceName string
28 | Batch string
29 | Value types.Dec
30 | Owner types.AccAddress
31 | Height int64
32 | Count int64
33 | Weight int64
34 | }
35 |
36 | type LocalOracleConfig struct {
37 | UserAddress types.AccAddress
38 | UserMnemonic string
39 | }
40 |
41 | type ValueUpdateListener func(sdk.Context, SourceValue)
42 |
--------------------------------------------------------------------------------
/x/tax/README.md:
--------------------------------------------------------------------------------
1 | # Readme
2 |
3 | Tax module is for customization of fees flow.
4 |
5 | DeductFee ante handler is sending specified bp(basis point, unit of `0.0001`) of fee to the address specified by tax module.
6 | And rest of them are sent to fee collector module as it was doing.
7 |
8 | # Queries
9 |
10 | Query command query tax collector (owner) and fee tax bp and transfer tax bp.
11 | ```sh
12 | blzcli query tax info
13 | ```
14 |
15 | # Transactions
16 |
17 | Set tax fee bp and transfer tax bp.
18 | ```sh
19 | blzcli tx tax set-bp 30 40 --from tax_owner --keyring-backend=test
20 | blzcli tx tax set-collector $(blzcli keys show -a user1 --keyring-backend=test) --from tax_owner --keyring-backend=test
21 | ```
22 | # Command to run test
23 |
24 | Go to root directory of project and run `make test-tax`.
--------------------------------------------------------------------------------
/x/tax/alias.go:
--------------------------------------------------------------------------------
1 | package tax
2 |
3 | import (
4 | "github.com/bluzelle/curium/x/tax/internal/keeper"
5 | "github.com/bluzelle/curium/x/tax/internal/types"
6 | )
7 |
8 | // constants
9 | var (
10 | ModuleName = types.ModuleName
11 | RouterKey = types.RouterKey
12 | StoreKey = types.StoreKey
13 | )
14 |
15 | // modules
16 | var (
17 | NewKeeper = keeper.NewKeeper
18 | NewQuerier = keeper.NewQuerier
19 | ModuleCdc = types.ModuleCdc
20 | RegisterCodec = types.RegisterCodec
21 | )
22 |
23 | // Keeper alias types
24 | type (
25 | Keeper = keeper.Keeper
26 | )
27 |
--------------------------------------------------------------------------------
/x/tax/client/cli/query.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/bluzelle/curium/x/tax/internal/types"
7 | "github.com/cosmos/cosmos-sdk/client"
8 | "github.com/cosmos/cosmos-sdk/client/context"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/cosmos/cosmos-sdk/codec"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | // GetQueryCmd returns module query commands
15 | func GetQueryCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
16 | taxQueryCmd := &cobra.Command{
17 | Use: types.ModuleName,
18 | Short: "Querying commands for the tax module",
19 | DisableFlagParsing: true,
20 | SuggestionsMinimumDistance: 0,
21 | RunE: client.ValidateCmd,
22 | }
23 |
24 | taxQueryCmd.AddCommand(flags.GetCommands(
25 | GetCmdQTaxInfo(storeKey, cdc),
26 | )...)
27 |
28 | return taxQueryCmd
29 | }
30 |
31 | // GetCmdQTaxInfo returns tax info by query
32 | func GetCmdQTaxInfo(queryRoute string, cdc *codec.Codec) *cobra.Command {
33 | return &cobra.Command{
34 | Use: "info",
35 | Short: "show tax info",
36 | Args: cobra.ExactArgs(0),
37 | RunE: func(cmd *cobra.Command, args []string) error {
38 | cliCtx := context.NewCLIContext().WithCodec(cdc)
39 | res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/info", queryRoute), nil)
40 |
41 | if err != nil {
42 | fmt.Println("could get tax info ", err)
43 | return nil
44 | }
45 |
46 | var out types.TaxInfo
47 | cdc.MustUnmarshalJSON(res, &out)
48 | return cliCtx.PrintOutput(out)
49 | },
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/x/tax/client/cli/tx.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "bufio"
5 | "strconv"
6 |
7 | "github.com/bluzelle/curium/x/tax/internal/types"
8 | "github.com/cosmos/cosmos-sdk/client"
9 | "github.com/cosmos/cosmos-sdk/client/context"
10 | "github.com/cosmos/cosmos-sdk/client/flags"
11 | "github.com/cosmos/cosmos-sdk/codec"
12 | sdk "github.com/cosmos/cosmos-sdk/types"
13 | "github.com/cosmos/cosmos-sdk/x/auth"
14 | "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
15 | "github.com/spf13/cobra"
16 | )
17 |
18 | func GetTxCmd(_ string, cdc *codec.Codec) *cobra.Command {
19 | taxTxCmd := &cobra.Command{
20 | Use: types.ModuleName,
21 | Short: "tax transaction subcommands",
22 | DisableFlagParsing: true,
23 | SuggestionsMinimumDistance: 2,
24 | RunE: client.ValidateCmd,
25 | }
26 | taxTxCmd.AddCommand(flags.PostCommands(
27 | GetCmdSetCollector(cdc),
28 | GetCmdSetBp(cdc),
29 | )...)
30 |
31 | return taxTxCmd
32 | }
33 |
34 | func GetCmdSetCollector(cdc *codec.Codec) *cobra.Command {
35 | cc := cobra.Command{
36 | Use: "set-collector [address]",
37 | Short: "set collector of tax module",
38 | Args: cobra.ExactArgs(1),
39 | RunE: func(cmd *cobra.Command, args []string) error {
40 | cliCtx := context.NewCLIContext().WithCodec(cdc)
41 | inBuf := bufio.NewReader(cmd.InOrStdin())
42 | txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
43 |
44 | collector, err := sdk.AccAddressFromBech32(args[0])
45 | if err != nil {
46 | return err
47 | }
48 |
49 | msg := types.NewMsgSetCollector(collector, cliCtx.GetFromAddress())
50 |
51 | err = msg.ValidateBasic()
52 | if err != nil {
53 | return err
54 | }
55 | return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
56 | },
57 | }
58 |
59 | return &cc
60 | }
61 |
62 | func GetCmdSetBp(cdc *codec.Codec) *cobra.Command {
63 | return &cobra.Command{
64 | Use: "set-bp [fee_bp] [transfer_bp]",
65 | Short: "set basis point (0.0001 unit) of tax",
66 | Args: cobra.ExactArgs(2),
67 | RunE: func(cmd *cobra.Command, args []string) error {
68 | cliCtx := context.NewCLIContext().WithCodec(cdc)
69 | inBuf := bufio.NewReader(cmd.InOrStdin())
70 | txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
71 |
72 | feebp, err := strconv.Atoi(args[0])
73 | if err != nil {
74 | return err
75 | }
76 |
77 | trfbp, err := strconv.Atoi(args[1])
78 | if err != nil {
79 | return err
80 | }
81 |
82 | msg := types.NewMsgSetBp(int64(feebp), int64(trfbp), cliCtx.GetFromAddress())
83 |
84 | err = msg.ValidateBasic()
85 | if err != nil {
86 | return err
87 | }
88 |
89 | return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
90 | },
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/x/tax/client/rest/query.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 |
7 | "github.com/cosmos/cosmos-sdk/client/context"
8 | "github.com/cosmos/cosmos-sdk/types/rest"
9 | )
10 |
11 | func QueryTaxInfoHandler(cliCtx context.CLIContext, storeName string) http.HandlerFunc {
12 | return func(w http.ResponseWriter, r *http.Request) {
13 |
14 | res, _, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/info", storeName), nil)
15 | if err != nil {
16 | rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
17 | return
18 | }
19 | rest.PostProcessResponse(w, cliCtx, res)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/x/tax/client/rest/rest.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/client/context"
7 | "github.com/gorilla/mux"
8 | )
9 |
10 | // RegisterRoutes - Central function to define routes that get registered by the main application
11 | func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string) {
12 | r.HandleFunc(fmt.Sprintf("/%s/info", storeName), QueryTaxInfoHandler(cliCtx, storeName)).Methods("GET")
13 | r.HandleFunc(fmt.Sprintf("/%s/bp", storeName), SetBpHandler(cliCtx)).Methods("POST")
14 | r.HandleFunc(fmt.Sprintf("/%s/collector", storeName), SetCollectorHandler(cliCtx)).Methods("POST")
15 | }
16 |
--------------------------------------------------------------------------------
/x/tax/client/rest/tx.go:
--------------------------------------------------------------------------------
1 | package rest
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/bluzelle/curium/x/tax/internal/types"
7 | "github.com/cosmos/cosmos-sdk/client/context"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/types/rest"
10 | "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
11 | )
12 |
13 | type setCollectorReq struct {
14 | BaseReq rest.BaseReq
15 | Collector string
16 | Proposer string
17 | }
18 |
19 | func SetCollectorHandler(cliCtx context.CLIContext) http.HandlerFunc {
20 | return func(w http.ResponseWriter, r *http.Request) {
21 | var req setCollectorReq
22 |
23 | if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
24 | rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request")
25 | return
26 | }
27 |
28 | baseReq := req.BaseReq.Sanitize()
29 | if !baseReq.ValidateBasic(w) {
30 | return
31 | }
32 |
33 | proposer, err := sdk.AccAddressFromBech32(req.Proposer)
34 | if err != nil {
35 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
36 | return
37 | }
38 |
39 | collector, err := sdk.AccAddressFromBech32(req.Collector)
40 | if err != nil {
41 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
42 | return
43 | }
44 |
45 | msg := types.NewMsgSetCollector(collector, proposer)
46 | err = msg.ValidateBasic()
47 | if err != nil {
48 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
49 | return
50 | }
51 |
52 | utils.WriteGenerateStdTxResponse(w, cliCtx, baseReq, []sdk.Msg{msg})
53 | }
54 | }
55 |
56 | type setBpReq struct {
57 | BaseReq rest.BaseReq
58 | FeeBp int
59 | TransferBp int
60 | Proposer string
61 | }
62 |
63 | func SetBpHandler(cliCtx context.CLIContext) http.HandlerFunc {
64 | return func(w http.ResponseWriter, r *http.Request) {
65 | var req setBpReq
66 |
67 | if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
68 | rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request")
69 | return
70 | }
71 |
72 | baseReq := req.BaseReq.Sanitize()
73 | if !baseReq.ValidateBasic(w) {
74 | return
75 | }
76 |
77 | proposer, err := sdk.AccAddressFromBech32(req.Proposer)
78 | if err != nil {
79 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
80 | return
81 | }
82 |
83 | // create the message
84 | msg := types.NewMsgSetBp(int64(req.FeeBp), int64(req.TransferBp), proposer)
85 | err = msg.ValidateBasic()
86 | if err != nil {
87 | rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
88 | return
89 | }
90 |
91 | utils.WriteGenerateStdTxResponse(w, cliCtx, baseReq, []sdk.Msg{msg})
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/x/tax/genesis.go:
--------------------------------------------------------------------------------
1 | package tax
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/bluzelle/curium/x/tax/internal/keeper"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | abci "github.com/tendermint/tendermint/abci/types"
9 | )
10 |
11 | type GenesisState struct {
12 | Collector sdk.AccAddress
13 | FeeBp int64
14 | TransferBp int64
15 | }
16 |
17 | func NewGenesisState() GenesisState {
18 | return GenesisState{}
19 | }
20 |
21 | func ValidateGenesis(data GenesisState) error {
22 | if data.Collector.Empty() && data.FeeBp > 0 {
23 | return errors.New("tax collector is empty but fee tax bp is not zero")
24 | }
25 | if data.Collector.Empty() && data.TransferBp > 0 {
26 | return errors.New("tax collector is empty but transfer tax bp is not zero")
27 | }
28 | return nil
29 | }
30 |
31 | func DefaultGenesisState() GenesisState {
32 | // $ blzcli keys add tax_owner --recover --keyring-backend=test
33 | // address: bluzelle1wjkdcz4hl4gcarnqtupu7vkftal6h34qxjh6rw
34 | // pubkey: bluzellepub1addwnpepq0r59990s6ljrucwnsf085p2lkugecf87gljr45cgalkfk623f88sr7re7n
35 | // mnemonic: day rabbit mom clown bleak brown large lobster reduce accuse violin where address click dynamic myself buyer daughter situate today wheel thumb sudden drill
36 | collector, err := sdk.AccAddressFromBech32("bluzelle1wjkdcz4hl4gcarnqtupu7vkftal6h34qxjh6rw")
37 | if err != nil {
38 | panic(err)
39 | }
40 | return GenesisState{
41 | Collector: collector,
42 | FeeBp: 100,
43 | TransferBp: 1,
44 | }
45 | }
46 |
47 | func InitGenesis(ctx sdk.Context, k keeper.IKeeper, data GenesisState) []abci.ValidatorUpdate {
48 | k.SetCollector(ctx, data.Collector)
49 | k.SetFeeBp(ctx, data.FeeBp)
50 | k.SetTransferBp(ctx, data.TransferBp)
51 | return []abci.ValidatorUpdate{}
52 | }
53 |
54 | func ExportGenesis(ctx sdk.Context, k keeper.IKeeper) GenesisState {
55 | collector := k.GetCollector(ctx)
56 | feebp := k.GetFeeBp(ctx)
57 | trfbp := k.GetTransferBp(ctx)
58 | return GenesisState{
59 | Collector: collector,
60 | FeeBp: feebp,
61 | TransferBp: trfbp,
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/x/tax/genesis_test.go:
--------------------------------------------------------------------------------
1 | package tax
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestNewGenesisState(t *testing.T) {
10 | newGenesis := NewGenesisState()
11 | require.True(t, newGenesis.Collector.Empty())
12 | require.True(t, newGenesis.FeeBp == 0)
13 | require.True(t, newGenesis.TransferBp == 0)
14 | }
15 |
16 | func TestValidateGenesis(t *testing.T) {
17 | genesis := GenesisState{
18 | FeeBp: 100, // 1.00%
19 | }
20 | require.Error(t, ValidateGenesis(genesis))
21 | }
22 |
23 | func TestInitGenesis(t *testing.T) {
24 | }
25 |
--------------------------------------------------------------------------------
/x/tax/handler.go:
--------------------------------------------------------------------------------
1 | package tax
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 |
7 | "github.com/bluzelle/curium/x/tax/internal/keeper"
8 | "github.com/bluzelle/curium/x/tax/internal/types"
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
11 | )
12 |
13 | func NewHandler(keeper keeper.IKeeper) sdk.Handler {
14 | return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
15 | switch msg := msg.(type) {
16 | case types.MsgSetCollector:
17 | return HandleMsgSetCollector(ctx, keeper, msg)
18 | case types.MsgSetBp:
19 | return HandleMsgSetBp(ctx, keeper, msg)
20 | default:
21 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, fmt.Sprintf("Unrecognized tax msg type: %v", msg.Type()))
22 | }
23 | }
24 | }
25 |
26 | func HandleMsgSetCollector(ctx sdk.Context, keeper keeper.IKeeper, msg types.MsgSetCollector) (*sdk.Result, error) {
27 | if err := msg.ValidateBasic(); err != nil {
28 | return &sdk.Result{}, err
29 | }
30 | oldCollector := keeper.GetCollector(ctx)
31 | if !bytes.Equal(msg.Proposer, oldCollector) {
32 | return &sdk.Result{}, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "proposer should be equal to original tax collector")
33 | }
34 | keeper.SetCollector(ctx, msg.NewCollector)
35 | return &sdk.Result{}, nil
36 | }
37 |
38 | func HandleMsgSetBp(ctx sdk.Context, keeper keeper.IKeeper, msg types.MsgSetBp) (*sdk.Result, error) {
39 | if err := msg.ValidateBasic(); err != nil {
40 | return &sdk.Result{}, err
41 | }
42 | oldCollector := keeper.GetCollector(ctx)
43 | if !bytes.Equal(msg.Proposer, oldCollector) {
44 | return &sdk.Result{}, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "proposer should be equal to original tax collector")
45 | }
46 | keeper.SetFeeBp(ctx, msg.NewFeeBp)
47 | keeper.SetTransferBp(ctx, msg.NewTransferBp)
48 | return &sdk.Result{}, nil
49 | }
50 |
--------------------------------------------------------------------------------
/x/tax/handler_test.go:
--------------------------------------------------------------------------------
1 | package tax_test
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | "github.com/bluzelle/curium/app"
8 | "github.com/bluzelle/curium/x/tax"
9 | "github.com/bluzelle/curium/x/tax/internal/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | "github.com/stretchr/testify/require"
12 | abci "github.com/tendermint/tendermint/abci/types"
13 | )
14 |
15 | func Test_handleMsgSetBp(t *testing.T) {
16 | tApp := app.NewTestApp()
17 | ctx := tApp.NewContext(true, abci.Header{})
18 | tax.InitGenesis(ctx, tApp.GetTaxKeeper(), tax.DefaultGenesisState())
19 |
20 | collector, err := sdk.AccAddressFromBech32("bluzelle1wjkdcz4hl4gcarnqtupu7vkftal6h34qxjh6rw")
21 | if err != nil {
22 | panic(err)
23 | }
24 |
25 | addr1 := sdk.AccAddress([]byte("my----------address1"))
26 |
27 | // try setting Bp with correct owner
28 | msg1 := types.NewMsgSetBp(11, 11, collector)
29 | _, err = tax.HandleMsgSetBp(ctx, tApp.GetTaxKeeper(), msg1)
30 | require.NoError(t, err)
31 | feebp1 := tApp.GetTaxKeeper().GetFeeBp(ctx)
32 | require.True(t, feebp1 == 11)
33 | trfbp1 := tApp.GetTaxKeeper().GetTransferBp(ctx)
34 | require.True(t, trfbp1 == 11)
35 |
36 | // try setting Bp with incorrect owner
37 | msg2 := types.NewMsgSetBp(12, 12, addr1)
38 | _, err = tax.HandleMsgSetBp(ctx, tApp.GetTaxKeeper(), msg2)
39 | require.Error(t, err)
40 | feebp2 := tApp.GetTaxKeeper().GetFeeBp(ctx)
41 | require.True(t, feebp2 == 11) // not changed
42 | trfbp2 := tApp.GetTaxKeeper().GetTransferBp(ctx)
43 | require.True(t, trfbp2 == 11) // not changed
44 | }
45 |
46 | func Test_handleMsgSetCollector(t *testing.T) {
47 | tApp := app.NewTestApp()
48 | ctx := tApp.NewContext(true, abci.Header{})
49 | tax.InitGenesis(ctx, tApp.GetTaxKeeper(), tax.DefaultGenesisState())
50 |
51 | collector, err := sdk.AccAddressFromBech32("bluzelle1wjkdcz4hl4gcarnqtupu7vkftal6h34qxjh6rw")
52 | if err != nil {
53 | panic(err)
54 | }
55 |
56 | addr1 := sdk.AccAddress([]byte("my----------address1"))
57 |
58 | // try setting collector with incorrect owner
59 | msg1 := types.NewMsgSetCollector(addr1, addr1)
60 | _, err = tax.HandleMsgSetCollector(ctx, tApp.GetTaxKeeper(), msg1)
61 | require.Error(t, err)
62 | owner1 := tApp.GetTaxKeeper().GetCollector(ctx)
63 | require.True(t, !bytes.Equal(owner1, addr1))
64 |
65 | // try setting collector with correct owner
66 | msg2 := types.NewMsgSetCollector(addr1, collector)
67 | _, err = tax.HandleMsgSetCollector(ctx, tApp.GetTaxKeeper(), msg2)
68 | require.NoError(t, err)
69 | owner2 := tApp.GetTaxKeeper().GetCollector(ctx)
70 | require.True(t, bytes.Equal(owner2, addr1))
71 | }
72 |
--------------------------------------------------------------------------------
/x/tax/internal/keeper/keeper_test.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestKeeper_Collector(t *testing.T) {
8 |
9 | }
10 |
11 | func TestKeeper_Bp(t *testing.T) {
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/x/tax/internal/keeper/querier.go:
--------------------------------------------------------------------------------
1 | package keeper
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 | abci "github.com/tendermint/tendermint/abci/types"
8 | )
9 |
10 | // constants
11 | const (
12 | QueryTaxInfo = "info"
13 | )
14 |
15 | // NewQuerier helps querying
16 | func NewQuerier(keeper IKeeper) sdk.Querier {
17 | return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) {
18 | switch path[0] {
19 | case QueryTaxInfo:
20 | return queryTaxInfo(ctx, keeper)
21 | default:
22 | return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown tax query endpoint")
23 | }
24 | }
25 | }
26 |
27 | func queryTaxInfo(ctx sdk.Context, keeper IKeeper) ([]byte, error) {
28 | taxInfo := keeper.GetTaxInfo(ctx)
29 |
30 | res, err := codec.MarshalJSONIndent(keeper.GetCodec(), taxInfo)
31 | return res, err
32 | }
33 |
--------------------------------------------------------------------------------
/x/tax/internal/keeper/querier_test.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func Test_queryTaxInfo(t *testing.T) {
8 | }
9 |
--------------------------------------------------------------------------------
/x/tax/internal/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | )
6 |
7 | // ModuleCdc is codec for this module
8 | var ModuleCdc = codec.New()
9 |
10 | func init() {
11 | RegisterCodec(ModuleCdc)
12 | }
13 |
14 | // RegisterCodec register codecs for this module
15 | func RegisterCodec(cdc *codec.Codec) {
16 | cdc.RegisterConcrete(MsgSetCollector{}, "tax/collector", nil)
17 | cdc.RegisterConcrete(MsgSetBp{}, "tax/bp", nil)
18 | }
19 |
--------------------------------------------------------------------------------
/x/tax/internal/types/key.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // keys for this module
4 | const (
5 | // module name
6 | ModuleName = "tax"
7 |
8 | // StoreKey to be used when creating the KVStore
9 | StoreKey = ModuleName
10 | RouterKey = ModuleName
11 | )
12 |
--------------------------------------------------------------------------------
/x/tax/internal/types/msg_collector.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 | // MsgSetCollector defines a message to modify collector
9 | type MsgSetCollector struct {
10 | NewCollector sdk.AccAddress
11 | Proposer sdk.AccAddress
12 | }
13 |
14 | // NewMsgSetCollector returns a new instance of MsgSetCollector
15 | func NewMsgSetCollector(newCollector, proposer sdk.AccAddress) MsgSetCollector {
16 |
17 | return MsgSetCollector{
18 | NewCollector: newCollector,
19 | Proposer: proposer,
20 | }
21 | }
22 |
23 | // Route returns MsgSetCollector message route
24 | func (msg MsgSetCollector) Route() string { return RouterKey }
25 |
26 | // Type returns MsgSetCollector message type
27 | func (msg MsgSetCollector) Type() string { return "set_collector" }
28 |
29 | // ValidateBasic do basic validation for MsgSetCollector
30 | func (msg MsgSetCollector) ValidateBasic() error {
31 | if msg.Proposer.Empty() {
32 | return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "proposer should not be empty address")
33 | }
34 | if msg.NewCollector.Empty() {
35 | return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "tax collector should not be empty address")
36 | }
37 |
38 | return nil
39 | }
40 |
41 | // GetSignBytes collect sign bytes from message
42 | func (msg MsgSetCollector) GetSignBytes() []byte {
43 | return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
44 | }
45 |
46 | // GetSigners return signers of this message
47 | func (msg MsgSetCollector) GetSigners() []sdk.AccAddress {
48 | return []sdk.AccAddress{msg.Proposer}
49 | }
50 |
--------------------------------------------------------------------------------
/x/tax/internal/types/msg_collector_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 |
7 | bluzellechain "github.com/bluzelle/curium/types"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | . "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func GetTestAddresses(t *testing.T) []sdk.AccAddress {
13 | addr1 := sdk.AccAddress([]byte("my----------address1"))
14 | addr2 := sdk.AccAddress([]byte("my----------address2"))
15 | return []sdk.AccAddress{addr1, addr2}
16 | }
17 |
18 | func TestNewMsgSetCollector(t *testing.T) {
19 | addrs := GetTestAddresses(t)
20 | proposer, newCollector := addrs[0], addrs[1]
21 |
22 | msg := NewMsgSetCollector(newCollector, proposer)
23 | True(t, bytes.Equal(msg.NewCollector.Bytes(), newCollector.Bytes()))
24 | True(t, bytes.Equal(msg.Proposer.Bytes(), proposer.Bytes()))
25 | }
26 |
27 | func TestMsgSetCollector_Route(t *testing.T) {
28 | Equal(t, MsgSetCollector{}.Route(), RouterKey)
29 | }
30 |
31 | func TestMsgSetCollector_Type(t *testing.T) {
32 | Equal(t, MsgSetCollector{}.Type(), "set_collector")
33 | }
34 |
35 | func TestMsgSetCollector_ValidateBasic(t *testing.T) {
36 | addrs := GetTestAddresses(t)
37 | proposer, newCollector := addrs[0], addrs[1]
38 |
39 | msg := NewMsgSetCollector(newCollector, proposer)
40 | err := msg.ValidateBasic()
41 | True(t, err == nil)
42 |
43 | msg = NewMsgSetCollector(sdk.AccAddress{}, proposer)
44 | err = msg.ValidateBasic()
45 | True(t, err != nil)
46 | Equal(t, err.Error(), "invalid address: tax collector should not be empty address")
47 |
48 | msg = NewMsgSetCollector(newCollector, sdk.AccAddress{})
49 | err = msg.ValidateBasic()
50 | True(t, err != nil)
51 | Equal(t, err.Error(), "invalid address: proposer should not be empty address")
52 | }
53 |
54 | func TestMsgSetCollector_GetSignBytes(t *testing.T) {
55 | config := sdk.GetConfig()
56 | config.SetBech32PrefixForAccount(bluzellechain.Bech32PrefixAccAddr, bluzellechain.Bech32PrefixAccPub)
57 |
58 | addrs := GetTestAddresses(t)
59 | proposer, newCollector := addrs[0], addrs[1]
60 | msg := NewMsgSetCollector(newCollector, proposer)
61 | Equal(t, string(msg.GetSignBytes()), `{"type":"tax/collector","value":{"NewCollector":"bluzelle1d4uj6tfd95kj6tfd95kkzerywfjhxuejgs5ltx","Proposer":"bluzelle1d4uj6tfd95kj6tfd95kkzerywfjhxue3xrpf9e"}}`)
62 | }
63 |
64 | func TestMsgSetCollector_GetSigners(t *testing.T) {
65 | addrs := GetTestAddresses(t)
66 | proposer, newCollector := addrs[0], addrs[1]
67 | msg := NewMsgSetCollector(newCollector, proposer)
68 | Equal(t, msg.GetSigners(), []sdk.AccAddress{proposer})
69 | }
70 |
--------------------------------------------------------------------------------
/x/tax/internal/types/msg_percentage.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 | // MsgSetBp defines a message to modify collector
9 | type MsgSetBp struct {
10 | NewFeeBp int64
11 | NewTransferBp int64
12 | Proposer sdk.AccAddress
13 | }
14 |
15 | // NewMsgSetBp returns a new instance of MsgSetBp
16 | func NewMsgSetBp(newFeeBp int64, newTransferBp int64, proposer sdk.AccAddress) MsgSetBp {
17 | return MsgSetBp{
18 | NewTransferBp: newTransferBp,
19 | NewFeeBp: newFeeBp,
20 | Proposer: proposer,
21 | }
22 | }
23 |
24 | // Route returns MsgSetBp message route
25 | func (msg MsgSetBp) Route() string { return RouterKey }
26 |
27 | // Type returns MsgSetBp message type
28 | func (msg MsgSetBp) Type() string { return "set_bp" }
29 |
30 | // ValidateBasic do basic validation for MsgSetBp
31 | func (msg MsgSetBp) ValidateBasic() error {
32 | if msg.Proposer.Empty() {
33 | return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "proposer should not be empty address")
34 | }
35 | if msg.NewFeeBp < 0 {
36 | return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "tax should not be negative")
37 | }
38 | if msg.NewFeeBp > 10000 {
39 | return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "tax should not exceed 10000 bp")
40 | }
41 | if msg.NewTransferBp < 0 {
42 | return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "tax should not be negative")
43 | }
44 | if msg.NewTransferBp > 10000 {
45 | return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "tax should not exceed 10000 bp")
46 | }
47 |
48 | return nil
49 | }
50 |
51 | // GetSignBytes collect sign bytes from message
52 | func (msg MsgSetBp) GetSignBytes() []byte {
53 | return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
54 | }
55 |
56 | // GetSigners return signers of this message
57 | func (msg MsgSetBp) GetSigners() []sdk.AccAddress {
58 | return []sdk.AccAddress{msg.Proposer}
59 | }
60 |
--------------------------------------------------------------------------------
/x/tax/internal/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | // TaxInfo is struct for tax querying
6 | type TaxInfo struct {
7 | Collector sdk.AccAddress
8 | FeeBp int64
9 | TransferBp int64
10 | }
11 |
--------------------------------------------------------------------------------
/x/tax/internal/types/types_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | delay@^5.0.0:
6 | version "5.0.0"
7 | resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
8 | integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
9 |
--------------------------------------------------------------------------------