├── .build.sh
├── .dockerignore
├── .gitattributes
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ ├── feature-request.md
│ └── issue-template.md
├── PULL_REQUEST_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE
│ ├── docs.md
│ ├── others.md
│ └── production.md
├── codecov.yml
├── stale.yml
└── workflows
│ ├── codeql-analysis.yml
│ ├── docker-push.yml
│ ├── lint.yml
│ ├── md-link-checker.yml
│ ├── nightly-tests.yml
│ ├── release-sims.yml
│ ├── release.yml
│ ├── sim-label.yml
│ ├── sims.yml
│ ├── stale.yml
│ └── test.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .mergify.yml
├── ATTRIBUTION
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── RELEASES.md
├── RELEASE_PROCESS.md
├── SECURITY.md
├── STATE-COMPATIBILITY.md
├── UPGRADING.md
├── ante
├── ante.go
├── gov_vote_ante.go
└── gov_vote_ante_test.go
├── api
└── atomone
│ ├── feemarket
│ ├── module
│ │ └── v1
│ │ │ └── module.pulsar.go
│ └── v1
│ │ ├── genesis.pulsar.go
│ │ ├── params.pulsar.go
│ │ ├── query.pulsar.go
│ │ ├── query_grpc.pb.go
│ │ ├── tx.pulsar.go
│ │ └── tx_grpc.pb.go
│ ├── gov
│ ├── module
│ │ └── v1
│ │ │ └── module.pulsar.go
│ ├── v1
│ │ ├── genesis.pulsar.go
│ │ ├── gov.pulsar.go
│ │ ├── query.pulsar.go
│ │ ├── query_grpc.pb.go
│ │ ├── tx.pulsar.go
│ │ └── tx_grpc.pb.go
│ └── v1beta1
│ │ ├── genesis.pulsar.go
│ │ ├── gov.pulsar.go
│ │ ├── query.pulsar.go
│ │ ├── query_grpc.pb.go
│ │ ├── tx.pulsar.go
│ │ └── tx_grpc.pb.go
│ └── photon
│ └── v1
│ ├── genesis.pulsar.go
│ ├── photon.pulsar.go
│ ├── query.pulsar.go
│ ├── query_grpc.pb.go
│ ├── tx.pulsar.go
│ └── tx_grpc.pb.go
├── app
├── app.go
├── app_helpers.go
├── app_test.go
├── const.go
├── encoding.go
├── export.go
├── genesis.go
├── genesis_account.go
├── genesis_account_fuzz_test.go
├── gov_handlers.go
├── helpers
│ └── test_helpers.go
├── keepers
│ ├── keepers.go
│ └── keys.go
├── modules.go
├── params
│ ├── amino.go
│ ├── config.go
│ ├── doc.go
│ ├── encoding.go
│ ├── proto.go
│ └── weights.go
├── sim
│ ├── sim_config.go
│ ├── sim_state.go
│ └── sim_utils.go
├── sim_bench_test.go
├── sim_test.go
└── upgrades
│ ├── types.go
│ ├── v2
│ ├── constants.go
│ └── upgrades.go
│ └── v3
│ ├── constants.go
│ └── upgrades.go
├── buf.work.yaml
├── client
└── docs
│ ├── config.json
│ ├── statik
│ └── statik.go
│ └── swagger-ui
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── index.html
│ ├── oauth2-redirect.html
│ ├── swagger-ui-bundle.js
│ ├── swagger-ui-bundle.js.map
│ ├── swagger-ui-es-bundle-core.js
│ ├── swagger-ui-es-bundle-core.js.map
│ ├── swagger-ui-es-bundle.js
│ ├── swagger-ui-es-bundle.js.map
│ ├── swagger-ui-standalone-preset.js
│ ├── swagger-ui-standalone-preset.js.map
│ ├── swagger-ui.css
│ ├── swagger-ui.css.map
│ ├── swagger-ui.js
│ ├── swagger-ui.js.map
│ └── swagger.yaml
├── cmd
└── atomoned
│ ├── cmd
│ ├── bech32_convert.go
│ ├── config.go
│ ├── genaccounts.go
│ ├── root.go
│ ├── root_test.go
│ ├── testnet.go
│ └── tx.go
│ └── main.go
├── contrib
├── Dockerfile.test
├── denom.json
├── devdeps
│ ├── go.mod
│ ├── go.sum
│ └── tools.go
├── generate_release_note
│ └── main.go
├── get_node.sh
├── githooks
│ ├── README.md
│ ├── pre-commit
│ └── precommit
├── localnet
│ ├── proposal_legacy_param_change.json
│ ├── proposal_text.json
│ └── proposal_upgrade.json
├── scripts
│ ├── local-atomone.sh
│ └── test_localnet_liveness.sh
└── single-node.sh
├── docs
├── AtomOne - Zellic Audit Report.pdf
├── README.md
└── architecture
│ ├── PROCESS.md
│ ├── README.md
│ ├── adr-001-late-quorum-extension.md
│ ├── adr-002-photon-token.md
│ ├── adr-003-governance-proposal-deposit-auto-throttler.md
│ ├── adr-004-nakamoto-bonus.md
│ ├── adr-template.md
│ ├── demo
│ ├── NakamotoBonus.ipynb
│ └── README_NakamotoBonus.md
│ └── img
│ ├── adr-001-voting-period-extension-late-quorum-case1.png
│ └── adr-001-voting-period-extension-late-quorum-case2.png
├── e2e.Dockerfile
├── go.mod
├── go.sum
├── mlc_config.json
├── pkg
└── address
│ ├── address.go
│ └── address_test.go
├── post
└── post.go
├── proto
├── atomone
│ ├── feemarket
│ │ ├── module
│ │ │ └── v1
│ │ │ │ └── module.proto
│ │ └── v1
│ │ │ ├── genesis.proto
│ │ │ ├── params.proto
│ │ │ ├── query.proto
│ │ │ └── tx.proto
│ ├── gov
│ │ ├── module
│ │ │ └── v1
│ │ │ │ └── module.proto
│ │ ├── v1
│ │ │ ├── genesis.proto
│ │ │ ├── gov.proto
│ │ │ ├── query.proto
│ │ │ └── tx.proto
│ │ └── v1beta1
│ │ │ ├── genesis.proto
│ │ │ ├── gov.proto
│ │ │ ├── query.proto
│ │ │ └── tx.proto
│ └── photon
│ │ └── v1
│ │ ├── genesis.proto
│ │ ├── photon.proto
│ │ ├── query.proto
│ │ └── tx.proto
├── buf.gen.gogo.yaml
├── buf.gen.pulsar.yaml
├── buf.gen.swagger.yaml
├── buf.lock
├── buf.yaml
└── scripts
│ ├── protoc-swagger-gen.sh
│ ├── protocgen-pulsar.sh
│ └── protocgen.sh
├── sims.mk
├── tests
└── e2e
│ ├── address.go
│ ├── chain_test.go
│ ├── doc.go
│ ├── docker
│ └── hermes.Dockerfile
│ ├── e2e_bank_test.go
│ ├── e2e_distribution_test.go
│ ├── e2e_encode_test.go
│ ├── e2e_evidence_test.go
│ ├── e2e_exec_test.go
│ ├── e2e_feegrant_test.go
│ ├── e2e_feemarket_test.go
│ ├── e2e_gov_test.go
│ ├── e2e_ibc_test.go
│ ├── e2e_photon_test.go
│ ├── e2e_rest_regression_test.go
│ ├── e2e_setup_test.go
│ ├── e2e_slashing_test.go
│ ├── e2e_staking_test.go
│ ├── e2e_test.go
│ ├── e2e_vesting_test.go
│ ├── genesis_test.go
│ ├── http_util_test.go
│ ├── io.go
│ ├── keys.go
│ ├── query_test.go
│ ├── scripts
│ └── hermes_bootstrap.sh
│ ├── util_test.go
│ └── validator_test.go
├── types
└── errors
│ └── errors.go
└── x
├── feemarket
├── AIMD.md
├── CLIENTS.md
├── README.md
├── ante
│ ├── expected_keepers.go
│ ├── expected_keepers_mocks_test.go
│ ├── fee.go
│ └── fee_test.go
├── client
│ └── cli
│ │ └── query.go
├── fuzz
│ ├── aimd_eip1559_test.go
│ ├── eip1559_test.go
│ └── tx_priority_test.go
├── keeper
│ ├── abci.go
│ ├── feemarket.go
│ ├── feemarket_test.go
│ ├── genesis.go
│ ├── genesis_test.go
│ ├── keeper.go
│ ├── keeper_test.go
│ ├── msg_server.go
│ ├── msg_server_test.go
│ ├── query_server.go
│ └── query_server_test.go
├── module.go
├── module_simulation.go
├── post
│ ├── expected_keepers.go
│ ├── expected_keepers_mocks_test.go
│ ├── post.go
│ └── post_test.go
├── testutil
│ ├── expected_keepers_mocks.go
│ └── keeper.go
└── types
│ ├── codec.go
│ ├── eip1559.go
│ ├── eip1559_aimd.go
│ ├── errors.go
│ ├── expected_keepers.go
│ ├── genesis.go
│ ├── genesis.pb.go
│ ├── genesis_test.go
│ ├── keys.go
│ ├── msgs.go
│ ├── msgs_test.go
│ ├── params.go
│ ├── params.pb.go
│ ├── params_test.go
│ ├── query.pb.go
│ ├── query.pb.gw.go
│ ├── resolver.go
│ ├── state.go
│ ├── state_fuzz_test.go
│ ├── state_test.go
│ └── tx.pb.go
├── gov
├── README.md
├── abci.go
├── abci_internal_test.go
├── abci_test.go
├── autocli.go
├── client
│ ├── cli
│ │ ├── prompt.go
│ │ ├── prompt_test.go
│ │ ├── query.go
│ │ ├── query_test.go
│ │ ├── tx.go
│ │ ├── tx_test.go
│ │ ├── util.go
│ │ └── util_test.go
│ ├── proposal_handler.go
│ ├── testutil
│ │ └── helpers.go
│ └── utils
│ │ ├── query.go
│ │ ├── query_test.go
│ │ ├── unified_diff.go
│ │ ├── unified_diff_test.go
│ │ ├── utils.go
│ │ └── utils_test.go
├── codec
│ ├── cdc.go
│ └── doc.go
├── common_test.go
├── exported
│ └── exported.go
├── genesis.go
├── genesis_test.go
├── keeper
│ ├── common_test.go
│ ├── constitution.go
│ ├── constitution_test.go
│ ├── deposit.go
│ ├── deposit_test.go
│ ├── export_test.go
│ ├── grpc_query.go
│ ├── grpc_query_test.go
│ ├── hooks_test.go
│ ├── internal_test.go
│ ├── invariants.go
│ ├── keeper.go
│ ├── keeper_test.go
│ ├── migrations.go
│ ├── min_deposit.go
│ ├── min_deposit_test.go
│ ├── min_initial_deposit.go
│ ├── min_initial_deposit_test.go
│ ├── msg_server.go
│ ├── msg_server_test.go
│ ├── params.go
│ ├── proposal.go
│ ├── proposal_test.go
│ ├── tally.go
│ ├── tally_test.go
│ ├── vote.go
│ └── vote_test.go
├── migrations
│ ├── v3
│ │ ├── convert.go
│ │ └── keys.go
│ └── v5
│ │ ├── store.go
│ │ └── store_test.go
├── module.go
├── simulation
│ ├── decoder.go
│ ├── decoder_test.go
│ ├── genesis.go
│ ├── genesis_test.go
│ ├── operations.go
│ ├── operations_test.go
│ ├── proposals.go
│ └── proposals_test.go
├── testutil
│ ├── configurator.go
│ ├── expected_keepers.go
│ └── expected_keepers_mocks.go
└── types
│ ├── config.go
│ ├── errors.go
│ ├── events.go
│ ├── expected_keepers.go
│ ├── hooks.go
│ ├── keys.go
│ ├── keys_test.go
│ ├── metadata.go
│ ├── unified_diff.go
│ ├── unified_diff_test.go
│ ├── v1
│ ├── codec.go
│ ├── content.go
│ ├── deposit.go
│ ├── genesis.go
│ ├── genesis.pb.go
│ ├── genesis_test.go
│ ├── gov.pb.go
│ ├── min_deposit.go
│ ├── min_deposit_test.go
│ ├── msgs.go
│ ├── msgs_test.go
│ ├── params.go
│ ├── params_legacy.go
│ ├── proposal.go
│ ├── proposals_test.go
│ ├── querier.go
│ ├── query.pb.go
│ ├── query.pb.gw.go
│ ├── quorum_check.go
│ ├── tally.go
│ ├── tx.pb.go
│ └── vote.go
│ └── v1beta1
│ ├── codec.go
│ ├── content.go
│ ├── deposit.go
│ ├── genesis.go
│ ├── genesis.pb.go
│ ├── gov.pb.go
│ ├── msgs.go
│ ├── msgs_test.go
│ ├── params.go
│ ├── proposal.go
│ ├── proposals_test.go
│ ├── querier.go
│ ├── query.pb.go
│ ├── query.pb.gw.go
│ ├── router.go
│ ├── tally.go
│ ├── tx.pb.go
│ └── vote.go
└── photon
├── README.md
├── ante
├── ante.go
├── ante_test.go
├── expected_keepers.go
└── expected_keepers_mocks_test.go
├── client
└── cli
│ ├── query.go
│ └── tx.go
├── genesis.go
├── genesis_test.go
├── keeper
├── grpc_query.go
├── grpc_query_test.go
├── keeper.go
├── msg_server.go
├── msg_server_test.go
├── params.go
├── params_test.go
└── resolver.go
├── module.go
├── module_simulation.go
├── simulation
├── decoder.go
├── genesis.go
├── operations.go
└── proposals.go
├── testutil
├── expected_keepers_mocks.go
└── keeper.go
└── types
├── codec.go
├── const.go
├── errors.go
├── events.go
├── expected_keepers.go
├── genesis.go
├── genesis.pb.go
├── genesis_test.go
├── keys.go
├── msgs.go
├── msgs_test.go
├── params.go
├── photon.pb.go
├── query.pb.go
├── query.pb.gw.go
├── tx.pb.go
└── types.go
/.build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -ue
4 |
5 | # Expect the following envvars to be set:
6 | # - APP
7 | # - VERSION
8 | # - COMMIT
9 | # - TARGET_OS
10 | # - LEDGER_ENABLED
11 | # - DEBUG
12 |
13 | # Source builder's functions library
14 | . /usr/local/share/tendermint/buildlib.sh
15 |
16 | # These variables are now available
17 | # - BASEDIR
18 | # - OUTDIR
19 |
20 | # Build for each os-architecture pair
21 | for platform in ${TARGET_PLATFORMS} ; do
22 | # This function sets GOOS, GOARCH, and OS_FILE_EXT environment variables
23 | # according to the build target platform. OS_FILE_EXT is empty in all
24 | # cases except when the target platform is 'windows'.
25 | setup_build_env_for_platform "${platform}"
26 |
27 | make clean
28 | echo Building for $(go env GOOS)/$(go env GOARCH) >&2
29 | GOROOT_FINAL="$(go env GOROOT)" \
30 | make build \
31 | LDFLAGS=-buildid=${VERSION} \
32 | VERSION=${VERSION} \
33 | COMMIT=${COMMIT} \
34 | LEDGER_ENABLED=${LEDGER_ENABLED}
35 | mv ./build/${APP}${OS_FILE_EXT} ${OUTDIR}/${APP}-${VERSION}-$(go env GOOS)-$(go env GOARCH)${OS_FILE_EXT}
36 |
37 | # This function restore the build environment variables to their
38 | # original state.
39 | restore_build_env
40 | done
41 |
42 | # Generate and display build report.
43 | generate_build_report
44 | cat ${OUTDIR}/build_report
45 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | .github
4 | .vscode
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/.gitattributes
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # CODEOWNERS: https://help.github.com/articles/about-codeowners/
2 |
3 | # Primary repo maintainers
4 | * @giunatale @tbruyelle @jaekwon @giuliostramondo
5 |
6 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Create a report to help us squash bugs!
4 | labels: bug, needs-triage
5 | ---
6 |
7 |
12 |
13 | ## Summary of Bug
14 |
15 |
16 |
17 | ## Version
18 |
19 |
20 |
21 | ## Steps to Reproduce
22 |
23 |
24 |
25 | ____
26 |
27 | #### For Admin Use
28 |
29 | - [ ] Not duplicate issue
30 | - [ ] Appropriate labels applied
31 | - [ ] Appropriate contributors tagged
32 | - [ ] Contributor assigned/self-assigned
33 | - [ ] Is a spike necessary to map out how the issue should be approached?
34 |
35 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Create a proposal to request a feature
4 | labels: enhancement, epic, needs-triage
5 | ---
6 |
7 |
13 |
14 | ## Summary
15 |
16 |
17 |
18 | ## Problem Definition
19 |
20 |
24 |
25 | ## Proposal
26 |
27 |
28 |
29 | ## Task list
30 |
31 | ```[tasklist]
32 | ### Must have
33 | - [ ] discuss proposal (if proposal rejected, close EPIC)
34 | - [ ] create ADR (if ADR rejected, close EPIC)
35 | - [ ] add sub-tasks needed to implement the proposed feature
36 | ```
37 |
38 | ```[tasklist]
39 | ### Nice to have
40 | - [ ] add sub-tasks that are nice to have for the proposed feature
41 | ```
42 | ____
43 |
44 | #### For Admin Use
45 |
46 | - [ ] Not duplicate issue
47 | - [ ] Appropriate labels applied
48 | - [ ] Appropriate contributors tagged
49 | - [ ] Contributor assigned/self-assigned
50 | - [ ] Is a spike necessary to map out how the issue should be approached?
51 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Issue Template
3 | about: Basic template for issues (used by the team)
4 | labels: needs-triage
5 | ---
6 |
7 |
12 |
13 | # Problem
14 |
15 |
16 |
17 | # Closing criteria
18 |
19 |
20 |
21 |
22 | # Problem details
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Please go the the `Preview` tab and select the appropriate sub-template:
2 |
3 | * [Production code](?expand=1&template=production.md) - for types `fix`, `feat`, and `refactor`.
4 | * [Docs](?expand=1&template=docs.md) - for documentation changes.
5 | * [Others](?expand=1&template=others.md) - for changes that do not affect production code.
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/docs.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Closes: #XXXX
4 |
5 |
7 |
8 |
9 | ---
10 |
11 | ### Author Checklist
12 |
13 | *All items are required. Please add a note to the item if the item is not applicable and
14 | please add links to any relevant follow up issues.*
15 |
16 | I have...
17 |
18 | - [ ] included the correct `docs:` prefix in the PR title
19 | - [ ] targeted the correct branch (see [PR Targeting](https://github.com/atomone-hub/atomone/blob/main/CONTRIBUTING.md#pr-targeting))
20 | - [ ] provided a link to the relevant issue or specification
21 | - [ ] reviewed "Files changed" and left comments if necessary
22 | - [ ] confirmed all CI checks have passed
23 |
24 | ### Reviewers Checklist
25 |
26 | *All items are required. Please add a note if the item is not applicable and please add
27 | your handle next to the items reviewed if you only reviewed selected items.*
28 |
29 | I have...
30 |
31 | - [ ] Confirmed the correct `docs:` prefix in the PR title
32 | - [ ] Confirmed all author checklist items have been addressed
33 | - [ ] Confirmed that this PR only changes documentation
34 | - [ ] Reviewed content for consistency
35 | - [ ] Reviewed content for thoroughness
36 | - [ ] Reviewed content for spelling and grammar
37 | - [ ] Tested instructions (if applicable)
38 |
39 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/others.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Closes: #XXXX
4 |
5 |
7 |
8 | ---
9 |
10 | ### Author Checklist
11 |
12 | *All items are required. Please add a note to the item if the item is not applicable and
13 | please add links to any relevant follow up issues.*
14 |
15 | I have...
16 |
17 | - [ ] Included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
18 | - [ ] Targeted the correct branch (see [PR Targeting](https://github.com/atomone-hub/atomone/blob/main/CONTRIBUTING.md#pr-targeting))
19 | - [ ] Provided a link to the relevant issue or specification
20 | - [ ] Reviewed "Files changed" and left comments if necessary
21 | - [ ] Confirmed all CI checks have passed
22 |
23 | ### Reviewers Checklist
24 |
25 | *All items are required. Please add a note if the item is not applicable and please add
26 | your handle next to the items reviewed if you only reviewed selected items.*
27 |
28 | I have...
29 |
30 | - [ ] Confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
31 | - [ ] Confirmed all author checklist items have been addressed
32 | - [ ] Confirmed that this PR does not change production code
33 |
34 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE/production.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | ## Description
6 |
7 | Closes: #XXXX
8 |
9 |
11 |
12 |
13 |
14 | ---
15 |
16 | ### Author Checklist
17 |
18 | *All items are required. Please add a note to the item if the item is not applicable and
19 | please add links to any relevant follow up issues.*
20 |
21 | I have...
22 |
23 | * [ ] Included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
24 | * [ ] Added `!` to the type prefix if API, client, or state breaking change (i.e., requires minor or major version bump)
25 | * [ ] Targeted the correct branch (see [PR Targeting](https://github.com/atomone-hub/atomone/blob/main/CONTRIBUTING.md#pr-targeting))
26 | * [ ] Provided a link to the relevant issue or specification
27 | * [ ] Followed the guidelines for [building SDK modules](https://github.com/atomone-hub/atomone/blob/main/docs/docs/building-modules)
28 | * [ ] Included the necessary unit and integration [tests](https://github.com/atomone-hub/atomone/blob/main/CONTRIBUTING.md#testing)
29 | * [ ] Added a changelog entry in `.changelog` (for details, see [contributing guidelines](../../CONTRIBUTING.md#changelog))
30 | * [ ] Included comments for [documenting Go code](https://blog.golang.org/godoc)
31 | * [ ] Updated the relevant documentation or specification
32 | * [ ] Reviewed "Files changed" and left comments if necessary
33 | * [ ] Confirmed all CI checks have passed
34 |
35 | ### Reviewers Checklist
36 |
37 | *All items are required. Please add a note if the item is not applicable and please add
38 | your handle next to the items reviewed if you only reviewed selected items.*
39 |
40 | I have...
41 |
42 | * [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
43 | * [ ] confirmed `!` in the type prefix if API or client breaking change
44 | * [ ] confirmed all author checklist items have been addressed
45 | * [ ] reviewed state machine logic
46 | * [ ] reviewed API design and naming
47 | * [ ] reviewed documentation is accurate
48 | * [ ] reviewed tests and test coverage
49 |
--------------------------------------------------------------------------------
/.github/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 | precision: 2
3 | round: down
4 | range: 70...100
5 | status:
6 | project:
7 | default:
8 | threshold: 1% # allow this much decrease on project
9 | app:
10 | target: 80%
11 | paths: # this must be a list type
12 | - "app/"
13 | changes: false
14 |
15 | comment:
16 | layout: "reach, diff, files"
17 | behavior: default # update if exists else create new
18 | require_changes: true
19 |
20 | ignore:
21 | - "*.pb.go"
22 | - "*.pb.gw.go"
23 | - "*.md"
24 | - "*.rst"
25 | - "cmd"
26 | - "client"
27 | - "contrib"
28 | - "docs"
29 | - "proto"
30 | - "tests/e2e"
31 | - "app/app_helpers.go"
32 | - "app/sim"
33 | - "app/upgrades"
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for probot-stale - https://github.com/probot/stale
2 |
3 | # Number of days of inactivity before an Issue or Pull Request becomes stale
4 | daysUntilStale: 10
5 |
6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
8 | daysUntilClose: 4
9 |
10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
11 | onlyLabels: []
12 |
13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
14 | exemptLabels:
15 | - blocked
16 | - pinned
17 | - security
18 |
19 | # Set to true to ignore issues in a project (defaults to false)
20 | exemptProjects: true
21 |
22 | # Set to true to ignore issues in a milestone (defaults to false)
23 | exemptMilestones: true
24 |
25 | # Label to use when marking as stale
26 | staleLabel: stale
27 |
28 | # Comment to post when marking as stale. Set to `false` to disable
29 | markComment: >
30 | This issue has been automatically marked as stale because it has not had
31 | recent activity. It will be closed if no further activity occurs. Thank you
32 | for your contributions.
33 | # Limit the number of actions per hour, from 1-30. Default is 30
34 | limitPerRun: 30
35 |
36 | # Limit to only `issues` or `pulls`
37 | only: pulls
38 |
39 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
40 | pulls:
41 | daysUntilStale: 30
42 | markComment: >
43 | This pull request has been automatically marked as stale because it has not had
44 | recent activity. It will be closed if no further activity occurs. Thank you
45 | for your contributions.
46 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - "**.go"
7 | push:
8 | branches:
9 | - main
10 | - release/v*
11 | - feat/**
12 | paths:
13 | - "**.go"
14 |
15 | jobs:
16 | analyze:
17 | name: Analyze
18 | runs-on: ubuntu-latest
19 | permissions:
20 | actions: read
21 | contents: read
22 | security-events: write
23 |
24 | steps:
25 | - name: Checkout repository
26 | uses: actions/checkout@v4
27 | - uses: actions/setup-go@v5
28 | with:
29 | go-version-file: go.mod
30 |
31 | # Initializes the CodeQL tools for scanning.
32 | - name: Initialize CodeQL
33 | uses: github/codeql-action/init@v3
34 | with:
35 | languages: "go"
36 | # If you wish to specify custom queries, you can do so here or in a config file.
37 | # By default, queries listed here will override any specified in a config file.
38 | # Prefix the list here with "+" to use these queries and those in the config file.
39 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
40 | queries: +security-and-quality,github/codeql/go/ql/src/experimental/InconsistentCode/DeferInLoop.ql@main,github/codeql/go/ql/src/experimental/Unsafe/WrongUsageOfUnsafe.ql@main,github/codeql/go/ql/src/experimental/CWE-369/DivideByZero.ql@main
41 | packs: +crypto-com/cosmos-sdk-codeql
42 |
43 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
44 | # If this step fails, then you should remove it and run the build manually (see below)
45 | - name: Autobuild
46 | uses: github/codeql-action/autobuild@v3
47 |
48 | # ℹ️ Command-line programs to run using the OS shell.
49 | # 📚 https://git.io/JvXDl
50 |
51 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
52 | # and modify them (or add more) to build your code if your project
53 | # uses a compiled language
54 |
55 | #- run: |
56 | # make bootstrap
57 | # make release
58 |
59 | - name: Perform CodeQL Analysis
60 | uses: github/codeql-action/analyze@v3
61 |
--------------------------------------------------------------------------------
/.github/workflows/docker-push.yml:
--------------------------------------------------------------------------------
1 | # source: https://docs.github.com/en/enterprise-cloud@latest/actions/publishing-packages/publishing-docker-images
2 | name: Create and publish a Docker image
3 |
4 | on:
5 | push:
6 | branches: ['release']
7 |
8 | env:
9 | REGISTRY: ghcr.io
10 | IMAGE_NAME: ${{ github.repository }}
11 |
12 | jobs:
13 | build-and-push-image:
14 | runs-on: ubuntu-latest
15 | permissions:
16 | contents: read
17 | packages: write
18 |
19 | steps:
20 | - name: Checkout repository
21 | uses: actions/checkout@v4
22 |
23 | - name: Log in to the Container registry
24 | uses: docker/login-action@v3.0.0
25 | with:
26 | registry: ${{ env.REGISTRY }}
27 | username: ${{ github.actor }}
28 | password: ${{ secrets.GITHUB_TOKEN }}
29 |
30 | - name: Extract metadata (tags, labels) for Docker
31 | id: meta
32 | uses: docker/metadata-action@v5.5.1
33 | with:
34 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
35 |
36 | - name: Build and push Docker image
37 | uses: docker/build-push-action@v5.1.0
38 | with:
39 | context: .
40 | push: true
41 | tags: ${{ steps.meta.outputs.tags }}
42 | labels: ${{ steps.meta.outputs.labels }}
43 |
44 | - name: Build and push e2e docker image
45 | uses: docker/build-push-action@v5.1.0
46 | with:
47 | context: .
48 | file: Dockerfile.e2e
49 | push: true
50 | tags: ${{ steps.meta.outputs.tags }}-e2e
51 | labels: ${{ steps.meta.outputs.labels }}
52 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 | on:
3 | push:
4 | branches:
5 | - main
6 | - release/**
7 | - feat/**
8 | pull_request:
9 | permissions:
10 | contents: read
11 | jobs:
12 | golangci:
13 | name: golangci-lint
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v4
17 | - uses: actions/setup-go@v5
18 | with:
19 | go-version-file: go.mod
20 | - uses: technote-space/get-diff-action@v6.1.2
21 | id: git_diff
22 | with:
23 | PATTERNS: |
24 | **/*.go
25 | go.mod
26 | go.sum
27 | **/go.mod
28 | **/go.sum
29 | - name: run linting
30 | if: env.GIT_DIFF
31 | run: |
32 | make lint
33 |
--------------------------------------------------------------------------------
/.github/workflows/md-link-checker.yml:
--------------------------------------------------------------------------------
1 | name: Check Markdown links
2 | on:
3 | workflow_dispatch:
4 | schedule:
5 | - cron: '* */24 * * *'
6 | jobs:
7 | markdown-link-check:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | - uses: gaurav-nelson/github-action-markdown-link-check@1.0.15
12 | with:
13 | folder-path: "docs"
--------------------------------------------------------------------------------
/.github/workflows/nightly-tests.yml:
--------------------------------------------------------------------------------
1 | name: "Nightly E2E run"
2 | on:
3 | workflow_call:
4 | workflow_dispatch:
5 | schedule:
6 | # run every day at 03:00 UTC
7 | - cron: "0 3 * * *"
8 |
9 | jobs:
10 |
11 | run-tests:
12 | uses: atomone-hub/atomone/.github/workflows/test.yml@main
13 |
14 | run-simulations:
15 | uses: atomone-hub/atomone/.github/workflows/sims.yml@main
16 |
17 | run-vulncheck:
18 | runs-on: ubuntu-latest
19 | timeout-minutes: 5
20 | steps:
21 | - uses: actions/checkout@v4
22 | - uses: actions/setup-go@v5
23 | with:
24 | go-version-file: go.mod
25 | - name: run-vulncheck
26 | id: vulncheck
27 | run: make vulncheck
28 |
29 | warn-if-failure:
30 | if: failure()
31 | needs: [ run-tests, run-vulncheck, run-simulations]
32 | runs-on: ubuntu-latest
33 | steps:
34 | - name: Notify Slack on failure
35 | uses: slackapi/slack-github-action@v1.25.0
36 | env:
37 | SLACK_WEBHOOK_URL: ${{ secrets.NIGHTLY_E2E_SLACK_WEBHOOK_URL }}
38 | SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
39 | BRANCH: ${{ github.ref_name }}
40 | RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
41 | COMMITS_URL: "${{ github.server_url }}/${{ github.repository }}/commits/${{ github.ref_name }}"
42 | with:
43 | payload: |
44 | {
45 | "blocks": [
46 | {
47 | "type": "header",
48 | "text": {
49 | "type": "plain_text",
50 | "text": "❗Nightly tests failed",
51 | "emoji": true
52 | }
53 | },
54 | {
55 | "type": "section",
56 | "text": {
57 | "type": "mrkdwn",
58 | "text": "See the <${{ env.RUN_URL }}|run details>"
59 | }
60 | }
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: "Release"
2 |
3 | on:
4 | # can be used to re-release an existing tag
5 | workflow_dispatch:
6 |
7 | push:
8 | tags:
9 | - "v[0-9]+\\.[0-9]+\\.[0-9]+"
10 | - "v[0-9]+\\.[0-9]+\\.[0-9]+-rc[0-9]+"
11 |
12 | jobs:
13 | release:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Checkout
17 | uses: actions/checkout@v4
18 | with:
19 | fetch-depth: 0
20 | - run: git fetch --force --tags
21 |
22 | - uses: actions/setup-go@v5
23 | with:
24 | go-version-file: go.mod
25 |
26 | - name: Set Env
27 | run: echo "TM_VERSION=$(make print_tm_version)" >> $GITHUB_ENV
28 |
29 | - name: Release
30 | uses: goreleaser/goreleaser-action@v5
31 | with:
32 | version: v1.25.1
33 | args: release --clean
34 | env:
35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36 |
--------------------------------------------------------------------------------
/.github/workflows/sim-label.yml:
--------------------------------------------------------------------------------
1 | name: SimLabeled
2 | on:
3 | pull_request:
4 | types: [ labeled ]
5 |
6 | jobs:
7 | cleanup-runs:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: rokroskar/workflow-run-cleanup-action@master
11 | env:
12 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
13 | # if: "!startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main'"
14 |
15 | newbuild:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/setup-go@v5
19 | - name: Install runsim
20 | run: go install github.com/cosmos/tools/cmd/runsim@v1.0.0
21 | - uses: actions/cache@v4
22 | with:
23 | path: ~/go/bin
24 | key: ${{ runner.os }}-go-runsim-binary
25 |
26 | test-sim-nondeterminism-labeled:
27 | if: ${{ github.event.label.name == 'sim' }}
28 | runs-on: ubuntu-latest
29 | needs: newbuild
30 | steps:
31 | - uses: actions/checkout@v4
32 | - uses: actions/setup-go@v5
33 | with:
34 | go-version-file: go.mod
35 | - uses: actions/cache@v4
36 | with:
37 | path: ~/go/bin
38 | key: ${{ runner.os }}-go-runsim-binary
39 | - name: test nondeterminism
40 | run: |
41 | make test-sim-nondeterminism
42 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: "Close stale pull requests"
2 | on:
3 | schedule:
4 | - cron: "0 0 * * 1-5"
5 |
6 | jobs:
7 | stale:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/stale@v9.0.0
11 | with:
12 | repo-token: ${{ secrets.GITHUB_TOKEN }}
13 | stale-pr-message: "This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
14 | days-before-stale: -1
15 | days-before-close: -1
16 | days-before-pr-stale: 45
17 | days-before-pr-close: 6
18 | exempt-pr-labels: "pinned, security, proposal, blocked, ADR"
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS
2 | .DS_Store
3 | *.swp
4 | *.swo
5 | *.swl
6 | *.swm
7 | *.swn
8 | .vscode
9 | .idea
10 |
11 | # Build
12 | artifacts
13 | vendor
14 | build
15 | tools/bin/*
16 | examples/build/*
17 | docs/_build
18 | docs/node_modules
19 | docs/tutorial
20 | dist
21 | tools-stamp
22 | docs/node_modules
23 |
24 | # Data - ideally these don't exist
25 | baseapp/data/*
26 | client/lcd/keys/*
27 | mytestnet
28 |
29 | # Testing
30 | coverage.txt
31 | profile.out
32 |
33 | # Vagrant
34 | .vagrant/
35 | *.box
36 | *.log
37 | vagrant
38 |
39 | # IDE
40 | .idea/
41 | *.iml
42 |
43 | # Graphviz
44 | dependency-graph.png
45 |
46 | # Latex
47 | *.aux
48 | *.out
49 | *.synctex.gz
50 | contract_tests/*
51 |
52 | go.work.sum
53 |
54 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | tests: false
3 | # timeout for analysis, e.g. 30s, 5m, default is 1m
4 | timeout: 5m
5 | skip-dirs:
6 | - tests/
7 | - client/docs/statik
8 |
9 | linters:
10 | disable-all: true
11 | enable:
12 | - dogsled
13 | - errcheck
14 | - exportloopref
15 | - gci
16 | - goconst
17 | - gocritic
18 | - gofumpt
19 | - gosec
20 | - gosimple
21 | - govet
22 | - ineffassign
23 | - misspell
24 | - nakedret
25 | - nolintlint
26 | - staticcheck
27 | - stylecheck
28 | - typecheck
29 | - thelper
30 | - unconvert
31 | - unparam
32 | - unused
33 |
34 | issues:
35 | exclude-rules:
36 | - text: 'Use of weak random number generator'
37 | linters:
38 | - gosec
39 | - text: 'comment on exported var'
40 | linters:
41 | - golint
42 | - text: "don't use an underscore in package name"
43 | linters:
44 | - golint
45 | - text: 'ST1003:'
46 | linters:
47 | - stylecheck
48 | # FIXME: Disabled until golangci-lint updates stylecheck with this fix:
49 | # https://github.com/dominikh/go-tools/issues/389
50 | - text: 'ST1016:'
51 | linters:
52 | - stylecheck
53 | - path: 'migrations'
54 | text: 'SA1019:'
55 | linters:
56 | - staticcheck
57 |
58 | max-issues-per-linter: 10000
59 | max-same-issues: 10000
60 |
61 | linters-settings:
62 | gci:
63 | custom-order: true
64 | sections:
65 | - standard # Standard section: captures all standard packages.
66 | - default # Default section: contains all imports that could not be matched to another section type.
67 | - blank # blank imports
68 | - dot # dot imports
69 | - prefix(github.com/cometbft/cometbft) # comet
70 | - prefix(github.com/cosmos) # cosmos org
71 | - prefix(cosmossdk.io) # new modules
72 | - prefix(github.com/cosmos/cosmos-sdk) # cosmos sdk
73 | - prefix(github.com/atomone-hub/atomone) # AtomOne
74 | dogsled:
75 | max-blank-identifiers: 3
76 | maligned:
77 | # print struct with more effective memory layout or not, false by default
78 | suggest-new: true
79 | nolintlint:
80 | allow-unused: false
81 | allow-leading-space: true
82 | require-explanation: false
83 | require-specific: false
84 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | ---
2 | project_name: atomone
3 |
4 | builds:
5 | - main: ./cmd/atomoned
6 | id: "atomoned"
7 | binary: atomoned
8 | mod_timestamp: "{{ .CommitTimestamp }}"
9 | flags:
10 | - -tags=netgo
11 | - -trimpath
12 | env:
13 | - CGO_ENABLED=0
14 | ldflags:
15 | # .Env.TM_VERSION is provided in the workflow runner environment -> see .github/workflows/release.yml
16 | - -X github.com/cosmos/cosmos-sdk/version.Name=atomone -X github.com/cosmos/cosmos-sdk/version.AppName=atomoned -X github.com/cosmos/cosmos-sdk/version.Version=v{{ .Version }} -X github.com/cosmos/cosmos-sdk/version.Commit={{ .Commit }} -X github.com/cosmos/cosmos-sdk/version.BuildTags=netgo -X github.com/cometbft/cometbft/version.TMCoreSemVer={{ .Env.TM_VERSION }} -w -s
17 | goos:
18 | - darwin
19 | - linux
20 | - windows
21 | goarch:
22 | - amd64
23 | - arm64
24 |
25 | archives:
26 | # disables archiving; to enable use commented lines below
27 | - format: binary
28 | name_template: "{{ .Binary }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
29 |
30 | # - format: tar.gz
31 | # wrap_in_directory: "true"
32 | # format_overrides:
33 | # - goos: windows
34 | # format: zip
35 | # name_template: "{{ .Binary }}-v{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
36 | # files:
37 | # - LICENSE
38 | # - README.md
39 | # rlcp: true
40 |
41 | release:
42 | prerelease: true
43 | name_template: "v{{.Version}}"
44 |
45 | checksum:
46 | name_template: SHA256SUMS-v{{.Version}}.txt
47 | algorithm: sha256
48 |
49 | snapshot:
50 | name_template: "{{ .Version }}-{{ .ShortCommit }}"
51 |
52 | changelog:
53 | disable: true
54 |
55 | git:
56 | # What should be used to sort tags when gathering the current and previous
57 | # tags if there are more than one tag in the same commit.
58 | #
59 | # source: https://goreleaser.com/customization/git/
60 | tag_sort: -version:refname
61 | prerelease_suffix: "-rc"
62 |
--------------------------------------------------------------------------------
/.mergify.yml:
--------------------------------------------------------------------------------
1 | defaults:
2 | actions:
3 | backport:
4 | assignees:
5 | - "{{ author }}"
6 |
7 | queue_rules:
8 | - name: default
9 | conditions:
10 | - "#approved-reviews-by>1"
11 |
12 | pull_request_rules:
13 | - name: Automatic merge on approval to the main branch
14 | conditions:
15 | - "#approved-reviews-by>=1"
16 | - base=main
17 | - label=A:automerge
18 | actions:
19 | queue:
20 | name: default
21 | merge:
22 | method: squash
23 | commit_message_template: |
24 | {{ title }} (#{{ number }})
25 | {{ body }}
26 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG IMG_TAG=latest
2 |
3 | # Compile the atomoned binary
4 | FROM golang:1.22-alpine AS atomoned-builder
5 | WORKDIR /src/app/
6 | COPY go.mod go.sum* ./
7 | RUN go mod download
8 | COPY . .
9 | ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
10 | RUN apk add --no-cache $PACKAGES
11 | RUN CGO_ENABLED=0 make install
12 |
13 | # Add to a distroless container
14 | FROM cgr.dev/chainguard/static:$IMG_TAG
15 | ARG IMG_TAG
16 | COPY --from=atomoned-builder /go/bin/atomoned /usr/local/bin/
17 | EXPOSE 26656 26657 1317 9090
18 | USER 0
19 |
20 | ENTRYPOINT ["atomoned", "start"]
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AtomOne
2 |
3 | AtomOne is built using the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) as a fork of the
4 | [Cosmos Hub](https://github.com/cosmos/gaia) at version [v15.2.0](https://github.com/cosmos/gaia/releases/tag/v15.2.0) (common commit hash 7281c9b).
5 |
6 | The following modifications have been made to the Cosmos Hub software to create AtomOne:
7 |
8 | 1. Removed x/globalfee module and revert to older and simpler fee decorator
9 | 2. Removed Packet Forwarding Middleware
10 | 3. Removed Interchain Security module
11 | 4. Reverted to standard Cosmos SDK v0.47.10 without the Liquid Staking Module (LSM)
12 | 5. Changed Bech32 prefixes to `atone` (see `cmd/atomoned/cmd/config.go`)
13 | 6. Removed ability for validators to vote on proposals with delegations, they can only use their own stake
14 |
15 | ## Reproducible builds
16 |
17 | An effort has been made to make it possible to build the exact same binary
18 | locally as the Github Release section. To do this:
19 | - Checkout to the expected released version
20 | - Run `make build` (which will output the binary to the `build` directory) or
21 | `make install`. Note that a fixed version of the `go` binary is required,
22 | follow the command instructions to install this specific version if needed.
23 | - The resulted binary should have the same sha256 hash than the one from the
24 | Github Release section.
25 |
26 | ## Ledger support
27 |
28 | Run `make build/install LEDGER_ENABLED=true` to have ledger support in
29 | `atomoned` binary.
30 |
31 | Note that this will disable reproducible builds, as it introduces OS
32 | dependencies.
33 |
34 | ## Genesis file
35 |
36 | The proposed genesis files for atomone can be found in the [genesis repo](https://github.com/atomone-hub/genesis).
37 |
38 | ## Public RPC and fullnode endpoints
39 |
40 | The public RPC and fullnode endpoints directory can be found in the [atom.one](https://atom.one)
41 | website.
42 |
43 | ## Acknowledgements
44 |
45 | Portions of this codebase are copied or adapted from [cosmos/gaia@v15](https://github.com/cosmos/gaia/tree/v15.0.0), [cosmos/cosmos-sdk@v47.10](https://github.com/cosmos/cosmos-sdk/tree/v0.47.10) and
46 | [skip-mev/feemarket@v1.1.1](https://github.com/skip-mev/feemarket/tree/v1.1.1).
47 |
48 | Their original licenses are both included in [ATTRIBUTION](ATTRIBUTION)
49 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | All in Bits strives to contribute toward the security of our ecosystem through
4 | internal security practices, and by working with external security researchers
5 | from the community.
6 |
7 | ## Reporting a Vulnerability
8 |
9 | If you've identified a vulnerability, please report it through one of the
10 | following venues:
11 | * Submit an advisory through GitHub: https://github.com/atomone-hub/atomone/security/advisories/new
12 | * Email security [at-symbol] tendermint [dot] com. If you are concerned about
13 | confidentiality e.g. because of a high-severity issue, you may email us for
14 | PGP or Signal contact details.
15 | * We provide bug bounty rewards through our program at
16 | [HackenProof](https://hackenproof.com/all-in-bits). You must report via
17 | HackenProof in order to be eligible for rewards.
18 |
19 | We will respond within 3 business days to all received reports.
20 |
21 | Thank you for helping to keep our ecosystem safe!
22 |
23 | ## Security Audits
24 |
25 | - March 2025: The security firm Zellic conducted a source code audit of the AtomOne daemon and
26 | published a [report](docs/AtomOne%20-%20Zellic%20Audit%20Report.pdf) on March 11, 2025. Zellic has
27 | independently published this report
28 | [here](https://github.com/Zellic/publications/blob/master/AtomOne%20-%20Zellic%20Audit%20Report.pdf)
29 | with a SHA-256 hash of 60625f148263829921f7b8cc4a065290b197ddb869ba821f7dc4cfe4a4f96ff1.
30 | The audit scope was the whole codebase with a specific focus on the new `x/photon` module and the [dynamic deposit proposal](https://github.com/atomone-hub/atomone/pull/69) from the `x/gov/` module.
31 |
--------------------------------------------------------------------------------
/app/app_helpers.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | import (
4 | ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper"
5 | ibctestingtypes "github.com/cosmos/ibc-go/v7/testing/types"
6 |
7 | capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
8 | )
9 |
10 | // GetStakingKeeper implements the TestingApp interface. Needed for ICS.
11 | func (app *AtomOneApp) GetStakingKeeper() ibctestingtypes.StakingKeeper { //nolint:nolintlint
12 | return app.StakingKeeper
13 | }
14 |
15 | // GetIBCKeeper implements the TestingApp interface.
16 | func (app *AtomOneApp) GetIBCKeeper() *ibckeeper.Keeper { //nolint:nolintlint
17 | return app.IBCKeeper
18 | }
19 |
20 | // GetScopedIBCKeeper implements the TestingApp interface.
21 | func (app *AtomOneApp) GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper { //nolint:nolintlint
22 | return app.ScopedIBCKeeper
23 | }
24 |
--------------------------------------------------------------------------------
/app/app_test.go:
--------------------------------------------------------------------------------
1 | package atomone_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | db "github.com/cometbft/cometbft-db"
9 | "github.com/cometbft/cometbft/libs/log"
10 |
11 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
12 |
13 | atomone "github.com/atomone-hub/atomone/app"
14 | atomonehelpers "github.com/atomone-hub/atomone/app/helpers"
15 | govtypes "github.com/atomone-hub/atomone/x/gov/types"
16 | )
17 |
18 | type EmptyAppOptions struct{}
19 |
20 | func (ao EmptyAppOptions) Get(_ string) interface{} {
21 | return nil
22 | }
23 |
24 | func TestAtomOneApp_BlockedModuleAccountAddrs(t *testing.T) {
25 | encConfig := atomone.RegisterEncodingConfig()
26 | app := atomone.NewAtomOneApp(
27 | log.NewNopLogger(),
28 | db.NewMemDB(),
29 | nil,
30 | true,
31 | map[int64]bool{},
32 | atomone.DefaultNodeHome,
33 | encConfig,
34 | EmptyAppOptions{},
35 | )
36 |
37 | moduleAccountAddresses := app.ModuleAccountAddrs()
38 | blockedAddrs := app.BlockedModuleAccountAddrs(moduleAccountAddresses)
39 |
40 | require.NotContains(t, blockedAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String())
41 | }
42 |
43 | func TestAtomOneApp_Export(t *testing.T) {
44 | app := atomonehelpers.Setup(t)
45 | _, err := app.ExportAppStateAndValidators(true, []string{}, []string{})
46 | require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
47 | }
48 |
--------------------------------------------------------------------------------
/app/const.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | const (
4 | appName = "AtomOneApp"
5 | )
6 |
--------------------------------------------------------------------------------
/app/encoding.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/std"
5 |
6 | "github.com/atomone-hub/atomone/app/params"
7 | )
8 |
9 | func RegisterEncodingConfig() params.EncodingConfig {
10 | encConfig := params.MakeEncodingConfig()
11 |
12 | std.RegisterLegacyAminoCodec(encConfig.Amino)
13 | std.RegisterInterfaces(encConfig.InterfaceRegistry)
14 | ModuleBasics.RegisterLegacyAminoCodec(encConfig.Amino)
15 | ModuleBasics.RegisterInterfaces(encConfig.InterfaceRegistry)
16 |
17 | return encConfig
18 | }
19 |
--------------------------------------------------------------------------------
/app/genesis.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/atomone-hub/atomone/app/params"
7 | )
8 |
9 | // The genesis state of the blockchain is represented here as a map of raw json
10 | // messages key'd by a identifier string.
11 | // The identifier is used to determine which module genesis information belongs
12 | // to so it may be appropriately routed during init chain.
13 | // Within this application default genesis information is retrieved from
14 | // the ModuleBasicManager which populates json from each BasicModule
15 | // object provided to it during init.
16 | type GenesisState map[string]json.RawMessage
17 |
18 | // NewDefaultGenesisState generates the default state for the application.
19 | func NewDefaultGenesisState(encConfig params.EncodingConfig) GenesisState {
20 | return ModuleBasics.DefaultGenesis(encConfig.Marshaler)
21 | }
22 |
--------------------------------------------------------------------------------
/app/genesis_account.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | import (
4 | "errors"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
8 | )
9 |
10 | var _ authtypes.GenesisAccount = (*SimGenesisAccount)(nil)
11 |
12 | // SimGenesisAccount defines a type that implements the GenesisAccount interface
13 | // to be used for simulation accounts in the genesis state.
14 | type SimGenesisAccount struct {
15 | *authtypes.BaseAccount
16 |
17 | // vesting account fields
18 | OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // total vesting coins upon initialization
19 | DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // delegated vested coins at time of delegation
20 | DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // delegated vesting coins at time of delegation
21 | StartTime int64 `json:"start_time" yaml:"start_time"` // vesting start time (UNIX Epoch time)
22 | EndTime int64 `json:"end_time" yaml:"end_time"` // vesting end time (UNIX Epoch time)
23 |
24 | // module account fields
25 | ModuleName string `json:"module_name" yaml:"module_name"` // name of the module account
26 | ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"` // permissions of module account
27 | }
28 |
29 | // Validate checks for errors on the vesting and module account parameters
30 | func (sga SimGenesisAccount) Validate() error {
31 | if sga.OriginalVesting.IsAnyNil() {
32 | return errors.New("OriginalVesting amount must not be nil")
33 | }
34 |
35 | if !sga.OriginalVesting.IsZero() {
36 | if sga.StartTime >= sga.EndTime {
37 | return errors.New("vesting start-time cannot be before end-time")
38 | }
39 | }
40 |
41 | if sga.BaseAccount == nil {
42 | return errors.New("BaseAccount must not be nil")
43 | }
44 |
45 | if sga.ModuleName != "" {
46 | ma := authtypes.ModuleAccount{
47 | BaseAccount: sga.BaseAccount, Name: sga.ModuleName, Permissions: sga.ModulePermissions,
48 | }
49 |
50 | if err := ma.Validate(); err != nil {
51 | return err
52 | }
53 | }
54 |
55 | return sga.BaseAccount.Validate()
56 | }
57 |
--------------------------------------------------------------------------------
/app/genesis_account_fuzz_test.go:
--------------------------------------------------------------------------------
1 | package atomone
2 |
3 | import (
4 | "runtime/debug"
5 | "testing"
6 |
7 | "github.com/google/gofuzz"
8 | )
9 |
10 | func TestFuzzGenesisAccountValidate(t *testing.T) {
11 | if testing.Short() {
12 | t.Skip("running in -short mode")
13 | }
14 |
15 | t.Parallel()
16 |
17 | acct := new(SimGenesisAccount)
18 | i := 0
19 | defer func() {
20 | r := recover()
21 | if r == nil {
22 | return
23 | }
24 |
25 | // Otherwise report on the configuration and iteration.
26 | t.Fatalf("Failed SimGenesisAccount on iteration #%d: %#v\n\n%s\n\n%s", i, acct, r, debug.Stack())
27 | }()
28 |
29 | f := fuzz.New()
30 | for i = 0; i < 1e5; i++ {
31 | acct = new(SimGenesisAccount)
32 | f.Fuzz(acct)
33 | acct.Validate() //nolint:errcheck
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/params/amino.go:
--------------------------------------------------------------------------------
1 | //go:build test_amino
2 | // +build test_amino
3 |
4 | package params
5 |
6 | import (
7 | "github.com/cosmos/cosmos-sdk/codec"
8 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
9 | "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
10 | )
11 |
12 | func MakeTestEncodingConfig() EncodingConfig {
13 | cdc := codec.NewLegacyAmino()
14 | interfaceRegistry := cdctypes.NewInterfaceRegistry()
15 | codec := codec.NewProtoCodec(interfaceRegistry)
16 |
17 | return EncodingConfig{
18 | InterfaceRegistry: interfaceRegistry,
19 | Marshaler: codec,
20 | TxConfig: legacytx.StdTxConfig{Cdc: cdc},
21 | Amino: cdc,
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/params/config.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | const (
4 | BondDenom = "uatone"
5 |
6 | Bech32PrefixAccAddr = "atone"
7 | )
8 |
9 | var (
10 | // Bech32PrefixAccPub defines the Bech32 prefix of an account's public key.
11 | Bech32PrefixAccPub = Bech32PrefixAccAddr + "pub"
12 | // Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address.
13 | Bech32PrefixValAddr = Bech32PrefixAccAddr + "valoper"
14 | // Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key.
15 | Bech32PrefixValPub = Bech32PrefixAccAddr + "valoperpub"
16 | // Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address.
17 | Bech32PrefixConsAddr = Bech32PrefixAccAddr + "valcons"
18 | // Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key.
19 | Bech32PrefixConsPub = Bech32PrefixAccAddr + "valconspub"
20 | )
21 |
--------------------------------------------------------------------------------
/app/params/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package params defines the simulation parameters in the atomone.
3 |
4 | It contains the default weights used for each transaction used on the module's
5 | simulation. These weights define the chance for a transaction to be simulated at
6 | any given operation.
7 |
8 | You can replace the default values for the weights by providing a params.json
9 | file with the weights defined for each of the transaction operations:
10 |
11 | {
12 | "op_weight_msg_send": 60,
13 | "op_weight_msg_delegate": 100,
14 | }
15 |
16 | In the example above, the `MsgSend` has 60% chance to be simulated, while the
17 | `MsgDelegate` will always be simulated.
18 | */
19 | package params
20 |
--------------------------------------------------------------------------------
/app/params/encoding.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/client"
5 | "github.com/cosmos/cosmos-sdk/codec"
6 | "github.com/cosmos/cosmos-sdk/codec/types"
7 | )
8 |
9 | // EncodingConfig specifies the concrete encoding types to use for a given app.
10 | // This is provided for compatibility between protobuf and amino implementations.
11 | type EncodingConfig struct {
12 | InterfaceRegistry types.InterfaceRegistry
13 | Marshaler codec.Codec
14 | TxConfig client.TxConfig
15 | Amino *codec.LegacyAmino
16 | }
17 |
--------------------------------------------------------------------------------
/app/params/proto.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
6 | "github.com/cosmos/cosmos-sdk/x/auth/tx"
7 | )
8 |
9 | // MakeEncodingConfig creates an EncodingConfig for an amino based test configuration.
10 | func MakeEncodingConfig() EncodingConfig {
11 | amino := codec.NewLegacyAmino()
12 | interfaceRegistry := codectypes.NewInterfaceRegistry()
13 | cdc := codec.NewProtoCodec(interfaceRegistry)
14 | txCfg := tx.NewTxConfig(cdc, tx.DefaultSignModes)
15 | return EncodingConfig{
16 | InterfaceRegistry: interfaceRegistry,
17 | Marshaler: cdc,
18 | TxConfig: txCfg,
19 | Amino: amino,
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/params/weights.go:
--------------------------------------------------------------------------------
1 | package params
2 |
3 | // Default simulation operation weights for messages and gov proposals
4 | const (
5 | DefaultWeightMsgSend int = 100
6 | DefaultWeightMsgMultiSend int = 10
7 | DefaultWeightMsgSetWithdrawAddress int = 50
8 | DefaultWeightMsgWithdrawDelegationReward int = 50
9 | DefaultWeightMsgWithdrawValidatorCommission int = 50
10 | DefaultWeightMsgFundCommunityPool int = 50
11 | DefaultWeightMsgDeposit int = 100
12 | DefaultWeightMsgVote int = 67
13 | DefaultWeightMsgUnjail int = 100
14 | DefaultWeightMsgCreateValidator int = 100
15 | DefaultWeightMsgEditValidator int = 5
16 | DefaultWeightMsgDelegate int = 100
17 | DefaultWeightMsgUndelegate int = 100
18 | DefaultWeightMsgBeginRedelegate int = 100
19 | DefaultWeightMsgCancelUnbondingDelegation int = 100
20 |
21 | DefaultWeightCommunitySpendProposal int = 5
22 | DefaultWeightTextProposal int = 5
23 | DefaultWeightParamChangeProposal int = 5
24 | )
25 |
--------------------------------------------------------------------------------
/app/upgrades/types.go:
--------------------------------------------------------------------------------
1 | package upgrades
2 |
3 | import (
4 | store "github.com/cosmos/cosmos-sdk/store/types"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | "github.com/cosmos/cosmos-sdk/types/module"
7 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
8 |
9 | "github.com/atomone-hub/atomone/app/keepers"
10 | )
11 |
12 | // Upgrade defines a struct containing necessary fields that a SoftwareUpgradeProposal
13 | // must have written, in order for the state migration to go smoothly.
14 | // An upgrade must implement this struct, and then set it in the app.go.
15 | // The app.go will then define the handler.
16 | type Upgrade struct {
17 | // Upgrade version name, for the upgrade handler, e.g. `v7`
18 | UpgradeName string
19 |
20 | // CreateUpgradeHandler defines the function that creates an upgrade handler
21 | CreateUpgradeHandler func(*module.Manager, module.Configurator, *keepers.AppKeepers) upgradetypes.UpgradeHandler
22 |
23 | // Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed.
24 | StoreUpgrades store.StoreUpgrades
25 | }
26 |
27 | // Fork defines a struct containing the requisite fields for a non-software upgrade proposal
28 | // Hard Fork at a given height to implement.
29 | // There is one time code that can be added for the start of the Fork, in `BeginForkLogic`.
30 | // Any other change in the code should be height-gated, if the goal is to have old and new binaries
31 | // to be compatible prior to the upgrade height.
32 | type Fork struct {
33 | // Upgrade version name, for the upgrade handler, e.g. `v7`
34 | UpgradeName string
35 | // height the upgrade occurs at
36 | UpgradeHeight int64
37 |
38 | // Function that runs some custom state transition code at the beginning of a fork.
39 | BeginForkLogic func(ctx sdk.Context, keepers *keepers.AppKeepers)
40 | }
41 |
--------------------------------------------------------------------------------
/app/upgrades/v2/constants.go:
--------------------------------------------------------------------------------
1 | package v2
2 |
3 | import (
4 | store "github.com/cosmos/cosmos-sdk/store/types"
5 | crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
6 |
7 | "github.com/atomone-hub/atomone/app/upgrades"
8 | photontypes "github.com/atomone-hub/atomone/x/photon/types"
9 | )
10 |
11 | const (
12 | UpgradeName = "v2"
13 | )
14 |
15 | var Upgrade = upgrades.Upgrade{
16 | UpgradeName: UpgradeName,
17 | CreateUpgradeHandler: CreateUpgradeHandler,
18 | StoreUpgrades: store.StoreUpgrades{
19 | Added: []string{
20 | // new module added in v2
21 | photontypes.ModuleName,
22 | },
23 | Deleted: []string{
24 | crisistypes.ModuleName,
25 | },
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/app/upgrades/v3/constants.go:
--------------------------------------------------------------------------------
1 | package v3
2 |
3 | import (
4 | store "github.com/cosmos/cosmos-sdk/store/types"
5 |
6 | "github.com/atomone-hub/atomone/app/upgrades"
7 | feemarkettypes "github.com/atomone-hub/atomone/x/feemarket/types"
8 | )
9 |
10 | const (
11 | UpgradeName = "v3"
12 | )
13 |
14 | var Upgrade = upgrades.Upgrade{
15 | UpgradeName: UpgradeName,
16 | CreateUpgradeHandler: CreateUpgradeHandler,
17 | StoreUpgrades: store.StoreUpgrades{
18 | Added: []string{
19 | // new module added in v3
20 | feemarkettypes.ModuleName,
21 | },
22 | },
23 | }
24 |
--------------------------------------------------------------------------------
/app/upgrades/v3/upgrades.go:
--------------------------------------------------------------------------------
1 | package v3
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | "github.com/cosmos/cosmos-sdk/types/module"
6 | upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
7 |
8 | "github.com/atomone-hub/atomone/app/keepers"
9 | )
10 |
11 | // CreateUpgradeHandler returns a upgrade handler for AtomOne v3
12 | func CreateUpgradeHandler(
13 | mm *module.Manager,
14 | configurator module.Configurator,
15 | keepers *keepers.AppKeepers,
16 | ) upgradetypes.UpgradeHandler {
17 | return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
18 | ctx.Logger().Info("Starting module migrations...")
19 | // RunMigrations will detect the add of the feemarket module, will initiate
20 | // its genesis and will fill the versionMap with its consensus version.
21 | vm, err := mm.RunMigrations(ctx, configurator, vm)
22 | if err != nil {
23 | return vm, err
24 | }
25 | ctx.Logger().Info("Upgrade complete")
26 | return vm, nil
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/buf.work.yaml:
--------------------------------------------------------------------------------
1 | # This workspace file points to the roots found in your
2 | # previous "buf.yaml" configuration.
3 | version: v1
4 | directories:
5 | - proto
6 |
--------------------------------------------------------------------------------
/client/docs/swagger-ui/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/client/docs/swagger-ui/favicon-16x16.png
--------------------------------------------------------------------------------
/client/docs/swagger-ui/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/client/docs/swagger-ui/favicon-32x32.png
--------------------------------------------------------------------------------
/client/docs/swagger-ui/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Swagger UI
7 |
8 |
9 |
10 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/cmd/atomoned/cmd/bech32_convert.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/spf13/cobra"
7 |
8 | appparams "github.com/atomone-hub/atomone/app/params"
9 | addressutil "github.com/atomone-hub/atomone/pkg/address"
10 | )
11 |
12 | var flagBech32Prefix = "prefix"
13 |
14 | // AddBech32ConvertCommand returns bech32-convert cobra Command.
15 | func AddBech32ConvertCommand() *cobra.Command {
16 | cmd := &cobra.Command{
17 | Use: "bech32-convert [address]",
18 | Short: "Convert any bech32 string to the cosmos prefix",
19 | Long: `Convert any bech32 string to the cosmos prefix
20 |
21 | Example:
22 | atomoned debug bech32-convert akash1a6zlyvpnksx8wr6wz8wemur2xe8zyh0ytz6d88
23 |
24 | atomoned debug bech32-convert stride1673f0t8p893rqyqe420mgwwz92ac4qv6synvx2 --prefix osmo
25 | `,
26 | Args: cobra.ExactArgs(1),
27 | RunE: func(cmd *cobra.Command, args []string) error {
28 | bech32prefix, err := cmd.Flags().GetString(flagBech32Prefix)
29 | if err != nil {
30 | return err
31 | }
32 |
33 | address := args[0]
34 | convertedAddress, err := addressutil.ConvertBech32Prefix(address, bech32prefix)
35 | if err != nil {
36 | return fmt.Errorf("convertation failed: %s", err)
37 | }
38 |
39 | cmd.Println(convertedAddress)
40 |
41 | return nil
42 | },
43 | }
44 |
45 | cmd.Flags().StringP(flagBech32Prefix, "p", appparams.Bech32PrefixAccAddr, "Bech32 Prefix to encode to")
46 |
47 | return cmd
48 | }
49 |
50 | // addDebugCommands injects custom debug commands into another command as children.
51 | func addDebugCommands(cmd *cobra.Command) *cobra.Command {
52 | cmd.AddCommand(AddBech32ConvertCommand())
53 | return cmd
54 | }
55 |
--------------------------------------------------------------------------------
/cmd/atomoned/cmd/config.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | appparams "github.com/atomone-hub/atomone/app/params"
7 | )
8 |
9 | func InitSDKConfig() {
10 | cfg := sdk.GetConfig()
11 | cfg.SetBech32PrefixForAccount(appparams.Bech32PrefixAccAddr, appparams.Bech32PrefixAccPub)
12 | cfg.SetBech32PrefixForValidator(appparams.Bech32PrefixValAddr, appparams.Bech32PrefixValPub)
13 | cfg.SetBech32PrefixForConsensusNode(appparams.Bech32PrefixConsAddr, appparams.Bech32PrefixConsPub)
14 | cfg.Seal()
15 | }
16 |
--------------------------------------------------------------------------------
/cmd/atomoned/cmd/root_test.go:
--------------------------------------------------------------------------------
1 | package cmd_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
9 |
10 | app "github.com/atomone-hub/atomone/app"
11 | "github.com/atomone-hub/atomone/cmd/atomoned/cmd"
12 | )
13 |
14 | func TestRootCmdConfig(t *testing.T) {
15 | rootCmd, _ := cmd.NewRootCmd()
16 | rootCmd.SetArgs([]string{
17 | "config", // Test the config cmd
18 | "keyring-backend", // key
19 | "test", // value
20 | })
21 |
22 | require.NoError(t, svrcmd.Execute(rootCmd, "", app.DefaultNodeHome))
23 | }
24 |
--------------------------------------------------------------------------------
/cmd/atomoned/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/cosmos/cosmos-sdk/server"
7 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
8 |
9 | app "github.com/atomone-hub/atomone/app"
10 | "github.com/atomone-hub/atomone/cmd/atomoned/cmd"
11 | )
12 |
13 | func main() {
14 | rootCmd, _ := cmd.NewRootCmd()
15 |
16 | if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
17 | switch e := err.(type) {
18 | case server.ErrorCode:
19 | os.Exit(e.Code)
20 |
21 | default:
22 | os.Exit(1)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/contrib/Dockerfile.test:
--------------------------------------------------------------------------------
1 | # Simple usage with a mounted data directory:
2 | # > docker build -t atomone .
3 | # > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.atomone:/root/.atomone atomone atomoned init
4 | # > docker run -it -p 46657:46657 -p 46656:46656 -v ~/.atomone:/root/.atomone atomone atomoned start
5 | FROM golang:1.22-alpine AS build-env
6 |
7 | # Set up dependencies
8 | ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
9 |
10 | # Set working directory for the build
11 | WORKDIR /go/src/github.com/atomone-hub/atomone
12 |
13 | # Add source files
14 | COPY . .
15 |
16 | # Install minimum necessary dependencies, build Cosmos SDK, remove packages
17 | RUN apk add --no-cache $PACKAGES && \
18 | make install
19 |
20 | # Final image
21 | FROM alpine:edge
22 |
23 | # Install ca-certificates
24 | RUN apk add --update ca-certificates
25 | WORKDIR /root
26 |
27 | # Copy over binaries from the build-env
28 | COPY --from=build-env /go/bin/atomoned /usr/bin/atomoned
29 |
30 | COPY ./contrib/single-node.sh .
31 |
32 | EXPOSE 26657
33 |
34 | ENTRYPOINT [ "./single-node.sh" ]
35 | # NOTE: to run this image, docker run -d -p 26657:26657 ./single-node.sh {{chain_id}} {{genesis_account}}
36 |
--------------------------------------------------------------------------------
/contrib/denom.json:
--------------------------------------------------------------------------------
1 |
2 |
3 | [{
4 | "base": "uatone",
5 | "denom_units": [
6 | {
7 | "aliases": [
8 | "microatone"
9 | ],
10 | "denom": "uatone",
11 | "exponent": 0
12 | },
13 | {
14 | "aliases": [
15 | "milliatone"
16 | ],
17 | "denom": "matone",
18 | "exponent": 3
19 | },
20 | {
21 | "aliases": [],
22 | "denom": "atone",
23 | "exponent": 6
24 | }
25 | ],
26 | "description": "The native staking token of AtomOne.",
27 | "display": "ATONE",
28 | "name": "ATONE",
29 | "symbol": "ATONE"
30 | }]
31 |
--------------------------------------------------------------------------------
/contrib/devdeps/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 |
3 | package devdeps
4 |
5 | import (
6 | // formatting
7 | _ "mvdan.cc/gofumpt"
8 |
9 | // linter
10 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint"
11 |
12 | // mocks
13 | _ "github.com/golang/mock/mockgen"
14 |
15 | // for releases
16 | _ "github.com/goreleaser/goreleaser"
17 |
18 | _ "github.com/rakyll/statik"
19 | _ "golang.org/x/vuln/cmd/govulncheck"
20 | )
21 |
--------------------------------------------------------------------------------
/contrib/generate_release_note/main.go:
--------------------------------------------------------------------------------
1 | //go:build exclude
2 | // +build exclude
3 |
4 | package main
5 |
6 | import (
7 | "errors"
8 | "fmt"
9 | "os"
10 | "strings"
11 | )
12 |
13 | func main() {
14 | args := os.Args
15 | if len(args) != 4 {
16 | fmt.Println("please add os.Args release version, build_report path and CHANGELOG.md path, example: go run main.go v7.0.0 ../../artifacts/build_report ../../CHANGELOG.md")
17 | }
18 |
19 | buildReportPath := args[2]
20 | changelogPath := args[3]
21 |
22 | buildReport, err := os.ReadFile(buildReportPath)
23 | if err != nil {
24 | fmt.Printf("file error: %s\n", err)
25 | }
26 |
27 | changelog, err := FindChangelog(changelogPath, args[1])
28 | if err != nil {
29 | fmt.Printf("cannot find changelog: %s\n", err)
30 | }
31 |
32 | note := strings.Builder{}
33 | note.WriteString(fmt.Sprintf("# AtomOne %s Release Notes\n", args[1]))
34 | note.WriteString(changelog)
35 | note.WriteString("```\n")
36 | note.Write(buildReport)
37 | note.WriteString("```\n")
38 |
39 | f, err := os.Create("./releasenote")
40 | if err != nil {
41 | fmt.Printf("cannot create a release note: %s\n", err)
42 | }
43 | defer f.Close()
44 |
45 | _, err = f.WriteString(note.String())
46 | if err != nil {
47 | fmt.Printf("cannot write to releasenote: %s\n", err)
48 | }
49 | }
50 |
51 | func FindChangelog(file, version string) (string, error) {
52 | data, err := os.ReadFile(file)
53 | if err != nil {
54 | return "", errors.New("read changelog file failed")
55 | }
56 |
57 | changelogs := string(data)
58 | i := strings.Index(changelogs, "["+version)
59 | if i == -1 {
60 | // -1 means not found
61 | return "", fmt.Errorf("cannot find version %s", version)
62 | }
63 | j := strings.Index(changelogs[i:], "##")
64 | if j == -1 {
65 | // -1 means not found
66 | return "", fmt.Errorf("cannot find the end of %s's changelog", version)
67 | }
68 |
69 | return changelogs[i : i+j], nil
70 | }
71 |
--------------------------------------------------------------------------------
/contrib/get_node.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | VERSION=v11.15.0
4 | NODE_FULL=node-${VERSION}-linux-x64
5 |
6 | mkdir -p ~/.local/bin
7 | mkdir -p ~/.local/node
8 | wget http://nodejs.org/dist/${VERSION}/${NODE_FULL}.tar.gz -O ~/.local/node/${NODE_FULL}.tar.gz
9 | tar -xzf ~/.local/node/${NODE_FULL}.tar.gz -C ~/.local/node/
10 | ln -s ~/.local/node/${NODE_FULL}/bin/node ~/.local/bin/node
11 | ln -s ~/.local/node/${NODE_FULL}/bin/npm ~/.local/bin/npm
12 | export PATH=~/.local/bin:$PATH
13 | npm i -g dredd@11.0.1
14 | ln -s ~/.local/node/${NODE_FULL}/bin/dredd ~/.local/bin/dredd
15 |
--------------------------------------------------------------------------------
/contrib/githooks/README.md:
--------------------------------------------------------------------------------
1 | # Git hooks
2 |
3 | Installation:
4 |
5 | ```
6 | git config core.hooksPath contrib/githooks
7 | ```
8 |
9 | ## pre-commit
10 |
11 | The hook automatically runs `gofmt`, `goimports`, and `misspell`
12 | to correctly format the `.go` files included in the commit, provided
13 | that all the aforementioned commands are installed and available
14 | in the user's search `$PATH` environment variable:
15 |
16 | ```
17 | go install golang.org/x/tools/cmd/goimports
18 | go install github.com/golangci/misspell/cmd/misspell@master
19 | ```
20 |
21 | It also runs `go mod tidy` and `golangci-lint` if available.
22 |
--------------------------------------------------------------------------------
/contrib/githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | CMDS='git go gofmt goimports misspell'
6 | STAGED_GO_FILES=$(git diff --cached --name-only -- '*.go')
7 |
8 | f_echo_stderr() {
9 | echo $@ >&2
10 | }
11 |
12 | f_exit_success() {
13 | [ x"$@" != "x" ] && f_echo_stderr $@ || exit 0
14 | }
15 | trap f_exit_success EXIT
16 |
17 | f_check_cmds() {
18 | for cmd in ${CMDS}; do
19 | which ${cmd} &>/dev/null || f_exit_success "couldn't find ${cmd}, skipping"
20 | done
21 | }
22 |
23 | f_check_cmds
24 |
25 | if [[ $STAGED_GO_FILES != "" ]]; then
26 | f_echo_stderr "[pre-commit] fmt'ing staged files..."
27 | for file in $STAGED_GO_FILES; do
28 | if [[ $file =~ vendor/ ]] || [[ $file =~ client/lcd/statik/ ]] || [[ $file =~ tests/mocks/ ]] || [[ $file =~ \.pb\.go ]]; then
29 | continue
30 | fi
31 |
32 | gofmt -w -s $file
33 | misspell -w $file
34 | goimports -w -local github.com/atomone-hub/atomone $file
35 | git add $file
36 |
37 | done
38 | fi
39 |
40 | # Run go mod tidy
41 | go mod tidy && git add go.mod go.sum
42 |
--------------------------------------------------------------------------------
/contrib/githooks/precommit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | CMDS='git go gofmt goimports misspell'
6 | STAGED_GO_FILES=$(git diff --cached --name-only -- '*.go')
7 |
8 | f_echo_stderr() {
9 | echo $@ >&2
10 | }
11 |
12 | f_exit_success() {
13 | [ x"$@" != "x" ] && f_echo_stderr $@ || exit 0
14 | }
15 | trap f_exit_success EXIT
16 |
17 | f_check_cmds() {
18 | for cmd in ${CMDS}; do
19 | which ${cmd} &>/dev/null || f_exit_success "couldn't find ${cmd}, skipping"
20 | done
21 | }
22 |
23 | f_check_cmds
24 |
25 | if [[ $STAGED_GO_FILES != "" ]]; then
26 | f_echo_stderr "[pre-commit] fmt'ing staged files..."
27 | for file in $STAGED_GO_FILES; do
28 | if [[ $file =~ vendor/ ]] || [[ $file =~ client/lcd/statik/ ]] || [[ $file =~ tests/mocks/ ]] || [[ $file =~ \.pb\.go ]]; then
29 | continue
30 | fi
31 |
32 | gofmt -w -s $file
33 | misspell -w $file
34 | goimports -w -local github.com/atomone-hub/atomone $file
35 | git add $file
36 |
37 | done
38 | fi
39 |
40 | # Run go mod tidy
41 | go mod tidy && git add go.mod go.sum
42 |
--------------------------------------------------------------------------------
/contrib/localnet/proposal_legacy_param_change.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "@type": "/atomone.gov.v1.MsgExecLegacyContent",
5 | "content": {
6 | "@type": "/cosmos.params.v1beta1.ParameterChangeProposal",
7 | "title": "IBC Transfers Enablement Proposal",
8 | "description": "This proposal would enable interchain functionality, allowing AtomOne to connect and interact seamlessly with the wider Cosmos ecosystem.",
9 | "changes": [
10 | {
11 | "subspace": "transfer",
12 | "key": "SendEnabled",
13 | "value": "true"
14 | },
15 | {
16 | "subspace": "transfer",
17 | "key": "ReceiveEnabled",
18 | "value": "true"
19 | }
20 | ]
21 | },
22 | "authority": "atone10d07y265gmmuvt4z0w9aw880jnsr700j5z0zqt"
23 | }
24 | ],
25 | "metadata": "ipfs://CID",
26 | "deposit": "200000000uatone",
27 | "title": "IBC Enablement",
28 | "summary": "summary"
29 | }
30 |
--------------------------------------------------------------------------------
/contrib/localnet/proposal_text.json:
--------------------------------------------------------------------------------
1 | {
2 | "metadata": "ipfs://CID",
3 | "deposit": "512000000uatone",
4 | "title": "text proposal",
5 | "summary": "my summary"
6 | }
7 |
--------------------------------------------------------------------------------
/contrib/localnet/proposal_upgrade.json:
--------------------------------------------------------------------------------
1 | {
2 | "messages": [
3 | {
4 | "@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade",
5 | "authority": "atone10d07y265gmmuvt4z0w9aw880jnsr700j5z0zqt",
6 | "plan": {
7 | "name": "v2",
8 | "time": "0001-01-01T00:00:00Z",
9 | "height": "80",
10 | "info": "",
11 | "upgraded_client_state": null
12 | }
13 | }
14 | ],
15 | "metadata": "ipfs://CID",
16 | "deposit": "512000000uatone",
17 | "title": "v2",
18 | "summary": "v2"
19 | }
20 |
--------------------------------------------------------------------------------
/contrib/scripts/local-atomone.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -eux
3 |
4 | # User balance of stake tokens
5 | USER_COINS="100000000000stake"
6 | # Amount of stake tokens staked
7 | STAKE="100000000stake"
8 | # Node IP address
9 | NODE_IP="127.0.0.1"
10 |
11 | # Home directory
12 | HOME_DIR="/Users/msalopek"
13 |
14 | # Validator moniker
15 | MONIKER="coordinator"
16 |
17 | # Validator directory
18 | PROV_NODE_DIR=${HOME_DIR}/provider-${MONIKER}
19 |
20 | # Coordinator key
21 | PROV_KEY=${MONIKER}-key
22 |
23 |
24 | # Clean start
25 | pkill -f atomoned &> /dev/null || true
26 | rm -rf ${PROV_NODE_DIR}
27 |
28 | # Build file and node directory structure
29 | atomoned init $MONIKER --chain-id provider --home ${PROV_NODE_DIR}
30 | jq ".app_state.gov.voting_params.voting_period = \"20s\" | .app_state.staking.params.unbonding_time = \"86400s\"" \
31 | ${PROV_NODE_DIR}/config/genesis.json > \
32 | ${PROV_NODE_DIR}/edited_genesis.json && mv ${PROV_NODE_DIR}/edited_genesis.json ${PROV_NODE_DIR}/config/genesis.json
33 |
34 | sleep 1
35 |
36 | # Create account keypair
37 | atomoned keys add $PROV_KEY --home ${PROV_NODE_DIR} --keyring-backend test --output json > ${PROV_NODE_DIR}/${PROV_KEY}.json 2>&1
38 | sleep 1
39 |
40 | # Add stake to user
41 | PROV_ACCOUNT_ADDR=$(jq -r '.address' ${PROV_NODE_DIR}/${PROV_KEY}.json)
42 | atomoned add-genesis-account $PROV_ACCOUNT_ADDR $USER_COINS --home ${PROV_NODE_DIR} --keyring-backend test
43 | sleep 1
44 |
45 |
46 | # Stake 1/1000 user's coins
47 | atomoned gentx $PROV_KEY $STAKE --chain-id provider --home ${PROV_NODE_DIR} --keyring-backend test --moniker $MONIKER
48 | sleep 1
49 |
50 | atomoned collect-gentxs --home ${PROV_NODE_DIR} --gentx-dir ${PROV_NODE_DIR}/config/gentx/
51 | sleep 1
52 |
53 | sed -i -r "/node =/ s/= .*/= \"tcp:\/\/${NODE_IP}:26658\"/" ${PROV_NODE_DIR}/config/client.toml
54 | sed -i -r 's/timeout_commit = "5s"/timeout_commit = "3s"/g' ${PROV_NODE_DIR}/config/config.toml
55 | sed -i -r 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ${PROV_NODE_DIR}/config/config.toml
56 |
57 |
58 | # Start atomone
59 | atomoned start \
60 | --home ${PROV_NODE_DIR} \
61 | --rpc.laddr tcp://${NODE_IP}:26658 \
62 | --grpc.address ${NODE_IP}:9091 \
63 | --address tcp://${NODE_IP}:26655 \
64 | --p2p.laddr tcp://${NODE_IP}:26656 \
65 | --grpc-web.enable=false &> ${PROV_NODE_DIR}/logs
66 |
--------------------------------------------------------------------------------
/contrib/scripts/test_localnet_liveness.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | CNT=0
4 | ITER=$1
5 | SLEEP=$2
6 | NUMBLOCKS=$3
7 | NODEADDR=$4
8 |
9 | if [ -z "$1" ]; then
10 | echo "Invalid argument: missing number of iterations"
11 | echo "sh test_localnet_liveness.sh "
12 | exit 1
13 | fi
14 |
15 | if [ -z "$2" ]; then
16 | echo "Invalid argument: missing sleep duration"
17 | echo "sh test_localnet_liveness.sh "
18 | exit 1
19 | fi
20 |
21 | if [ -z "$3" ]; then
22 | echo "Invalid argument: missing number of blocks"
23 | echo "sh test_localnet_liveness.sh "
24 | exit 1
25 | fi
26 |
27 | if [ -z "$4" ]; then
28 | echo "Invalid argument: missing node address"
29 | echo "sh test_localnet_liveness.sh "
30 | exit 1
31 | fi
32 |
33 | echo "running 'sh test_localnet_liveness.sh iterations=$ITER sleep=$SLEEP num-blocks=$NUMBLOCKS node-address=$NODEADDR'"
34 |
35 | while [ ${CNT} -lt $ITER ]; do
36 | curr_block=$(curl -s $NODEADDR:26657/status | jq -r '.result.sync_info.latest_block_height')
37 |
38 | tail liveness.out
39 |
40 | if [ ! -z ${curr_block} ]; then
41 | echo "Current block: ${curr_block}"
42 | fi
43 |
44 | if [ ! -z ${curr_block} ] && [ ${curr_block} -gt ${NUMBLOCKS} ]; then
45 | echo "Success: number of blocks reached"
46 | exit 0
47 | fi
48 |
49 | sleep $SLEEP
50 | done
51 |
52 | echo "Failed: timeout reached"
53 | exit 1
54 |
--------------------------------------------------------------------------------
/contrib/single-node.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -o errexit -o nounset
4 |
5 | CHAINID=$1
6 | GENACCT=$2
7 |
8 | if [ -z "$1" ]; then
9 | echo "Need to input chain id..."
10 | exit 1
11 | fi
12 |
13 | if [ -z "$2" ]; then
14 | echo "Need to input genesis account address..."
15 | exit 1
16 | fi
17 |
18 | # Build genesis file incl account for passed address
19 | coins="10000000000stake,100000000000samoleans"
20 | atomoned init --chain-id $CHAINID $CHAINID
21 | atomoned keys add validator --keyring-backend="test"
22 | atomoned add-genesis-account $(atomoned keys show validator -a --keyring-backend="test") $coins
23 | atomoned add-genesis-account $GENACCT $coins
24 | atomoned gentx validator 5000000000stake --keyring-backend="test" --chain-id $CHAINID
25 | atomoned collect-gentxs
26 |
27 | # Set proper defaults and change ports
28 | echo "Setting rpc listen address"
29 | sed -i '' 's#"tcp://127.0.0.1:26657"#"tcp://0.0.0.0:26657"#g' ~/.atomone/config/config.toml
30 | echo 2
31 | sed -i '' 's/timeout_commit = "5s"/timeout_commit = "1s"/g' ~/.atomone/config/config.toml
32 | sed -i '' 's/timeout_propose = "3s"/timeout_propose = "1s"/g' ~/.atomone/config/config.toml
33 | sed -i '' 's/index_all_keys = false/index_all_keys = true/g' ~/.atomone/config/config.toml
34 |
35 | # Start the atomone
36 | atomoned start --pruning=nothing
37 |
--------------------------------------------------------------------------------
/docs/AtomOne - Zellic Audit Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/docs/AtomOne - Zellic Audit Report.pdf
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | # AtomOne Documentation
8 |
9 | Welcome to the documentation of the **AtomOne application: `atomone`**.
10 |
11 | ## Testing Chain Upgrade
12 |
13 | Chain upgrade is an important procedure that should be tested carefully. This
14 | section aims to provide a guide for testing chain upgrades in AtomOne using a
15 | localnet.
16 |
17 | 1. Git checkout the version of AtomOne you want to upgrade from.
18 | 2. Update `contrib/localnet/upgrade_proposal.json` with the correct plan name,
19 | which means the exact `UpgradeName` used to qualify the upgrade in the
20 | next version. For instance for the v2 upgrade, the plan name is `v2` (see
21 | the `app/upgrade` folder).
22 | 3. Run `make localnet-start` to start a new localnet.
23 | 4. Run `make localnet-submit-upgrade-proposal` to submit the upgrade proposal
24 | and give it enough yes votes for passing the tally.
25 | 5. Wait for 5 minutes (the voting period) and run `atomoned --home ~/.atomone-localnet q gov proposals`
26 | to check that the proposal has passed.
27 | 6. Wait for the block height that was registered in the upgrade proposal. Once
28 | reached the localnet should stop producing blocks, and return an error like:
29 | ```
30 | ERR UPGRADE "v2" NEEDED (...)
31 | ERR CONSENSUS FAILURE!!!
32 | ```
33 | This means it is time to upgrade the binary.
34 | 7. Stop the `make localnet-start`
35 | 8. Git checkout the version of AtomOne you want to upgrade to.
36 | 9. Run `make localnet-restart` (/!\ not `localnet-start` which would delete all
37 | the chain data). Block production should restart.
38 | 10. Check that the upgrade procedure has been executed properly.
39 | 11. Restart the node to ensure it continues producing blocks after the upgrade.
40 |
--------------------------------------------------------------------------------
/docs/architecture/adr-template.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | # ADR {ADR-NUMBER}: {TITLE}
6 |
7 | ## Changelog
8 |
9 | - {date}: {changelog}
10 |
11 | ## Status
12 |
13 | {DRAFT | PROPOSED} Not Implemented
14 |
15 | > Please have a look at the [PROCESS](./PROCESS.md#adr-status) page.
16 | > Use DRAFT if the ADR is in a draft stage (draft PR) or PROPOSED if it's in review.
17 |
18 | ## Abstract
19 |
20 | > "If you can't explain it simply, you don't understand it well enough." Provide
21 | > a simplified and layman-accessible explanation of the ADR.
22 | > A short (~200 word) description of the issue being addressed.
23 |
24 | ## Context
25 |
26 | > This section contains all the context one needs to understand the current state, and why there is a problem.
27 | > It should be as succinct as possible and introduce the high level idea behind the solution.
28 | > The language in this section is value-neutral. It is simply describing facts.
29 |
30 | ## Decision
31 |
32 | > This section explains all of the details of the proposed solution, including implementation details.
33 | It should also describe affects / corollary items that may need to be changed as a part of this.
34 | If the proposed change will be large, please also indicate a way to do the change to maximize ease of review.
35 | (e.g. the optimal split of things to do between separate PR's)
36 |
37 | ## Consequences
38 |
39 | > This section describes the consequences, after applying the decision.
40 | > All consequences should be summarized here, not just the "positive" ones.
41 |
42 | ### Positive
43 |
44 | > {positive consequences}
45 |
46 | ### Negative
47 |
48 | > {negative consequences}
49 |
50 | ### Neutral
51 |
52 | > {neutral consequences}
53 |
54 | ## References
55 |
56 | > Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here!
57 |
58 | * {reference link}
59 |
--------------------------------------------------------------------------------
/docs/architecture/demo/README_NakamotoBonus.md:
--------------------------------------------------------------------------------
1 | # Nakamoto Bonus Demo
2 |
3 | The `NakamotoBonus.ipynb` demo showcases the effect of assigning the block reward in a proportional and in a uniform way. The user is able to change using a widget the state of the delegations on the network and amount of the reward that is assigned proportionally vs uniformly and see how this affects the way reward is split across validators.
4 | It can be seen that, increasing the amount of reward that is assigned uniformly - i.e. the Nakamoto Bonus - increases the incentive of delegators to delegate on validators having less voting power.
5 |
6 | ## Requirements
7 |
8 | The file `NakamotoBonus.ipynb` is a Jupyter notebook file and it requires python and jupyterlab to be installed in the system. There are several ways to install Jupyter lab, for more information refer to this [link](https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html).
9 |
10 | ## Usage
11 |
12 | Jupyter should be launched using the terminal from the folder containing the file `NakamotoBonus.ipynb`.
13 |
14 | ```bash
15 | jupyter lab
16 | ```
17 |
18 | This will launch the jupyter webui. The user can then select the `NakamotoBonus.ipynb` using the file browser on the left side of the UI, and execute the code in the cells to generate the charts.
19 |
--------------------------------------------------------------------------------
/docs/architecture/img/adr-001-voting-period-extension-late-quorum-case1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/docs/architecture/img/adr-001-voting-period-extension-late-quorum-case1.png
--------------------------------------------------------------------------------
/docs/architecture/img/adr-001-voting-period-extension-late-quorum-case2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/atomone-hub/atomone/f82dce0ebfcae9a297fdc5c79e2c234b86f23b8e/docs/architecture/img/adr-001-voting-period-extension-late-quorum-case2.png
--------------------------------------------------------------------------------
/e2e.Dockerfile:
--------------------------------------------------------------------------------
1 | ARG GO_VERSION
2 | ARG IMG_TAG=latest
3 |
4 | # Compile the atomoned binary
5 | FROM golang:$GO_VERSION-alpine AS atomoned-builder
6 | WORKDIR /src/app/
7 | COPY go.mod go.sum* ./
8 | RUN go mod download
9 | COPY . .
10 | ENV PACKAGES curl make git libc-dev bash gcc linux-headers eudev-dev python3
11 | RUN apk add --no-cache $PACKAGES
12 | RUN CGO_ENABLED=0 make install
13 |
14 | # Add to a distroless container
15 | FROM alpine:$IMG_TAG
16 | RUN adduser -D nonroot
17 | ARG IMG_TAG
18 | COPY --from=atomoned-builder /go/bin/atomoned /usr/local/bin/
19 | EXPOSE 26656 26657 1317 9090
20 | USER nonroot
21 |
22 | ENTRYPOINT ["atomoned", "start"]
23 |
--------------------------------------------------------------------------------
/mlc_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "ignorePatterns": [ { "pattern": "^https://ipfs.io/ipfs/" } ],
3 | "replacementPatterns": [ ],
4 | "httpHeaders": [ ],
5 | "timeout": "20s",
6 | "retryOn429": true,
7 | "retryCount": 5,
8 | "fallbackRetryDelay": "30s",
9 | "aliveStatusCodes": [0, 200, 206, 403, 429]
10 | }
11 |
--------------------------------------------------------------------------------
/pkg/address/address.go:
--------------------------------------------------------------------------------
1 | package address
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/types/bech32"
7 | )
8 |
9 | // ConvertBech32Prefix convert bech32 address to specified prefix.
10 | func ConvertBech32Prefix(address, prefix string) (string, error) {
11 | _, bz, err := bech32.DecodeAndConvert(address)
12 | if err != nil {
13 | return "", fmt.Errorf("cannot decode %s address: %s", address, err)
14 | }
15 |
16 | convertedAddress, err := bech32.ConvertAndEncode(prefix, bz)
17 | if err != nil {
18 | return "", fmt.Errorf("cannot convert %s address: %s", address, err)
19 | }
20 |
21 | return convertedAddress, nil
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/address/address_test.go:
--------------------------------------------------------------------------------
1 | package address
2 |
3 | import (
4 | "errors"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestConvertBech32Prefix(t *testing.T) {
11 | cases := []struct {
12 | name string
13 | address string
14 | prefix string
15 | converted string
16 | err error
17 | }{
18 | {
19 | name: "Convert valid bech 32 address",
20 | address: "akash1a6zlyvpnksx8wr6wz8wemur2xe8zyh0ytz6d88",
21 | converted: "cosmos1a6zlyvpnksx8wr6wz8wemur2xe8zyh0yxeh27a",
22 | prefix: "cosmos",
23 | },
24 | {
25 | name: "Convert invalid address",
26 | address: "invalidaddress",
27 | prefix: "cosmos",
28 | err: errors.New("cannot decode invalidaddress address: decoding bech32 failed: invalid separator index -1"),
29 | },
30 | }
31 |
32 | for _, tt := range cases {
33 | t.Run(tt.name, func(t *testing.T) {
34 | convertedAddress, err := ConvertBech32Prefix(tt.address, tt.prefix)
35 | if tt.err != nil {
36 | require.ErrorContains(t, err, tt.err.Error())
37 | } else {
38 | require.NoError(t, err)
39 | }
40 | require.Equal(t, tt.converted, convertedAddress)
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/post/post.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | errorsmod "cosmossdk.io/errors"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
8 |
9 | feemarketpost "github.com/atomone-hub/atomone/x/feemarket/post"
10 | )
11 |
12 | // PostHandlerOptions are the options required for constructing a FeeMarket PostHandler.
13 | type HandlerOptions struct {
14 | FeemarketKeeper feemarketpost.FeeMarketKeeper
15 | ConsensusParamsKeeper feemarketpost.ConsensusParamsKeeper
16 | }
17 |
18 | // NewPostHandler returns a PostHandler chain with the fee deduct decorator.
19 | func NewPostHandler(options HandlerOptions) (sdk.PostHandler, error) {
20 | if options.FeemarketKeeper == nil {
21 | return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "feemarket keeper is required for post builder")
22 | }
23 |
24 | postDecorators := []sdk.PostDecorator{
25 | feemarketpost.NewFeemarketStateUpdateDecorator(
26 | options.FeemarketKeeper,
27 | options.ConsensusParamsKeeper,
28 | ),
29 | }
30 |
31 | return sdk.ChainPostDecorators(postDecorators...), nil
32 | }
33 |
--------------------------------------------------------------------------------
/proto/atomone/feemarket/module/v1/module.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package atomone.feemarket.module.v1;
4 |
5 | import "cosmos/app/v1alpha1/module.proto";
6 |
7 | // Module is the config object of the builder module.
8 | message Module {
9 | option (cosmos.app.v1alpha1.module) = {
10 | go_import : "github.com/atomone-hub/atomone/x/feemarket"
11 | };
12 |
13 | // Authority defines the custom module authority. If not set, defaults to the
14 | // governance module.
15 | string authority = 1;
16 | }
17 |
--------------------------------------------------------------------------------
/proto/atomone/feemarket/v1/genesis.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package atomone.feemarket.v1;
3 |
4 | option go_package = "github.com/atomone-hub/atomone/x/feemarket/types";
5 |
6 | import "gogoproto/gogo.proto";
7 | import "cosmos_proto/cosmos.proto";
8 | import "atomone/feemarket/v1/params.proto";
9 |
10 | // GenesisState defines the feemarket module's genesis state.
11 | message GenesisState {
12 | // Params are the parameters for the feemarket module. These parameters
13 | // can be utilized to implement both the base EIP-1559 fee market and
14 | // and the AIMD EIP-1559 fee market.
15 | Params params = 1 [ (gogoproto.nullable) = false ];
16 |
17 | // State contains the current state of the AIMD fee market.
18 | State state = 2 [ (gogoproto.nullable) = false ];
19 | }
20 |
21 | // State is utilized to track the current state of the fee market. This includes
22 | // the current base fee, learning rate, and block gas within the
23 | // specified AIMD window.
24 | message State {
25 | // BaseGasPrice is the current base fee. This is denominated in the fee per
26 | // gas unit.
27 | string base_gas_price = 1 [
28 | (cosmos_proto.scalar) = "cosmos.Dec",
29 | (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
30 | (gogoproto.nullable) = false
31 | ];
32 |
33 | // LearningRate is the current learning rate.
34 | string learning_rate = 2 [
35 | (cosmos_proto.scalar) = "cosmos.Dec",
36 | (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
37 | (gogoproto.nullable) = false
38 | ];
39 |
40 | // Window contains a list of the last blocks' gas values. This is used
41 | // to calculate the next base fee. This stores the number of units of gas
42 | // consumed per block.
43 | repeated uint64 window = 3;
44 |
45 | // Index is the index of the current block in the block gas window.
46 | uint64 index = 4;
47 | }
48 |
--------------------------------------------------------------------------------
/proto/atomone/feemarket/v1/tx.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package atomone.feemarket.v1;
3 |
4 | import "atomone/feemarket/v1/params.proto";
5 | import "cosmos_proto/cosmos.proto";
6 | import "cosmos/msg/v1/msg.proto";
7 | import "gogoproto/gogo.proto";
8 | import "amino/amino.proto";
9 |
10 | option go_package = "github.com/atomone-hub/atomone/x/feemarket/types";
11 |
12 | // Message service defines the types of messages supported by the feemarket
13 | // module.
14 | service Msg {
15 | option (cosmos.msg.v1.service) = true;
16 |
17 | // UpdateParams defines a method for updating the feemarket module parameters.
18 | rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);
19 | }
20 |
21 | // MsgUpdateParams defines the sdk.Msg/UpdateParams request type. It contains
22 | // the new parameters for the feemarket module.
23 | message MsgUpdateParams {
24 | option (cosmos.msg.v1.signer) = "authority";
25 | option (amino.name) = "atomone/x/feemarket/v1/MsgUpdateParams";
26 |
27 | // Authority defines the authority that is updating the feemarket module
28 | // parameters.
29 | string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
30 | // Params defines the new parameters for the feemarket module.
31 | Params params = 2 [ (gogoproto.nullable) = false ];
32 | }
33 |
34 | // MsgUpdateParamsResponse defines the response structure for executing a
35 | // MsgUpdateParams message.
36 | message MsgUpdateParamsResponse {}
37 |
--------------------------------------------------------------------------------
/proto/atomone/gov/module/v1/module.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package atomone.gov.module.v1;
4 |
5 | import "cosmos/app/v1alpha1/module.proto";
6 |
7 | // Module is the config object of the gov module.
8 | message Module {
9 | option (cosmos.app.v1alpha1.module) = {
10 | go_import : "github.com/atomone-hub/atomone/x/gov"
11 | };
12 |
13 | // max_metadata_len defines the maximum proposal metadata length.
14 | // Defaults to 255 if not explicitly set.
15 | uint64 max_metadata_len = 1;
16 |
17 | // authority defines the custom module authority. If not set, defaults to the
18 | // governance module.
19 | string authority = 2;
20 | }
21 |
--------------------------------------------------------------------------------
/proto/atomone/gov/v1/genesis.proto:
--------------------------------------------------------------------------------
1 | // Since: cosmos-sdk 0.46
2 | syntax = "proto3";
3 |
4 | package atomone.gov.v1;
5 |
6 | import "atomone/gov/v1/gov.proto";
7 |
8 | option go_package = "github.com/atomone-hub/atomone/x/gov/types/v1";
9 |
10 | // GenesisState defines the gov module's genesis state.
11 | message GenesisState {
12 | // starting_proposal_id is the ID of the starting proposal.
13 | uint64 starting_proposal_id = 1;
14 | // deposits defines all the deposits present at genesis.
15 | repeated Deposit deposits = 2;
16 | // votes defines all the votes present at genesis.
17 | repeated Vote votes = 3;
18 | // proposals defines all the proposals present at genesis.
19 | repeated Proposal proposals = 4;
20 | // Deprecated: Prefer to use `params` instead.
21 | // deposit_params defines all the paramaters of related to deposit.
22 | DepositParams deposit_params = 5 [ deprecated = true ];
23 | // Deprecated: Prefer to use `params` instead.
24 | // voting_params defines all the paramaters of related to voting.
25 | VotingParams voting_params = 6 [ deprecated = true ];
26 | // Deprecated: Prefer to use `params` instead.
27 | // tally_params defines all the paramaters of related to tally.
28 | TallyParams tally_params = 7 [ deprecated = true ];
29 | // params defines all the paramaters of x/gov module.
30 | //
31 | // Since: cosmos-sdk 0.47
32 | Params params = 8;
33 | // The constitution allows builders to lay a foundation and define purpose.
34 | //
35 | // Since: cosmos-sdk 0.48
36 | string constitution = 9;
37 |
38 | // last updated value for the dynamic min deposit
39 | LastMinDeposit last_min_deposit = 10;
40 |
41 | // last updated value for the dynamic min initial deposit
42 | LastMinDeposit last_min_initial_deposit = 11;
43 | }
44 |
--------------------------------------------------------------------------------
/proto/atomone/gov/v1beta1/genesis.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package atomone.gov.v1beta1;
4 |
5 | import "gogoproto/gogo.proto";
6 | import "atomone/gov/v1beta1/gov.proto";
7 | import "amino/amino.proto";
8 |
9 | option go_package = "github.com/atomone-hub/atomone/x/gov/types/v1beta1";
10 |
11 | // GenesisState defines the gov module's genesis state.
12 | message GenesisState {
13 | // starting_proposal_id is the ID of the starting proposal.
14 | uint64 starting_proposal_id = 1;
15 | // deposits defines all the deposits present at genesis.
16 | repeated Deposit deposits = 2 [
17 | (gogoproto.castrepeated) = "Deposits",
18 | (gogoproto.nullable) = false,
19 | (amino.dont_omitempty) = true
20 | ];
21 | // votes defines all the votes present at genesis.
22 | repeated Vote votes = 3 [
23 | (gogoproto.castrepeated) = "Votes",
24 | (gogoproto.nullable) = false,
25 | (amino.dont_omitempty) = true
26 | ];
27 | // proposals defines all the proposals present at genesis.
28 | repeated Proposal proposals = 4 [
29 | (gogoproto.castrepeated) = "Proposals",
30 | (gogoproto.nullable) = false,
31 | (amino.dont_omitempty) = true
32 | ];
33 | // params defines all the parameters of related to deposit.
34 | DepositParams deposit_params = 5
35 | [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
36 | // params defines all the parameters of related to voting.
37 | VotingParams voting_params = 6
38 | [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
39 | // params defines all the parameters of related to tally.
40 | TallyParams tally_params = 7
41 | [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
42 | }
43 |
--------------------------------------------------------------------------------
/proto/atomone/photon/v1/genesis.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package atomone.photon.v1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "atomone/photon/v1/photon.proto";
6 | import "amino/amino.proto";
7 |
8 | option go_package = "github.com/atomone-hub/atomone/x/photon/types";
9 |
10 | // GenesisState defines the x/photon module's genesis state.
11 | message GenesisState {
12 | Params params = 1 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ];
13 | }
14 |
--------------------------------------------------------------------------------
/proto/atomone/photon/v1/photon.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package atomone.photon.v1;
3 |
4 | import "gogoproto/gogo.proto";
5 |
6 | option go_package = "github.com/atomone-hub/atomone/x/photon/types";
7 |
8 | // Params defines the parameters for the x/photon module.
9 | message Params {
10 | // Allow to mint photon or not
11 | bool mint_disabled = 1;
12 | // tx_fee_exceptions holds the msg type urls that are allowed to use some
13 | // different tx fee coins than photon.
14 | // A wildcard "*" can be used to allow all transactions to use any fee denom.
15 | repeated string tx_fee_exceptions = 2;
16 | }
17 |
--------------------------------------------------------------------------------
/proto/atomone/photon/v1/query.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package atomone.photon.v1;
3 |
4 | import "gogoproto/gogo.proto";
5 | import "google/api/annotations.proto";
6 | import "cosmos/base/query/v1beta1/pagination.proto";
7 | import "atomone/photon/v1/photon.proto";
8 | import "cosmos/base/v1beta1/coin.proto";
9 | import "amino/amino.proto";
10 | import "cosmos_proto/cosmos.proto";
11 |
12 | option go_package = "github.com/atomone-hub/atomone/x/photon/types";
13 |
14 | // Query defines the gRPC querier service.
15 | service Query {
16 | // Parameters queries the parameters of the module.
17 | rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
18 | option (google.api.http).get = "/atomone/photon/v1/params";
19 | }
20 | // ConversionRate queries the photon's conversion rate
21 | rpc ConversionRate(QueryConversionRateRequest) returns (QueryConversionRateResponse) {
22 | option (google.api.http).get = "/atomone/photon/v1/conversion_rate";
23 | }
24 | }
25 |
26 | // QueryParamsRequest is request type for the Query/Params RPC method.
27 | message QueryParamsRequest {}
28 |
29 | // QueryParamsResponse is response type for the Query/Params RPC method.
30 | message QueryParamsResponse {
31 | // params holds all the parameters of this module.
32 | Params params = 1 [ (gogoproto.nullable) = false ];
33 | }
34 |
35 | // QueryConversionRateRequest is request type for the Query/ConversionRate RPC method.
36 | message QueryConversionRateRequest {}
37 |
38 | // QueryConversionRateResponse is response type for the Query/ConversionRate RPC method.
39 | message QueryConversionRateResponse {
40 | // conversion_rate represents the factor used to convert atone to photon.
41 | string conversion_rate = 1 [ (cosmos_proto.scalar) = "cosmos.Dec" ];
42 | }
43 |
--------------------------------------------------------------------------------
/proto/buf.gen.gogo.yaml:
--------------------------------------------------------------------------------
1 | version: v1
2 | plugins:
3 | - name: gocosmos
4 | out: ..
5 | opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types
6 | - name: grpc-gateway
7 | out: ..
8 | opt: logtostderr=true,allow_colon_final_segments=true
--------------------------------------------------------------------------------
/proto/buf.gen.pulsar.yaml:
--------------------------------------------------------------------------------
1 | version: v1
2 |
3 | managed:
4 | enabled: true
5 | go_package_prefix:
6 | default: cosmossdk.io/api
7 | except:
8 | - buf.build/googleapis/googleapis
9 | - buf.build/cosmos/gogo-proto
10 | - buf.build/cosmos/cosmos-proto
11 | plugins:
12 | - name: go-pulsar
13 | out: ../api
14 | opt: paths=source_relative
15 | - name: go-grpc
16 | out: ../api
17 | opt: paths=source_relative
--------------------------------------------------------------------------------
/proto/buf.gen.swagger.yaml:
--------------------------------------------------------------------------------
1 | version: v1
2 | plugins:
3 | - name: swagger
4 | out: ./tmp-swagger-gen
5 | opt:
6 | - logtostderr=true
7 | - fqn_for_swagger_name=true
8 | - simple_operation_ids=true
9 |
--------------------------------------------------------------------------------
/proto/buf.lock:
--------------------------------------------------------------------------------
1 | # Generated by buf. DO NOT EDIT.
2 | version: v1
3 | deps:
4 | - remote: buf.build
5 | owner: cosmos
6 | repository: cosmos-proto
7 | commit: 1935555c206d4afb9e94615dfd0fad31
8 | digest: shake256:c74d91a3ac7ae07d579e90eee33abf9b29664047ac8816500cf22c081fec0d72d62c89ce0bebafc1f6fec7aa5315be72606717740ca95007248425102c365377
9 | - remote: buf.build
10 | owner: cosmos
11 | repository: cosmos-sdk
12 | commit: 954f7b05f38440fc8250134b15adec47
13 | digest: shake256:2ab4404fd04a7d1d52df0e2d0f2d477a3d83ffd88d876957bf3fedfd702c8e52833d65b3ce1d89a3c5adf2aab512616b0e4f51d8463f07eda9a8a3317ee3ac54
14 | - remote: buf.build
15 | owner: cosmos
16 | repository: gogo-proto
17 | commit: 5e5b9fdd01804356895f8f79a6f1ddc1
18 | digest: shake256:0b85da49e2e5f9ebc4806eae058e2f56096ff3b1c59d1fb7c190413dd15f45dd456f0b69ced9059341c80795d2b6c943de15b120a9e0308b499e43e4b5fc2952
19 | - remote: buf.build
20 | owner: cosmos
21 | repository: ibc
22 | commit: fbb44f5ad3194450af479a615fa715d9
23 | digest: shake256:3fbf41c96089017ebf3b5143f78de0d531f604cb11da1bc98b2104eb6dd295b8a49f5f35c60b8389ba50bfa08959da905109324099e75ece9afd8e4087b14019
24 | - remote: buf.build
25 | owner: cosmos
26 | repository: ics23
27 | commit: 55085f7c710a45f58fa09947208eb70b
28 | digest: shake256:9bf0bc495b5a11c88d163d39ef521bc4b00bc1374a05758c91d82821bdc61f09e8c2c51dda8452529bf80137f34d852561eacbe9550a59015d51cecb0dacb628
29 | - remote: buf.build
30 | owner: cosmos
31 | repository: interchain-security
32 | commit: 4fcaba68958648a180fdc72c487018b5
33 | digest: shake256:a699ee174513d757cbd2f7a5827f9622b15c0204fe850bdeedbeb4e141f6c33a0e3e341e7aaf6cdd2e05f3deaf6932282805a090b0624759a2418ed7aceb3bc7
34 | - remote: buf.build
35 | owner: googleapis
36 | repository: googleapis
37 | commit: cc916c31859748a68fd229a3c8d7a2e8
38 | digest: shake256:469b049d0eb04203d5272062636c078decefc96fec69739159c25d85349c50c34c7706918a8b216c5c27f76939df48452148cff8c5c3ae77fa6ba5c25c1b8bf8
39 |
--------------------------------------------------------------------------------
/proto/buf.yaml:
--------------------------------------------------------------------------------
1 | # Generated by "buf config migrate-v1beta1". Edit as necessary, and
2 | # remove this comment when you're finished.
3 | #
4 | # This module represents the "proto" root found in
5 | # the previous configuration.
6 | version: v1
7 | name: buf.build/atomone-hub/atomone
8 | deps:
9 | - buf.build/cosmos/gogo-proto
10 | - buf.build/cosmos/cosmos-sdk:v0.47.0
11 | - buf.build/googleapis/googleapis
12 |
13 | breaking:
14 | use:
15 | - FILE
16 | lint:
17 | use:
18 | - DEFAULT
19 | - COMMENTS
20 | - FILE_LOWER_SNAKE_CASE
21 | except:
22 | - UNARY_RPC
23 | - COMMENT_FIELD
24 | - SERVICE_SUFFIX
25 | - PACKAGE_VERSION_SUFFIX
26 | - RPC_REQUEST_STANDARD_NAME
27 | ignore:
28 | - tendermint
29 |
--------------------------------------------------------------------------------
/proto/scripts/protoc-swagger-gen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eo pipefail
4 |
5 | cd proto
6 | # Generate atomone & cosmos-sdj swagger files
7 | # We don't care about filtering query.proto or service.proto files, because
8 | # client/docs/config.json has a white list of the required files.
9 | buf generate --template buf.gen.swagger.yaml
10 | buf generate --template buf.gen.swagger.yaml buf.build/cosmos/cosmos-sdk
11 |
12 | # combine swagger files
13 | # uses nodejs package `swagger-combine`.
14 | # all the individual swagger files need to be configured in `config.json` for merging
15 | swagger-combine ../client/docs/config.json -o ../client/docs/swagger-ui/swagger.yaml -f yaml --continueOnConflictingPaths true --includeDefinitions true
16 |
17 | # clean swagger files
18 | rm -rf ./tmp-swagger-gen
19 |
--------------------------------------------------------------------------------
/proto/scripts/protocgen-pulsar.sh:
--------------------------------------------------------------------------------
1 |
2 | # this script is for generating protobuf files for the new google.golang.org/protobuf API
3 |
4 | set -eo pipefail
5 |
6 | protoc_install_gopulsar() {
7 | go install github.com/cosmos/cosmos-proto/cmd/protoc-gen-go-pulsar@latest
8 | go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
9 | }
10 |
11 | protoc_install_gopulsar
12 |
13 | echo "Cleaning API directory"
14 | (cd api; find ./ -type f \( -iname \*.pulsar.go -o -iname \*.pb.go -o -iname \*.cosmos_orm.go -o -iname \*.pb.gw.go \) -delete; find . -empty -type d -delete; cd ..)
15 |
16 | echo "Generating API module"
17 | (cd proto; buf generate --template buf.gen.pulsar.yaml)
18 |
--------------------------------------------------------------------------------
/proto/scripts/protocgen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -eo pipefail
4 | echo "Generating gogo proto code"
5 | cd proto
6 | proto_dirs=$(find ./ -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq)
7 | for dir in $proto_dirs; do
8 | for file in $(find "${dir}" -maxdepth 1 -name '*.proto'); do
9 | if grep "option go_package" $file &> /dev/null ; then
10 | buf generate --template buf.gen.gogo.yaml $file
11 | fi
12 | done
13 | done
14 | cd ..
15 | # move proto files to the right places
16 | cp -r github.com/atomone-hub/atomone/* ./
17 | rm -rf github.com
18 |
--------------------------------------------------------------------------------
/tests/e2e/address.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "fmt"
5 | "math/rand"
6 | "strconv"
7 |
8 | "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
9 | crypto "github.com/cosmos/cosmos-sdk/crypto/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | )
12 |
13 | // HDPath generates an HD path based on the wallet index
14 | func HDPath(index int) string {
15 | return fmt.Sprintf("m/44'/118'/0'/0/%d", index)
16 | }
17 |
18 | // PubKey returns a sample account PubKey
19 | func PubKey() crypto.PubKey {
20 | seed := []byte(strconv.Itoa(rand.Int()))
21 | return ed25519.GenPrivKeyFromSecret(seed).PubKey()
22 | }
23 |
24 | // AccAddress returns a sample account address
25 | func AccAddress() sdk.AccAddress {
26 | addr := PubKey().Address()
27 | return sdk.AccAddress(addr)
28 | }
29 |
30 | // Address returns a sample string account address
31 | func Address() string {
32 | return AccAddress().String()
33 | }
34 |
--------------------------------------------------------------------------------
/tests/e2e/doc.go:
--------------------------------------------------------------------------------
1 | // package e2e defines an integration testing suite used for full end-to-end
2 | // testing functionality.
3 | //
4 | // The file e2e_suite_test.go defines the testing suite and contains the core
5 | // bootrapping logic that creates a testing environment via Docker containers.
6 | // A testing network is created dynamically and contains multiple Docker
7 | // containers:
8 | //
9 | // 1. Two independent AtomOne networks
10 | // 3. A hermes relayer connecting the two AtomOne networks over IBC
11 | //
12 | // The file e2e_test.go contains the actual end-to-end integration tests that
13 | // utilize the testing suite.
14 | package e2e
15 |
--------------------------------------------------------------------------------
/tests/e2e/docker/hermes.Dockerfile:
--------------------------------------------------------------------------------
1 | FROM --platform=linux/amd64 informalsystems/hermes:1.10.0 AS hermes-builder
2 |
3 | FROM --platform=linux/amd64 debian:buster-slim
4 | USER root
5 |
6 | COPY --from=hermes-builder /usr/bin/hermes /usr/local/bin/
7 | RUN chmod +x /usr/local/bin/hermes
8 |
9 | EXPOSE 3031
--------------------------------------------------------------------------------
/tests/e2e/e2e_encode_test.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "encoding/base64"
5 | "path/filepath"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | )
9 |
10 | const (
11 | rawTxFile = "tx_raw.json"
12 | )
13 |
14 | func (s *IntegrationTestSuite) testEncode() {
15 | chain := s.chainA
16 | _, encoded, err := buildRawTx()
17 | s.Require().NoError(err)
18 |
19 | got := s.execEncode(chain, filepath.Join(atomoneHomePath, rawTxFile))
20 | s.T().Logf("encoded tx: %s", got)
21 | s.Require().Equal(encoded, got)
22 | }
23 |
24 | func (s *IntegrationTestSuite) testDecode() {
25 | chain := s.chainA
26 | rawTx, encoded, err := buildRawTx()
27 | s.Require().NoError(err)
28 |
29 | got := s.execDecode(chain, encoded)
30 | s.T().Logf("raw tx: %s", got)
31 | s.Require().Equal(string(rawTx), got)
32 | }
33 |
34 | // buildRawTx build a dummy tx using the TxBuilder and
35 | // return the JSON and encoded tx's
36 | func buildRawTx() ([]byte, string, error) {
37 | builder := txConfig.NewTxBuilder()
38 | builder.SetGasLimit(gas)
39 | builder.SetFeeAmount(sdk.NewCoins(standardFees))
40 | builder.SetMemo("foomemo")
41 | tx, err := txConfig.TxJSONEncoder()(builder.GetTx())
42 | if err != nil {
43 | return nil, "", err
44 | }
45 | txBytes, err := txConfig.TxEncoder()(builder.GetTx())
46 | if err != nil {
47 | return nil, "", err
48 | }
49 | return tx, base64.StdEncoding.EncodeToString(txBytes), err
50 | }
51 |
--------------------------------------------------------------------------------
/tests/e2e/e2e_evidence_test.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 |
8 | "github.com/cosmos/cosmos-sdk/x/evidence/exported"
9 | evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
10 | )
11 |
12 | func (s *IntegrationTestSuite) testEvidenceQueries() {
13 | s.Run("queries", func() {
14 | var (
15 | valIdx = 0
16 | chain = s.chainA
17 | chainAPI = fmt.Sprintf("http://%s", s.valResources[chain.id][valIdx].GetHostPort("1317/tcp"))
18 | )
19 | res, err := queryAllEvidence(chainAPI)
20 | s.Require().NoError(err)
21 | s.Require().Equal(numberOfEvidences, len(res.Evidence))
22 | for _, evidence := range res.Evidence {
23 | var exportedEvidence exported.Evidence
24 | err := cdc.UnpackAny(evidence, &exportedEvidence)
25 | s.Require().NoError(err)
26 | eq, ok := exportedEvidence.(*evidencetypes.Equivocation)
27 | s.Require().True(ok)
28 | s.execQueryEvidence(chain, valIdx, eq.Hash().String())
29 | }
30 | })
31 | }
32 |
33 | func (s *IntegrationTestSuite) execQueryEvidence(c *chain, valIdx int, hash string) (res evidencetypes.Equivocation) {
34 | ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
35 | defer cancel()
36 |
37 | s.T().Logf("querying evidence %s on chain %s", hash, c.id)
38 |
39 | atomoneCommand := []string{
40 | atomonedBinary,
41 | queryCommand,
42 | evidencetypes.ModuleName,
43 | hash,
44 | }
45 |
46 | s.executeAtomoneTxCommand(ctx, c, atomoneCommand, valIdx, func(stdOut []byte, stdErr []byte) bool {
47 | // TODO parse evidence after fix the SDK
48 | // https://github.com/cosmos/cosmos-sdk/issues/13444
49 | // s.Require().NoError(yaml.Unmarshal(stdOut, &res))
50 | return true
51 | })
52 | return res
53 | }
54 |
--------------------------------------------------------------------------------
/tests/e2e/e2e_slashing_test.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | const jailedValidatorKey = "jailed"
4 |
5 | func (s *IntegrationTestSuite) testSlashing(chainEndpoint string) {
6 | s.Run("unjail validator", func() {
7 | validators, err := queryValidators(chainEndpoint)
8 | s.Require().NoError(err)
9 |
10 | for _, val := range validators {
11 | if val.Jailed {
12 | s.execUnjail(
13 | s.chainA,
14 | withKeyValue(flagFrom, jailedValidatorKey),
15 | )
16 |
17 | valQ, err := queryValidator(chainEndpoint, val.OperatorAddress)
18 | s.Require().NoError(err)
19 | s.Require().False(valQ.Jailed)
20 | }
21 | }
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/tests/e2e/io.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | )
8 |
9 | // copyFile copy file from src to dst
10 | func copyFile(src, dst string) (int64, error) {
11 | sourceFileStat, err := os.Stat(src)
12 | if err != nil {
13 | return 0, err
14 | }
15 |
16 | if !sourceFileStat.Mode().IsRegular() {
17 | return 0, fmt.Errorf("%s is not a regular file", src)
18 | }
19 |
20 | source, err := os.Open(src)
21 | if err != nil {
22 | return 0, err
23 | }
24 | defer source.Close()
25 |
26 | destination, err := os.Create(dst)
27 | if err != nil {
28 | return 0, err
29 | }
30 | defer destination.Close()
31 |
32 | nBytes, err := io.Copy(destination, source)
33 | return nBytes, err
34 | }
35 |
36 | // writeFile write a byte slice into a file path
37 | // create the file if it doesn't exist
38 | // NOTE: this file can be write and read by everyone
39 | func writeFile(path string, body []byte) error {
40 | return os.WriteFile(path, body, 0o666) //nolint:gosec
41 | }
42 |
--------------------------------------------------------------------------------
/tests/e2e/keys.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "github.com/cosmos/go-bip39"
5 | )
6 |
7 | // createMnemonic creates a random string mnemonic
8 | func createMnemonic() (string, error) {
9 | entropySeed, err := bip39.NewEntropy(256)
10 | if err != nil {
11 | return "", err
12 | }
13 |
14 | mnemonic, err := bip39.NewMnemonic(entropySeed)
15 | if err != nil {
16 | return "", err
17 | }
18 |
19 | return mnemonic, nil
20 | }
21 |
--------------------------------------------------------------------------------
/tests/e2e/util_test.go:
--------------------------------------------------------------------------------
1 | package e2e
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec/unknownproto"
7 | sdktx "github.com/cosmos/cosmos-sdk/types/tx"
8 | )
9 |
10 | func decodeTx(txBytes []byte) (*sdktx.Tx, error) {
11 | var raw sdktx.TxRaw
12 |
13 | // reject all unknown proto fields in the root TxRaw
14 | err := unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, encodingConfig.InterfaceRegistry)
15 | if err != nil {
16 | return nil, fmt.Errorf("failed to reject unknown fields: %w", err)
17 | }
18 |
19 | if err := cdc.Unmarshal(txBytes, &raw); err != nil {
20 | return nil, err
21 | }
22 |
23 | var body sdktx.TxBody
24 | if err := cdc.Unmarshal(raw.BodyBytes, &body); err != nil {
25 | return nil, fmt.Errorf("failed to decode tx: %w", err)
26 | }
27 |
28 | var authInfo sdktx.AuthInfo
29 |
30 | // reject all unknown proto fields in AuthInfo
31 | err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, encodingConfig.InterfaceRegistry)
32 | if err != nil {
33 | return nil, fmt.Errorf("failed to reject unknown fields: %w", err)
34 | }
35 |
36 | if err := cdc.Unmarshal(raw.AuthInfoBytes, &authInfo); err != nil {
37 | return nil, fmt.Errorf("failed to decode auth info: %w", err)
38 | }
39 |
40 | return &sdktx.Tx{
41 | Body: &body,
42 | AuthInfo: &authInfo,
43 | Signatures: raw.Signatures,
44 | }, nil
45 | }
46 |
47 | func concatFlags(originalCollection []string, commandFlags []string, generalFlags []string) []string {
48 | originalCollection = append(originalCollection, commandFlags...)
49 | originalCollection = append(originalCollection, generalFlags...)
50 |
51 | return originalCollection
52 | }
53 |
--------------------------------------------------------------------------------
/types/errors/errors.go:
--------------------------------------------------------------------------------
1 | package errors
2 |
3 | import (
4 | errorsmod "cosmossdk.io/errors"
5 | )
6 |
7 | const codespace = "atomone"
8 |
9 | var (
10 | // ErrTxDecode is returned if we cannot parse a transaction
11 | ErrTxDecode = errorsmod.Register(codespace, 1, "tx parse error")
12 | // ErrUnauthorized is used whenever a request without sufficient
13 | // authorization is handled.
14 | ErrUnauthorized = errorsmod.Register(codespace, 2, "unauthorized")
15 |
16 | // ErrInsufficientFunds is used when the account cannot pay requested amount.
17 | ErrInsufficientFunds = errorsmod.Register(codespace, 3, "insufficient funds")
18 |
19 | // ErrInsufficientFunds is used when the account cannot pay requested amount.
20 | ErrInsufficientFee = errorsmod.Register(codespace, 4, "insufficient fee")
21 |
22 | // ErrInvalidCoins is used when sdk.Coins are invalid.
23 | ErrInvalidCoins = errorsmod.Register(codespace, 5, "invalid coins")
24 |
25 | // ErrInvalidType defines an error an invalid type.
26 | ErrInvalidType = errorsmod.Register(codespace, 6, "invalid type")
27 |
28 | // ErrLogic defines an internal logic error, e.g. an invariant or assertion
29 | // that is violated. It is a programmer error, not a user-facing error.
30 | ErrLogic = errorsmod.Register(codespace, 7, "internal logic error")
31 |
32 | // ErrNotFound defines an error when requested entity doesn't exist in the state.
33 | ErrNotFound = errorsmod.Register(codespace, 8, "not found")
34 |
35 | // ErrInsufficientStake is used when the account has insufficient staked tokens.
36 | ErrInsufficientStake = errorsmod.Register(codespace, 9, "insufficient stake")
37 | )
38 |
--------------------------------------------------------------------------------
/x/feemarket/ante/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
6 |
7 | "github.com/atomone-hub/atomone/x/feemarket/types"
8 | )
9 |
10 | type FeeMarketKeeper interface {
11 | GetMinGasPrice(sdk.Context, string) (sdk.DecCoin, error)
12 | GetParams(sdk.Context) (types.Params, error)
13 | }
14 |
15 | // AccountKeeper defines the contract needed for AccountKeeper related APIs.
16 | // Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators.
17 | type AccountKeeper interface {
18 | GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
19 | }
20 |
21 | // FeeGrantKeeper defines the expected feegrant keeper.
22 | type FeeGrantKeeper interface {
23 | UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
24 | }
25 |
26 | // BankKeeper defines the contract needed for supply related APIs.
27 | type BankKeeper interface {
28 | SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
29 | }
30 |
--------------------------------------------------------------------------------
/x/feemarket/fuzz/tx_priority_test.go:
--------------------------------------------------------------------------------
1 | package fuzz_test
2 |
3 | import (
4 | "math"
5 | "testing"
6 |
7 | sdkmath "cosmossdk.io/math"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/stretchr/testify/require"
10 | "pgregory.net/rapid"
11 |
12 | "github.com/atomone-hub/atomone/x/feemarket/ante"
13 | )
14 |
15 | type input struct {
16 | payFee sdk.Coin
17 | gasLimit int64
18 | currentGasPrice sdk.DecCoin
19 | }
20 |
21 | // TestGetTxPriority ensures that tx priority is properly bounded
22 | func TestGetTxPriority(t *testing.T) {
23 | rapid.Check(t, func(t *rapid.T) {
24 | inputs := createRandomInput(t)
25 |
26 | priority := ante.GetTxPriority(inputs.payFee, inputs.gasLimit, inputs.currentGasPrice)
27 | require.GreaterOrEqual(t, priority, int64(0))
28 | require.LessOrEqual(t, priority, int64(math.MaxInt64))
29 | })
30 | }
31 |
32 | // CreateRandomInput returns a random inputs to the priority function.
33 | func createRandomInput(t *rapid.T) input {
34 | denom := "skip"
35 |
36 | price := rapid.Int64Range(1, 1_000_000_000).Draw(t, "gas price")
37 | priceDec := sdkmath.LegacyNewDecWithPrec(price, 6)
38 |
39 | gasLimit := rapid.Int64Range(1_000_000, 1_000_000_000_000).Draw(t, "gas limit")
40 |
41 | if priceDec.MulInt64(gasLimit).GTE(sdkmath.LegacyNewDec(math.MaxInt64)) {
42 | t.Fatalf("not supposed to happen")
43 | }
44 |
45 | payFeeAmt := rapid.Int64Range(priceDec.MulInt64(gasLimit).TruncateInt64(), math.MaxInt64).Draw(t, "fee amount")
46 |
47 | return input{
48 | payFee: sdk.NewCoin(denom, sdkmath.NewInt(payFeeAmt)),
49 | gasLimit: gasLimit,
50 | currentGasPrice: sdk.NewDecCoinFromDec(denom, priceDec),
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/x/feemarket/keeper/abci.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | abci "github.com/cometbft/cometbft/abci/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // EndBlock returns an endblocker for the x/feemarket module. The endblocker
10 | // is responsible for updating the state of the fee market based on the
11 | // AIMD learning rate adjustment algorithm.
12 | func (k *Keeper) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
13 | if err := k.UpdateFeeMarket(ctx); err != nil {
14 | panic(err)
15 | }
16 |
17 | return []abci.ValidatorUpdate{}
18 | }
19 |
--------------------------------------------------------------------------------
/x/feemarket/keeper/genesis.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | "github.com/atomone-hub/atomone/x/feemarket/types"
7 | )
8 |
9 | // InitGenesis initializes the feemarket module's state from a given genesis state.
10 | func (k *Keeper) InitGenesis(ctx sdk.Context, gs types.GenesisState) {
11 | if err := gs.ValidateBasic(); err != nil {
12 | panic(err)
13 | }
14 |
15 | if gs.Params.Window != uint64(len(gs.State.Window)) {
16 | panic("genesis state and parameters do not match for window")
17 | }
18 |
19 | // Initialize the fee market state and parameters.
20 | if err := k.SetParams(ctx, gs.Params); err != nil {
21 | panic(err)
22 | }
23 |
24 | if err := k.SetState(ctx, gs.State); err != nil {
25 | panic(err)
26 | }
27 |
28 | // always init enabled height to -1 until it is explicitly set later in the application
29 | k.SetEnabledHeight(ctx, -1)
30 | }
31 |
32 | // ExportGenesis returns a GenesisState for a given context.
33 | func (k *Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
34 | // Get the feemarket module's parameters.
35 | params, err := k.GetParams(ctx)
36 | if err != nil {
37 | panic(err)
38 | }
39 |
40 | // Get the feemarket module's state.
41 | state, err := k.GetState(ctx)
42 | if err != nil {
43 | panic(err)
44 | }
45 |
46 | return types.NewGenesisState(params, state)
47 | }
48 |
--------------------------------------------------------------------------------
/x/feemarket/keeper/genesis_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/atomone-hub/atomone/x/feemarket/testutil"
7 | "github.com/atomone-hub/atomone/x/feemarket/types"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestInitGenesis(t *testing.T) {
12 | k, _, ctx := testutil.SetupKeeper(t, 0)
13 | t.Run("default genesis should not panic", func(t *testing.T) {
14 | require.NotPanics(t, func() {
15 | k.InitGenesis(ctx, *types.DefaultGenesisState())
16 | })
17 | })
18 |
19 | t.Run("default AIMD genesis should not panic", func(t *testing.T) {
20 | require.NotPanics(t, func() {
21 | k.InitGenesis(ctx, *types.DefaultAIMDGenesisState())
22 | })
23 | })
24 |
25 | t.Run("bad genesis state should panic", func(t *testing.T) {
26 | gs := types.DefaultGenesisState()
27 | gs.Params.Window = 0
28 | require.Panics(t, func() {
29 | k.InitGenesis(ctx, *gs)
30 | })
31 | })
32 |
33 | t.Run("mismatch in params and state for window should panic", func(t *testing.T) {
34 | gs := types.DefaultAIMDGenesisState()
35 | gs.Params.Window = 1
36 |
37 | require.Panics(t, func() {
38 | k.InitGenesis(ctx, *gs)
39 | })
40 | })
41 | }
42 |
43 | func TestExportGenesis(t *testing.T) {
44 | k, _, ctx := testutil.SetupKeeper(t, 0)
45 | t.Run("export genesis should not panic for default eip-1559", func(t *testing.T) {
46 | gs := types.DefaultGenesisState()
47 | k.InitGenesis(ctx, *gs)
48 |
49 | var exportedGenesis *types.GenesisState
50 | require.NotPanics(t, func() {
51 | exportedGenesis = k.ExportGenesis(ctx)
52 | })
53 |
54 | require.Equal(t, gs, exportedGenesis)
55 | })
56 |
57 | t.Run("export genesis should not panic for default AIMD eip-1559", func(t *testing.T) {
58 | gs := types.DefaultAIMDGenesisState()
59 | k.InitGenesis(ctx, *gs)
60 |
61 | var exportedGenesis *types.GenesisState
62 | require.NotPanics(t, func() {
63 | exportedGenesis = k.ExportGenesis(ctx)
64 | })
65 |
66 | require.Equal(t, gs, exportedGenesis)
67 | })
68 | }
69 |
--------------------------------------------------------------------------------
/x/feemarket/keeper/msg_server.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 | "fmt"
6 |
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 |
9 | "github.com/atomone-hub/atomone/x/feemarket/types"
10 | )
11 |
12 | var _ types.MsgServer = (*MsgServer)(nil)
13 |
14 | // MsgServer is the server API for x/feemarket Msg service.
15 | type MsgServer struct {
16 | k *Keeper
17 | }
18 |
19 | // NewMsgServer returns the MsgServer implementation.
20 | func NewMsgServer(k *Keeper) types.MsgServer {
21 | return &MsgServer{k}
22 | }
23 |
24 | // Params defines a method that updates the module's parameters. The signer of the message must
25 | // be the module authority.
26 | func (ms MsgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) {
27 | ctx := sdk.UnwrapSDKContext(goCtx)
28 |
29 | if msg.Authority != ms.k.GetAuthority() {
30 | return nil, fmt.Errorf("invalid authority to execute message")
31 | }
32 |
33 | gotParams, err := ms.k.GetParams(ctx)
34 | if err != nil {
35 | return nil, fmt.Errorf("error getting params: %w", err)
36 | }
37 |
38 | // if going from disabled -> enabled, set enabled height
39 | if !gotParams.Enabled && msg.Params.Enabled {
40 | ms.k.SetEnabledHeight(ctx, ctx.BlockHeight())
41 | }
42 |
43 | params := msg.Params
44 | if err := ms.k.SetParams(ctx, params); err != nil {
45 | return nil, fmt.Errorf("error setting params: %w", err)
46 | }
47 |
48 | newState := types.NewState(params.Window, params.MinBaseGasPrice, params.MinLearningRate)
49 | if err := ms.k.SetState(ctx, newState); err != nil {
50 | return nil, fmt.Errorf("error setting state: %w", err)
51 | }
52 |
53 | return &types.MsgUpdateParamsResponse{}, nil
54 | }
55 |
--------------------------------------------------------------------------------
/x/feemarket/keeper/query_server.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | "github.com/atomone-hub/atomone/x/feemarket/types"
9 | )
10 |
11 | var _ types.QueryServer = (*QueryServer)(nil)
12 |
13 | // QueryServer defines the gRPC server for the x/feemarket module.
14 | type QueryServer struct {
15 | k Keeper
16 | }
17 |
18 | // NewQueryServer creates a new instance of the x/feemarket QueryServer type.
19 | func NewQueryServer(keeper Keeper) types.QueryServer {
20 | return &QueryServer{k: keeper}
21 | }
22 |
23 | // Params defines a method that returns the current feemarket parameters.
24 | func (q QueryServer) Params(goCtx context.Context, _ *types.ParamsRequest) (*types.ParamsResponse, error) {
25 | ctx := sdk.UnwrapSDKContext(goCtx)
26 |
27 | params, err := q.k.GetParams(ctx)
28 | return &types.ParamsResponse{Params: params}, err
29 | }
30 |
31 | // State defines a method that returns the current feemarket state.
32 | func (q QueryServer) State(goCtx context.Context, _ *types.StateRequest) (*types.StateResponse, error) {
33 | ctx := sdk.UnwrapSDKContext(goCtx)
34 |
35 | state, err := q.k.GetState(ctx)
36 | return &types.StateResponse{State: state}, err
37 | }
38 |
39 | // GasPrice defines a method that returns the current feemarket base gas price.
40 | func (q QueryServer) GasPrice(goCtx context.Context, req *types.GasPriceRequest) (*types.GasPriceResponse, error) {
41 | ctx := sdk.UnwrapSDKContext(goCtx)
42 |
43 | gasPrice, err := q.k.GetMinGasPrice(ctx, req.GetDenom())
44 | return &types.GasPriceResponse{Price: gasPrice}, err
45 | }
46 |
47 | // GasPrices defines a method that returns the current feemarket list of gas prices.
48 | func (q QueryServer) GasPrices(goCtx context.Context, _ *types.GasPricesRequest) (*types.GasPricesResponse, error) {
49 | ctx := sdk.UnwrapSDKContext(goCtx)
50 |
51 | gasPrices, err := q.k.GetMinGasPrices(ctx)
52 | return &types.GasPricesResponse{Prices: gasPrices}, err
53 | }
54 |
--------------------------------------------------------------------------------
/x/feemarket/module_simulation.go:
--------------------------------------------------------------------------------
1 | package feemarket
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/cosmos/cosmos-sdk/types/module"
8 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
9 |
10 | "github.com/atomone-hub/atomone/x/feemarket/types"
11 | "github.com/atomone-hub/atomone/x/gov/simulation"
12 | )
13 |
14 | // GenerateGenesisState returns a disabled feemarket module because the module
15 | // does not work well with simulations. Especially the feemarket ante handler
16 | // does not accept 0 fee coins which is quite common during simulation's
17 | // operations.
18 | func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
19 | params := types.DefaultParams()
20 | params.Enabled = false
21 | genesis := types.NewGenesisState(params, types.DefaultState())
22 | simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(genesis)
23 | fmt.Println("Feemarket module is disabled")
24 | }
25 |
26 | // RegisterStoreDecoder registers a decoder.
27 | func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
28 | sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
29 | }
30 |
31 | // WeightedOperations returns the all the module operations with their respective weights.
32 | func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/x/feemarket/post/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package post
2 |
3 | import (
4 | tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | "github.com/atomone-hub/atomone/x/feemarket/types"
9 | )
10 |
11 | type FeeMarketKeeper interface {
12 | GetState(ctx sdk.Context) (types.State, error)
13 | GetParams(ctx sdk.Context) (types.Params, error)
14 | SetState(ctx sdk.Context, state types.State) error
15 | GetEnabledHeight(ctx sdk.Context) (int64, error)
16 | }
17 |
18 | type ConsensusParamsKeeper interface {
19 | Get(sdk.Context) (*tmproto.ConsensusParams, error)
20 | }
21 |
--------------------------------------------------------------------------------
/x/feemarket/testutil/expected_keepers_mocks.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: x/feemarket/types/expected_keepers.go
3 |
4 | // Package testutil is a generated GoMock package.
5 | package testutil
6 |
7 | import (
8 | reflect "reflect"
9 |
10 | types "github.com/cometbft/cometbft/proto/tendermint/types"
11 | types0 "github.com/cosmos/cosmos-sdk/types"
12 | gomock "github.com/golang/mock/gomock"
13 | )
14 |
15 | // MockConsensusParamsKeeper is a mock of ConsensusParamsKeeper interface.
16 | type MockConsensusParamsKeeper struct {
17 | ctrl *gomock.Controller
18 | recorder *MockConsensusParamsKeeperMockRecorder
19 | }
20 |
21 | // MockConsensusParamsKeeperMockRecorder is the mock recorder for MockConsensusParamsKeeper.
22 | type MockConsensusParamsKeeperMockRecorder struct {
23 | mock *MockConsensusParamsKeeper
24 | }
25 |
26 | // NewMockConsensusParamsKeeper creates a new mock instance.
27 | func NewMockConsensusParamsKeeper(ctrl *gomock.Controller) *MockConsensusParamsKeeper {
28 | mock := &MockConsensusParamsKeeper{ctrl: ctrl}
29 | mock.recorder = &MockConsensusParamsKeeperMockRecorder{mock}
30 | return mock
31 | }
32 |
33 | // EXPECT returns an object that allows the caller to indicate expected use.
34 | func (m *MockConsensusParamsKeeper) EXPECT() *MockConsensusParamsKeeperMockRecorder {
35 | return m.recorder
36 | }
37 |
38 | // Get mocks base method.
39 | func (m *MockConsensusParamsKeeper) Get(arg0 types0.Context) (*types.ConsensusParams, error) {
40 | m.ctrl.T.Helper()
41 | ret := m.ctrl.Call(m, "Get", arg0)
42 | ret0, _ := ret[0].(*types.ConsensusParams)
43 | ret1, _ := ret[1].(error)
44 | return ret0, ret1
45 | }
46 |
47 | // Get indicates an expected call of Get.
48 | func (mr *MockConsensusParamsKeeperMockRecorder) Get(arg0 interface{}) *gomock.Call {
49 | mr.mock.ctrl.T.Helper()
50 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockConsensusParamsKeeper)(nil).Get), arg0)
51 | }
52 |
--------------------------------------------------------------------------------
/x/feemarket/testutil/keeper.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/golang/mock/gomock"
7 |
8 | tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
9 | tmtime "github.com/cometbft/cometbft/types/time"
10 |
11 | "github.com/cosmos/cosmos-sdk/testutil"
12 | sdk "github.com/cosmos/cosmos-sdk/types"
13 | moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
14 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
15 |
16 | "github.com/atomone-hub/atomone/x/feemarket/keeper"
17 | "github.com/atomone-hub/atomone/x/feemarket/types"
18 | govtypes "github.com/atomone-hub/atomone/x/gov/types"
19 | )
20 |
21 | type Mocks struct {
22 | ConsensusParamsKeeper *MockConsensusParamsKeeper
23 | }
24 |
25 | func SetupMsgServer(t *testing.T, maxBlockGas uint64) (types.MsgServer, *keeper.Keeper, Mocks, sdk.Context) {
26 | t.Helper()
27 | k, m, ctx := SetupKeeper(t, maxBlockGas)
28 | return keeper.NewMsgServer(k), k, m, ctx
29 | }
30 |
31 | func SetupQueryServer(t *testing.T, maxBlockGas uint64) (types.QueryServer, *keeper.Keeper, Mocks, sdk.Context) {
32 | t.Helper()
33 | k, m, ctx := SetupKeeper(t, maxBlockGas)
34 | return keeper.NewQueryServer(*k), k, m, ctx
35 | }
36 |
37 | const MaxBlockGas = 30_000_000
38 |
39 | func SetupKeeper(t *testing.T, maxBlockGas uint64) (*keeper.Keeper, Mocks, sdk.Context) {
40 | t.Helper()
41 | ctrl := gomock.NewController(t)
42 | m := Mocks{
43 | ConsensusParamsKeeper: NewMockConsensusParamsKeeper(ctrl),
44 | }
45 |
46 | key := sdk.NewKVStoreKey(types.StoreKey)
47 | testCtx := testutil.DefaultContextWithDB(t, key, sdk.NewTransientStoreKey("transient_test"))
48 | ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()})
49 | encCfg := moduletestutil.MakeTestEncodingConfig()
50 | types.RegisterInterfaces(encCfg.InterfaceRegistry)
51 | // banktypes.RegisterInterfaces(encCfg.InterfaceRegistry)
52 | authority := authtypes.NewModuleAddress(govtypes.ModuleName).String()
53 |
54 | // setup block max gas
55 | if maxBlockGas == 0 {
56 | maxBlockGas = MaxBlockGas
57 | }
58 | m.ConsensusParamsKeeper.EXPECT().Get(ctx).
59 | Return(&tmproto.ConsensusParams{
60 | Block: &tmproto.BlockParams{MaxGas: int64(maxBlockGas)},
61 | }, nil).MaxTimes(1)
62 |
63 | return keeper.NewKeeper(encCfg.Codec, key, &types.ErrorDenomResolver{}, m.ConsensusParamsKeeper, authority), m, ctx
64 | }
65 |
--------------------------------------------------------------------------------
/x/feemarket/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | "github.com/cosmos/cosmos-sdk/codec/legacy"
6 | "github.com/cosmos/cosmos-sdk/codec/types"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | "github.com/cosmos/cosmos-sdk/types/msgservice"
9 | )
10 |
11 | // RegisterLegacyAminoCodec registers the necessary x/feemarket interfaces (messages) on the
12 | // provided LegacyAmino codec.
13 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
14 | legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "atomone/x/feemarket/v1/MsgUpdateParams")
15 | }
16 |
17 | // RegisterInterfaces registers the x/feemarket interfaces (messages + msg server) on the
18 | // provided InterfaceRegistry.
19 | func RegisterInterfaces(registry types.InterfaceRegistry) {
20 | registry.RegisterImplementations((*sdk.Msg)(nil),
21 | &MsgUpdateParams{},
22 | )
23 |
24 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
25 | }
26 |
--------------------------------------------------------------------------------
/x/feemarket/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdkerrors "cosmossdk.io/errors"
5 | )
6 |
7 | var (
8 | ErrNoFeeCoins = sdkerrors.New(ModuleName, 1, "no fee coin provided. Must provide one.")
9 | ErrTooManyFeeCoins = sdkerrors.New(ModuleName, 2, "too many fee coins provided. Only one fee coin may be provided")
10 | ErrResolverNotSet = sdkerrors.New(ModuleName, 3, "denom resolver interface not set. Only the feemarket base fee denomination can be used")
11 | ErrMaxGasExceeded = sdkerrors.New(ModuleName, 4, "block gas cannot exceed max block gas")
12 | )
13 |
--------------------------------------------------------------------------------
/x/feemarket/types/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | type ConsensusParamsKeeper interface {
10 | Get(sdk.Context) (*tmproto.ConsensusParams, error)
11 | }
12 |
--------------------------------------------------------------------------------
/x/feemarket/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "encoding/json"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec"
7 | )
8 |
9 | // NewGenesisState returns a new genesis state for the module.
10 | func NewGenesisState(
11 | params Params,
12 | state State,
13 | ) *GenesisState {
14 | return &GenesisState{
15 | Params: params,
16 | State: state,
17 | }
18 | }
19 |
20 | // ValidateBasic performs basic validation of the genesis state data returning an
21 | // error for any failed validation criteria.
22 | func (gs *GenesisState) ValidateBasic() error {
23 | if err := gs.Params.ValidateBasic(); err != nil {
24 | return err
25 | }
26 | return gs.State.ValidateBasic()
27 | }
28 |
29 | // GetGenesisStateFromAppState returns x/feemarket GenesisState given raw application
30 | // genesis state.
31 | func GetGenesisStateFromAppState(cdc codec.Codec, appState map[string]json.RawMessage) GenesisState {
32 | var gs GenesisState
33 | cdc.MustUnmarshalJSON(appState[ModuleName], &gs)
34 | return gs
35 | }
36 |
--------------------------------------------------------------------------------
/x/feemarket/types/genesis_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | "github.com/atomone-hub/atomone/x/feemarket/types"
9 | )
10 |
11 | func TestGenesis(t *testing.T) {
12 | t.Run("can create a new default genesis state", func(t *testing.T) {
13 | gs := types.DefaultGenesisState()
14 | require.NoError(t, gs.ValidateBasic())
15 | })
16 |
17 | t.Run("can accept a valid genesis state for AIMD eip-1559", func(t *testing.T) {
18 | gs := types.DefaultAIMDGenesisState()
19 | require.NoError(t, gs.ValidateBasic())
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/x/feemarket/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName is the name of the feemarket module.
5 | ModuleName = "feemarket"
6 | // StoreKey is the store key string for the feemarket module.
7 | StoreKey = ModuleName
8 | )
9 |
10 | const (
11 | prefixParams = iota + 1
12 | prefixState
13 | prefixEnableHeight = 3
14 | )
15 |
16 | var (
17 | // KeyParams is the store key for the feemarket module's parameters.
18 | KeyParams = []byte{prefixParams}
19 |
20 | // KeyState is the store key for the feemarket module's data.
21 | KeyState = []byte{prefixState}
22 |
23 | // KeyEnabledHeight is the store key for the feemarket module's enabled height.
24 | KeyEnabledHeight = []byte{prefixEnableHeight}
25 | )
26 |
--------------------------------------------------------------------------------
/x/feemarket/types/msgs.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | )
6 |
7 | var _ sdk.Msg = &MsgUpdateParams{}
8 |
9 | // NewMsgUpdateParams returns a new message to update the x/feemarket module's parameters.
10 | func NewMsgUpdateParams(authority string, params Params) MsgUpdateParams {
11 | return MsgUpdateParams{
12 | Authority: authority,
13 | Params: params,
14 | }
15 | }
16 |
17 | // GetSigners implements GetSigners for the msg.
18 | func (m *MsgUpdateParams) GetSigners() []sdk.AccAddress {
19 | addr, _ := sdk.AccAddressFromBech32(m.Authority)
20 | return []sdk.AccAddress{addr}
21 | }
22 |
23 | // ValidateBasic determines whether the information in the message is formatted correctly, specifically
24 | // whether the authority is a valid acc-address.
25 | func (m *MsgUpdateParams) ValidateBasic() error {
26 | // validate authority address
27 | _, err := sdk.AccAddressFromBech32(m.Authority)
28 | if err != nil {
29 | return err
30 | }
31 |
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/x/feemarket/types/msgs_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 |
10 | "github.com/atomone-hub/atomone/x/feemarket/types"
11 | )
12 |
13 | func TestMsgUpdateParams(t *testing.T) {
14 | t.Run("should reject a message with an invalid authority address", func(t *testing.T) {
15 | msg := types.NewMsgUpdateParams("invalid", types.DefaultParams())
16 | err := msg.ValidateBasic()
17 | require.Error(t, err)
18 | })
19 |
20 | t.Run("should accept an empty message with a valid authority address", func(t *testing.T) {
21 | msg := types.NewMsgUpdateParams(sdk.AccAddress("test").String(), types.DefaultParams())
22 | err := msg.ValidateBasic()
23 | require.NoError(t, err)
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/x/feemarket/types/resolver.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // DenomResolver is an interface to convert a given token to the feemarket's base token.
10 | type DenomResolver interface {
11 | // ConvertToDenom converts deccoin into the equivalent amount of the token denominated in denom.
12 | ConvertToDenom(ctx sdk.Context, coin sdk.DecCoin, denom string) (sdk.DecCoin, error)
13 | // ExtraDenoms returns a list of denoms in addition of `Params.base_denom` it's possible to pay fees with
14 | ExtraDenoms(ctx sdk.Context) ([]string, error)
15 | }
16 |
17 | // TestDenomResolver is a test implementation of the DenomResolver interface. It returns "feeCoin.Amount baseDenom" for all coins that are not the baseDenom.
18 | // NOTE: DO NOT USE THIS IN PRODUCTION
19 | type TestDenomResolver struct{}
20 |
21 | // ConvertToDenom returns "coin.Amount denom" for all coins that are not the denom.
22 | func (r *TestDenomResolver) ConvertToDenom(_ sdk.Context, coin sdk.DecCoin, denom string) (sdk.DecCoin, error) {
23 | if coin.Denom == denom {
24 | return coin, nil
25 | }
26 |
27 | return sdk.NewDecCoinFromDec(denom, coin.Amount), nil
28 | }
29 |
30 | func (r *TestDenomResolver) ExtraDenoms(_ sdk.Context) ([]string, error) {
31 | return []string{}, nil
32 | }
33 |
34 | // ErrorDenomResolver is a test implementation of the DenomResolver interface. It returns an error for all coins that are not the baseDenom.
35 | // NOTE: DO NOT USE THIS IN PRODUCTION
36 | type ErrorDenomResolver struct{}
37 |
38 | // ConvertToDenom returns an error for all coins that are not the denom.
39 | func (r *ErrorDenomResolver) ConvertToDenom(_ sdk.Context, coin sdk.DecCoin, denom string) (sdk.DecCoin, error) {
40 | if coin.Denom == denom {
41 | return coin, nil
42 | }
43 |
44 | return sdk.DecCoin{}, fmt.Errorf("error resolving denom")
45 | }
46 |
47 | func (r *ErrorDenomResolver) ExtraDenoms(_ sdk.Context) ([]string, error) {
48 | return []string{}, nil
49 | }
50 |
--------------------------------------------------------------------------------
/x/gov/abci_internal_test.go:
--------------------------------------------------------------------------------
1 | package gov
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | func failingHandler(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) {
12 | panic("test-fail")
13 | }
14 |
15 | func okHandler(_ sdk.Context, _ sdk.Msg) (*sdk.Result, error) {
16 | return new(sdk.Result), nil
17 | }
18 |
19 | func TestSafeExecuteHandler(t *testing.T) {
20 | t.Parallel()
21 |
22 | require := require.New(t)
23 | var ctx sdk.Context
24 |
25 | r, err := safeExecuteHandler(ctx, nil, failingHandler)
26 | require.ErrorContains(err, "test-fail")
27 | require.Nil(r)
28 |
29 | r, err = safeExecuteHandler(ctx, nil, okHandler)
30 | require.Nil(err)
31 | require.NotNil(r)
32 | }
33 |
--------------------------------------------------------------------------------
/x/gov/autocli.go:
--------------------------------------------------------------------------------
1 | package gov
2 |
3 | import (
4 | autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
5 | govv1 "cosmossdk.io/api/cosmos/gov/v1"
6 | govv1beta1 "cosmossdk.io/api/cosmos/gov/v1beta1"
7 | )
8 |
9 | // AutoCLIOptions implements the autocli.HasAutoCLIConfig interface.
10 | func (am AppModule) AutoCLIOptions() *autocliv1.ModuleOptions {
11 | return &autocliv1.ModuleOptions{
12 | Tx: &autocliv1.ServiceCommandDescriptor{
13 | Service: govv1.Msg_ServiceDesc.ServiceName,
14 | // map v1beta1 as a sub-command
15 | SubCommands: map[string]*autocliv1.ServiceCommandDescriptor{
16 | "v1beta1": {Service: govv1beta1.Msg_ServiceDesc.ServiceName},
17 | },
18 | },
19 | Query: &autocliv1.ServiceCommandDescriptor{
20 | Service: govv1.Query_ServiceDesc.ServiceName,
21 | // map v1beta1 as a sub-command
22 | SubCommands: map[string]*autocliv1.ServiceCommandDescriptor{
23 | "v1beta1": {Service: govv1beta1.Query_ServiceDesc.ServiceName},
24 | },
25 | },
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/x/gov/client/proposal_handler.go:
--------------------------------------------------------------------------------
1 | package client
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // function to create the cli handler
8 | type CLIHandlerFn func() *cobra.Command
9 |
10 | // ProposalHandler wraps CLIHandlerFn
11 | type ProposalHandler struct {
12 | CLIHandler CLIHandlerFn
13 | }
14 |
15 | // NewProposalHandler creates a new ProposalHandler object
16 | func NewProposalHandler(cliHandler CLIHandlerFn) ProposalHandler {
17 | return ProposalHandler{
18 | CLIHandler: cliHandler,
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/x/gov/client/utils/unified_diff.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/hexops/gotextdiff"
7 | "github.com/hexops/gotextdiff/myers"
8 | "github.com/hexops/gotextdiff/span"
9 | )
10 |
11 | // GenerateUnifiedDiff generates a unified diff from src and dst strings using gotextdiff.
12 | // This is the only function that uses the gotextdiff library as its primary use is for
13 | // clients.
14 | func GenerateUnifiedDiff(src, dst string) (string, error) {
15 | // Create spans for the source and destination texts
16 | srcURI := span.URIFromPath("src")
17 |
18 | if src == "" || src[len(src)-1] != '\n' {
19 | src += "\n" // Add an EOL to src if it's empty or newline is missing
20 | }
21 | if dst == "" || dst[len(dst)-1] != '\n' {
22 | dst += "\n" // Add an EOL to dst if it's empty or newline is missing
23 | }
24 |
25 | // Compute the edits using the Myers diff algorithm
26 | eds := myers.ComputeEdits(srcURI, src, dst)
27 |
28 | // Generate the unified diff string
29 | diff := gotextdiff.ToUnified("src", "dst", src, eds)
30 |
31 | // Convert the diff to a string
32 | diffStr := fmt.Sprintf("%v", diff)
33 |
34 | return diffStr, nil
35 | }
36 |
--------------------------------------------------------------------------------
/x/gov/client/utils/unified_diff_test.go:
--------------------------------------------------------------------------------
1 | package utils_test
2 |
3 | import (
4 | "strings"
5 | "testing"
6 |
7 | "github.com/atomone-hub/atomone/x/gov/client/utils"
8 | "github.com/atomone-hub/atomone/x/gov/types"
9 | "github.com/stretchr/testify/require"
10 | )
11 |
12 | func TestGenerateUnifiedDiff(t *testing.T) {
13 | tests := []struct {
14 | name string
15 | src string
16 | dst string
17 | expected string
18 | }{
19 | {
20 | name: "No changes",
21 | src: "Line one\nLine two\nLine three",
22 | dst: "Line one\nLine two\nLine three",
23 | expected: ``,
24 | },
25 | {
26 | name: "Line added",
27 | src: "Line one\nLine two",
28 | dst: "Line one\nLine two\nLine three",
29 | expected: `@@ -1,2 +1,3 @@
30 | Line one
31 | Line two
32 | +Line three
33 | `,
34 | },
35 | {
36 | name: "Line deleted",
37 | src: "Line one\nLine two\nLine three",
38 | dst: "Line one\nLine three",
39 | expected: `@@ -1,3 +1,2 @@
40 | Line one
41 | -Line two
42 | Line three
43 | `,
44 | },
45 | {
46 | name: "Line modified",
47 | src: "Line one\nLine two\nLine three",
48 | dst: "Line one\nLine two modified\nLine three",
49 | expected: `@@ -1,3 +1,3 @@
50 | Line one
51 | -Line two
52 | +Line two modified
53 | Line three
54 | `,
55 | },
56 | {
57 | name: "Multiple changes",
58 | src: "Line one\nLine two\nLine three",
59 | dst: "Line zero\nLine one\nLine three\nLine four",
60 | expected: `@@ -1,3 +1,4 @@
61 | +Line zero
62 | Line one
63 | -Line two
64 | Line three
65 | +Line four
66 | `,
67 | },
68 | }
69 |
70 | for _, tt := range tests {
71 | t.Run(tt.name, func(t *testing.T) {
72 | diff, err := utils.GenerateUnifiedDiff(tt.src, tt.dst)
73 | require.NoError(t, err)
74 |
75 | diffContent := strings.TrimPrefix(diff, "--- src\n+++ dst\n")
76 | expectedContent := strings.TrimPrefix(tt.expected, "--- src\n+++ dst\n")
77 |
78 | require.Equal(t, expectedContent, diffContent)
79 | })
80 | }
81 | }
82 |
83 | func TestUnifiedDiffIntegration(t *testing.T) {
84 | src := "Line one\nLine two\nLine three"
85 | dst := "Line zero\nLine one\nLine three\nLine four"
86 |
87 | diffStr, err := utils.GenerateUnifiedDiff(src, dst)
88 | require.NoError(t, err)
89 |
90 | result, err := types.ApplyUnifiedDiff(src, diffStr)
91 | require.NoError(t, err)
92 | require.Equal(t, dst, result)
93 | }
94 |
--------------------------------------------------------------------------------
/x/gov/client/utils/utils.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/atomone-hub/atomone/x/gov/types/v1beta1"
7 | )
8 |
9 | // NormalizeVoteOption - normalize user specified vote option
10 | func NormalizeVoteOption(option string) string {
11 | switch option {
12 | case "Yes", "yes":
13 | return v1beta1.OptionYes.String()
14 |
15 | case "Abstain", "abstain":
16 | return v1beta1.OptionAbstain.String()
17 |
18 | case "No", "no":
19 | return v1beta1.OptionNo.String()
20 |
21 | default:
22 | return option
23 | }
24 | }
25 |
26 | // NormalizeWeightedVoteOptions - normalize vote options param string
27 | func NormalizeWeightedVoteOptions(options string) string {
28 | newOptions := []string{}
29 | for _, option := range strings.Split(options, ",") {
30 | fields := strings.Split(option, "=")
31 | fields[0] = NormalizeVoteOption(fields[0])
32 | if len(fields) < 2 {
33 | fields = append(fields, "1")
34 | }
35 | newOptions = append(newOptions, strings.Join(fields, "="))
36 | }
37 | return strings.Join(newOptions, ",")
38 | }
39 |
40 | // NormalizeProposalType - normalize user specified proposal type.
41 | func NormalizeProposalType(proposalType string) string {
42 | switch proposalType {
43 | case "Text", "text":
44 | return v1beta1.ProposalTypeText
45 |
46 | default:
47 | return ""
48 | }
49 | }
50 |
51 | // NormalizeProposalStatus - normalize user specified proposal status.
52 | func NormalizeProposalStatus(status string) string {
53 | switch status {
54 | case "DepositPeriod", "deposit_period":
55 | return v1beta1.StatusDepositPeriod.String()
56 | case "VotingPeriod", "voting_period":
57 | return v1beta1.StatusVotingPeriod.String()
58 | case "Passed", "passed":
59 | return v1beta1.StatusPassed.String()
60 | case "Rejected", "rejected":
61 | return v1beta1.StatusRejected.String()
62 | default:
63 | return status
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/x/gov/codec/cdc.go:
--------------------------------------------------------------------------------
1 | package codec
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | var (
10 | Amino = codec.NewLegacyAmino()
11 | ModuleCdc = codec.NewAminoCodec(Amino)
12 | )
13 |
14 | func init() {
15 | cryptocodec.RegisterCrypto(Amino)
16 | codec.RegisterEvidences(Amino)
17 | sdk.RegisterLegacyAminoCodec(Amino)
18 | }
19 |
--------------------------------------------------------------------------------
/x/gov/codec/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package codec provides a singleton instance of Amino codec that should be used to register
3 | any concrete type that can later be referenced inside a MsgSubmitProposal instance so that they
4 | can be (de)serialized properly.
5 |
6 | Amino types should be ideally registered inside this codec within the init function of each module's
7 | codec.go file as follows:
8 |
9 | func init() {
10 | // ...
11 |
12 | RegisterLegacyAminoCodec(govcodec.Amino)
13 | RegisterLegacyAminoCodec(groupcodec.Amino)
14 |
15 | }
16 |
17 | The codec instance is put inside this package and not the x/gov/types package in order to avoid any dependency cycle.
18 | */
19 | package codec
20 |
--------------------------------------------------------------------------------
/x/gov/exported/exported.go:
--------------------------------------------------------------------------------
1 | package exported
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
6 | )
7 |
8 | type (
9 | ParamSet = paramtypes.ParamSet
10 |
11 | // Subspace defines an interface that implements the legacy x/params Subspace
12 | // type.
13 | //
14 | // NOTE: This is used solely for migration of x/params managed parameters.
15 | ParamSubspace interface {
16 | Get(ctx sdk.Context, key []byte, ptr interface{})
17 | }
18 | )
19 |
--------------------------------------------------------------------------------
/x/gov/keeper/constitution.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | "github.com/atomone-hub/atomone/x/gov/types"
7 | )
8 |
9 | func (keeper Keeper) GetConstitution(ctx sdk.Context) (constitution string) {
10 | store := ctx.KVStore(keeper.storeKey)
11 | bz := store.Get(types.KeyConstitution)
12 |
13 | return string(bz)
14 | }
15 |
16 | func (keeper Keeper) SetConstitution(ctx sdk.Context, constitution string) {
17 | store := ctx.KVStore(keeper.storeKey)
18 | store.Set(types.KeyConstitution, []byte(constitution))
19 | }
20 |
21 | // ApplyConstitutionAmendment applies the amendment as a patch against the current constitution
22 | // and returns the updated constitution. If the amendment cannot be applied cleanly, an error is returned.
23 | func (k Keeper) ApplyConstitutionAmendment(ctx sdk.Context, amendment string) (updatedConstitution string, err error) {
24 | if amendment == "" {
25 | return "", types.ErrInvalidConstitutionAmendment.Wrap("amendment cannot be empty")
26 | }
27 |
28 | currentConstitution := k.GetConstitution(ctx)
29 | updatedConstitution, err = types.ApplyUnifiedDiff(currentConstitution, amendment)
30 | if err != nil {
31 | return "", types.ErrInvalidConstitutionAmendment.Wrapf("failed to apply amendment: %v", err)
32 | }
33 |
34 | return updatedConstitution, nil
35 | }
36 |
--------------------------------------------------------------------------------
/x/gov/keeper/constitution_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 | )
8 |
9 | func TestApplyConstitutionAmendment(t *testing.T) {
10 | govKeeper, _, _, ctx := setupGovKeeper(t)
11 |
12 | tests := []struct {
13 | name string
14 | initialConstitution string
15 | amendment string
16 | expectedResult string
17 | expectError bool
18 | }{
19 | {
20 | name: "failed patch application",
21 | initialConstitution: "Hello World",
22 | amendment: "Hi World",
23 | expectError: true,
24 | },
25 | {
26 | name: "successful patch application",
27 | initialConstitution: "Hello\nWorld",
28 | amendment: "@@ -1,2 +1,2 @@\n-Hello\n+Hi\n World",
29 | expectError: false,
30 | expectedResult: "Hi\nWorld",
31 | },
32 | {
33 | name: "successful patch application with multiple hunks",
34 | initialConstitution: "Line one\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine",
35 | amendment: "--- src\n+++ dst\n@@ -1,2 +1,2 @@\n-Line one\n+Line one modified\n Line two\n@@ -8,2 +8,2 @@\n Line eight\n-Line nine\n+Line nine modified",
36 | expectError: false,
37 | expectedResult: "Line one modified\nLine two\nLine three\nLine four\nLine five\nLine six\nLine seven\nLine eight\nLine nine modified",
38 | },
39 | }
40 |
41 | for _, tt := range tests {
42 | t.Run(tt.name, func(t *testing.T) {
43 | govKeeper.SetConstitution(ctx, tt.initialConstitution)
44 | updatedConstitution, err := govKeeper.ApplyConstitutionAmendment(ctx, tt.amendment)
45 | if tt.expectError {
46 | require.Error(t, err)
47 | } else {
48 | require.NoError(t, err)
49 | require.Equal(t, tt.expectedResult, updatedConstitution)
50 | }
51 | })
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/x/gov/keeper/export_test.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | // ValidateInitialDeposit is a helper function used only in deposit tests which returns the same
6 | // functionality of validateInitialDeposit private function.
7 | func (k Keeper) ValidateInitialDeposit(ctx sdk.Context, initialDeposit sdk.Coins) error {
8 | return k.validateInitialDeposit(ctx, initialDeposit)
9 | }
10 |
--------------------------------------------------------------------------------
/x/gov/keeper/internal_test.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import "github.com/atomone-hub/atomone/x/gov/types"
4 |
5 | // UnsafeSetHooks updates the gov keeper's hooks, overriding any potential
6 | // pre-existing hooks.
7 | // WARNING: this function should only be used in tests.
8 | func UnsafeSetHooks(k *Keeper, h types.GovHooks) {
9 | k.hooks = h
10 | }
11 |
--------------------------------------------------------------------------------
/x/gov/keeper/invariants.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | // DONTCOVER
4 |
5 | import (
6 | "fmt"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 |
10 | "github.com/atomone-hub/atomone/x/gov/types"
11 | v1 "github.com/atomone-hub/atomone/x/gov/types/v1"
12 | )
13 |
14 | // RegisterInvariants registers all governance invariants
15 | func RegisterInvariants(ir sdk.InvariantRegistry, keeper *Keeper, bk types.BankKeeper) {
16 | ir.RegisterRoute(types.ModuleName, "module-account", ModuleAccountInvariant(keeper, bk))
17 | }
18 |
19 | // AllInvariants runs all invariants of the governance module
20 | func AllInvariants(keeper *Keeper, bk types.BankKeeper) sdk.Invariant {
21 | return func(ctx sdk.Context) (string, bool) {
22 | return ModuleAccountInvariant(keeper, bk)(ctx)
23 | }
24 | }
25 |
26 | // ModuleAccountInvariant checks that the module account coins reflects the sum of
27 | // deposit amounts held on store.
28 | func ModuleAccountInvariant(keeper *Keeper, bk types.BankKeeper) sdk.Invariant {
29 | return func(ctx sdk.Context) (string, bool) {
30 | var expectedDeposits sdk.Coins
31 |
32 | keeper.IterateAllDeposits(ctx, func(deposit v1.Deposit) bool {
33 | expectedDeposits = expectedDeposits.Add(deposit.Amount...)
34 | return false
35 | })
36 |
37 | macc := keeper.GetGovernanceAccount(ctx)
38 | balances := bk.GetAllBalances(ctx, macc.GetAddress())
39 |
40 | // Require that the deposit balances are <= than the x/gov module's total
41 | // balances. We use the <= operator since external funds can be sent to x/gov
42 | // module's account and so the balance can be larger.
43 | broken := !balances.IsAllGTE(expectedDeposits)
44 |
45 | return sdk.FormatInvariant(types.ModuleName, "deposits",
46 | fmt.Sprintf("\tgov ModuleAccount coins: %s\n\tsum of deposit amounts: %s\n",
47 | balances, expectedDeposits)), broken
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/x/gov/keeper/migrations.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | "github.com/atomone-hub/atomone/x/gov/exported"
7 | v5 "github.com/atomone-hub/atomone/x/gov/migrations/v5"
8 | )
9 |
10 | // Migrator is a struct for handling in-place store migrations.
11 | type Migrator struct {
12 | keeper *Keeper
13 | legacySubspace exported.ParamSubspace
14 | }
15 |
16 | // NewMigrator returns a new Migrator.
17 | func NewMigrator(keeper *Keeper, legacySubspace exported.ParamSubspace) Migrator {
18 | return Migrator{
19 | keeper: keeper,
20 | legacySubspace: legacySubspace,
21 | }
22 | }
23 |
24 | // Migrate4to5 migrates the store from version 4 to 5.
25 | func (m Migrator) Migrate4to5(ctx sdk.Context) error {
26 | return v5.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
27 | }
28 |
--------------------------------------------------------------------------------
/x/gov/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | "github.com/atomone-hub/atomone/x/gov/types"
7 | v1 "github.com/atomone-hub/atomone/x/gov/types/v1"
8 | )
9 |
10 | // SetParams sets the gov module's parameters.
11 | func (k Keeper) SetParams(ctx sdk.Context, params v1.Params) error {
12 | store := ctx.KVStore(k.storeKey)
13 | bz, err := k.cdc.Marshal(¶ms)
14 | if err != nil {
15 | return err
16 | }
17 | store.Set(types.ParamsKey, bz)
18 |
19 | return nil
20 | }
21 |
22 | // GetParams gets the gov module's parameters.
23 | func (k Keeper) GetParams(clientCtx sdk.Context) (params v1.Params) {
24 | store := clientCtx.KVStore(k.storeKey)
25 | bz := store.Get(types.ParamsKey)
26 | if bz == nil {
27 | return params
28 | }
29 |
30 | k.cdc.MustUnmarshal(bz, ¶ms)
31 | return params
32 | }
33 |
--------------------------------------------------------------------------------
/x/gov/migrations/v3/keys.go:
--------------------------------------------------------------------------------
1 | package v3
2 |
3 | const (
4 | // ModuleName is the name of the module
5 | ModuleName = "gov"
6 | )
7 |
--------------------------------------------------------------------------------
/x/gov/migrations/v5/store.go:
--------------------------------------------------------------------------------
1 | package v5
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | govv1 "github.com/atomone-hub/atomone/x/gov/types/v1"
9 | )
10 |
11 | var ParamsKey = []byte{0x30}
12 |
13 | // Addition of the dynamic-deposit parameters.
14 | // Addition of the burnDepositNoThreshold parameter.
15 | func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec) error {
16 | store := ctx.KVStore(storeKey)
17 | paramsBz := store.Get(ParamsKey)
18 |
19 | var params govv1.Params
20 | cdc.MustUnmarshal(paramsBz, ¶ms)
21 |
22 | defaultParams := govv1.DefaultParams()
23 | params.MinDepositThrottler = defaultParams.MinDepositThrottler
24 | params.MinInitialDepositThrottler = defaultParams.MinInitialDepositThrottler
25 | params.BurnDepositNoThreshold = defaultParams.BurnDepositNoThreshold
26 |
27 | bz, err := cdc.Marshal(¶ms)
28 | if err != nil {
29 | return err
30 | }
31 | store.Set(ParamsKey, bz)
32 | return nil
33 | }
34 |
--------------------------------------------------------------------------------
/x/gov/migrations/v5/store_test.go:
--------------------------------------------------------------------------------
1 | package v5_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
9 | "github.com/cosmos/cosmos-sdk/testutil"
10 | moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
11 | "github.com/cosmos/cosmos-sdk/x/bank"
12 |
13 | "github.com/atomone-hub/atomone/x/gov"
14 | v5 "github.com/atomone-hub/atomone/x/gov/migrations/v5"
15 | govv1 "github.com/atomone-hub/atomone/x/gov/types/v1"
16 | )
17 |
18 | func TestMigrateStore(t *testing.T) {
19 | cdc := moduletestutil.MakeTestEncodingConfig(gov.AppModuleBasic{}, bank.AppModuleBasic{}).Codec
20 | govKey := storetypes.NewKVStoreKey("gov")
21 | ctx := testutil.DefaultContext(govKey, storetypes.NewTransientStoreKey("transient_test"))
22 | store := ctx.KVStore(govKey)
23 |
24 | var params govv1.Params
25 | bz := store.Get(v5.ParamsKey)
26 | require.NoError(t, cdc.Unmarshal(bz, ¶ms))
27 | require.NotNil(t, params)
28 | require.Nil(t, params.MinDepositThrottler)
29 | require.Nil(t, params.MinInitialDepositThrottler)
30 | require.Equal(t, "", params.BurnDepositNoThreshold)
31 |
32 | // Run migrations.
33 | err := v5.MigrateStore(ctx, govKey, cdc)
34 | require.NoError(t, err)
35 |
36 | // Check params
37 | bz = store.Get(v5.ParamsKey)
38 | require.NoError(t, cdc.Unmarshal(bz, ¶ms))
39 | require.NotNil(t, params)
40 | require.Equal(t, govv1.DefaultParams().MinDepositThrottler, params.MinDepositThrottler)
41 | require.Equal(t, govv1.DefaultParams().MinInitialDepositThrottler, params.MinInitialDepositThrottler)
42 | require.Equal(t, govv1.DefaultParams().BurnDepositNoThreshold, params.BurnDepositNoThreshold)
43 | }
44 |
--------------------------------------------------------------------------------
/x/gov/simulation/decoder.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "bytes"
5 | "encoding/binary"
6 | "fmt"
7 |
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | "github.com/cosmos/cosmos-sdk/types/kv"
10 |
11 | "github.com/atomone-hub/atomone/x/gov/types"
12 | "github.com/atomone-hub/atomone/x/gov/types/v1beta1"
13 | )
14 |
15 | // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
16 | // Value to the corresponding gov type.
17 | func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
18 | return func(kvA, kvB kv.Pair) string {
19 | switch {
20 | case bytes.Equal(kvA.Key[:1], types.ProposalsKeyPrefix):
21 | var proposalA v1beta1.Proposal
22 | err := cdc.Unmarshal(kvA.Value, &proposalA)
23 | if err != nil {
24 | panic(err)
25 | }
26 | var proposalB v1beta1.Proposal
27 | err = cdc.Unmarshal(kvB.Value, &proposalB)
28 | if err != nil {
29 | panic(err)
30 | }
31 | return fmt.Sprintf("%v\n%v", proposalA, proposalB)
32 |
33 | case bytes.Equal(kvA.Key[:1], types.ActiveProposalQueuePrefix),
34 | bytes.Equal(kvA.Key[:1], types.InactiveProposalQueuePrefix),
35 | bytes.Equal(kvA.Key[:1], types.ProposalIDKey):
36 | proposalIDA := binary.LittleEndian.Uint64(kvA.Value)
37 | proposalIDB := binary.LittleEndian.Uint64(kvB.Value)
38 | return fmt.Sprintf("proposalIDA: %d\nProposalIDB: %d", proposalIDA, proposalIDB)
39 |
40 | case bytes.Equal(kvA.Key[:1], types.DepositsKeyPrefix):
41 | var depositA, depositB v1beta1.Deposit
42 | cdc.MustUnmarshal(kvA.Value, &depositA)
43 | cdc.MustUnmarshal(kvB.Value, &depositB)
44 | return fmt.Sprintf("%v\n%v", depositA, depositB)
45 |
46 | case bytes.Equal(kvA.Key[:1], types.VotesKeyPrefix):
47 | var voteA, voteB v1beta1.Vote
48 | cdc.MustUnmarshal(kvA.Value, &voteA)
49 | cdc.MustUnmarshal(kvB.Value, &voteB)
50 | return fmt.Sprintf("%v\n%v", voteA, voteB)
51 |
52 | case bytes.Equal(kvA.Key[:1], types.VotingPeriodProposalKeyPrefix):
53 | return fmt.Sprintf("%v\n%v", kvA.Value, kvB.Value)
54 |
55 | default:
56 | panic(fmt.Sprintf("invalid governance key prefix %X", kvA.Key[:1]))
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/x/gov/testutil/configurator.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
3 | import (
4 | appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
5 | "cosmossdk.io/core/appconfig"
6 |
7 | "github.com/cosmos/cosmos-sdk/testutil/configurator"
8 |
9 | govmodulev1 "github.com/atomone-hub/atomone/api/atomone/gov/module/v1"
10 | )
11 |
12 | func GovModule() configurator.ModuleOption {
13 | return func(config *configurator.Config) {
14 | config.ModuleConfigs["gov"] = &appv1alpha1.ModuleConfig{
15 | Name: "gov",
16 | Config: appconfig.WrapAny(&govmodulev1.Module{}),
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/x/gov/testutil/expected_keepers.go:
--------------------------------------------------------------------------------
1 | // This file only used to generate mocks
2 |
3 | package testutil
4 |
5 | import (
6 | math "cosmossdk.io/math"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
10 | bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
11 |
12 | "github.com/atomone-hub/atomone/x/gov/types"
13 | )
14 |
15 | // AccountKeeper extends gov's actual expected AccountKeeper with additional
16 | // methods used in tests.
17 | type AccountKeeper interface {
18 | types.AccountKeeper
19 |
20 | IterateAccounts(ctx sdk.Context, cb func(account authtypes.AccountI) (stop bool))
21 | }
22 |
23 | // BankKeeper extends gov's actual expected BankKeeper with additional
24 | // methods used in tests.
25 | type BankKeeper interface {
26 | bankkeeper.Keeper
27 | }
28 |
29 | // StakingKeeper extends gov's actual expected StakingKeeper with additional
30 | // methods used in tests.
31 | type StakingKeeper interface {
32 | types.StakingKeeper
33 |
34 | BondDenom(ctx sdk.Context) string
35 | TokensFromConsensusPower(ctx sdk.Context, power int64) math.Int
36 | }
37 |
--------------------------------------------------------------------------------
/x/gov/types/config.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // Config is a config struct used for intialising the gov module to avoid using globals.
4 | type Config struct {
5 | // MaxMetadataLen defines the maximum proposal metadata length.
6 | MaxMetadataLen uint64
7 | }
8 |
9 | // DefaultConfig returns the default config for gov.
10 | func DefaultConfig() Config {
11 | return Config{
12 | MaxMetadataLen: 255,
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/x/gov/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // Governance module event types
4 | const (
5 | EventTypeSubmitProposal = "submit_proposal"
6 | EventTypeProposalDeposit = "proposal_deposit"
7 | EventTypeProposalVote = "proposal_vote"
8 | EventTypeInactiveProposal = "inactive_proposal"
9 | EventTypeActiveProposal = "active_proposal"
10 | EventTypeSignalProposal = "signal_proposal"
11 | EventTypeQuorumCheck = "quorum_check"
12 | EventTypeMinDepositChange = "min_deposit_change"
13 | EventTypeMinInitialDepositChange = "min_initial_deposit_change"
14 |
15 | AttributeKeyVoter = "voter"
16 | AttributeKeyProposalResult = "proposal_result"
17 | AttributeKeyOption = "option"
18 | AttributeKeyProposalID = "proposal_id"
19 | AttributeKeyProposalMessages = "proposal_messages" // Msg type_urls in the proposal
20 | AttributeKeyVotingPeriodStart = "voting_period_start"
21 | AttributeValueProposalDropped = "proposal_dropped" // didn't meet min deposit
22 | AttributeValueProposalPassed = "proposal_passed" // met vote quorum
23 | AttributeValueProposalRejected = "proposal_rejected" // didn't meet vote quorum
24 | AttributeValueProposalFailed = "proposal_failed" // error on proposal handler
25 | AttributeKeyProposalType = "proposal_type"
26 | AttributeSignalTitle = "signal_title"
27 | AttributeSignalDescription = "signal_description"
28 | AttributeValueProposalQuorumMet = "proposal_quorum_met" // met quorum
29 | AttributeValueProposalQuorumNotMet = "proposal_quorum_not_met" // didn't meet quorum
30 | AttributeValueProposalQuorumCheckSkipped = "proposal_quorum_check_skipped" // skipped quorum check
31 | AttributeKeyNewMinDeposit = "new_min_deposit" // new min deposit value
32 | AttributeKeyLastMinDeposit = "last_min_deposit" // last min deposit value
33 | AttributeKeyNewMinInitialDeposit = "new_min_initial_deposit" // new min initial deposit value
34 | AttributeKeyLastMinInitialDeposit = "last_min_initial_deposit" // last min initial deposit value
35 | )
36 |
--------------------------------------------------------------------------------
/x/gov/types/hooks.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | )
6 |
7 | var _ GovHooks = MultiGovHooks{}
8 |
9 | // combine multiple governance hooks, all hook functions are run in array sequence
10 | type MultiGovHooks []GovHooks
11 |
12 | func NewMultiGovHooks(hooks ...GovHooks) MultiGovHooks {
13 | return hooks
14 | }
15 |
16 | func (h MultiGovHooks) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) {
17 | for i := range h {
18 | h[i].AfterProposalSubmission(ctx, proposalID)
19 | }
20 | }
21 |
22 | func (h MultiGovHooks) AfterProposalDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) {
23 | for i := range h {
24 | h[i].AfterProposalDeposit(ctx, proposalID, depositorAddr)
25 | }
26 | }
27 |
28 | func (h MultiGovHooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
29 | for i := range h {
30 | h[i].AfterProposalVote(ctx, proposalID, voterAddr)
31 | }
32 | }
33 |
34 | func (h MultiGovHooks) AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) {
35 | for i := range h {
36 | h[i].AfterProposalFailedMinDeposit(ctx, proposalID)
37 | }
38 | }
39 |
40 | func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) {
41 | for i := range h {
42 | h[i].AfterProposalVotingPeriodEnded(ctx, proposalID)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/x/gov/types/keys_test.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/stretchr/testify/require"
8 |
9 | "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | )
12 |
13 | var addr = sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
14 |
15 | func TestProposalKeys(t *testing.T) {
16 | // key proposal
17 | key := ProposalKey(1)
18 | proposalID := SplitProposalKey(key)
19 | require.Equal(t, int(proposalID), 1)
20 |
21 | // key active proposal queue
22 | now := time.Now()
23 | key = ActiveProposalQueueKey(3, now)
24 | proposalID, expTime := SplitActiveProposalQueueKey(key)
25 | require.Equal(t, int(proposalID), 3)
26 | require.True(t, now.Equal(expTime))
27 |
28 | // key inactive proposal queue
29 | key = InactiveProposalQueueKey(3, now)
30 | proposalID, expTime = SplitInactiveProposalQueueKey(key)
31 | require.Equal(t, int(proposalID), 3)
32 | require.True(t, now.Equal(expTime))
33 |
34 | // invalid key
35 | require.Panics(t, func() { SplitProposalKey([]byte("test")) })
36 | require.Panics(t, func() { SplitInactiveProposalQueueKey([]byte("test")) })
37 | }
38 |
39 | func TestDepositKeys(t *testing.T) {
40 | key := DepositsKey(2)
41 | proposalID := SplitProposalKey(key)
42 | require.Equal(t, int(proposalID), 2)
43 |
44 | key = DepositKey(2, addr)
45 | proposalID, depositorAddr := SplitKeyDeposit(key)
46 | require.Equal(t, int(proposalID), 2)
47 | require.Equal(t, addr, depositorAddr)
48 | }
49 |
50 | func TestVoteKeys(t *testing.T) {
51 | key := VotesKey(2)
52 | proposalID := SplitProposalKey(key)
53 | require.Equal(t, int(proposalID), 2)
54 |
55 | key = VoteKey(2, addr)
56 | proposalID, voterAddr := SplitKeyDeposit(key)
57 | require.Equal(t, int(proposalID), 2)
58 | require.Equal(t, addr, voterAddr)
59 | }
60 |
--------------------------------------------------------------------------------
/x/gov/types/metadata.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // ProposalMetadata is the metadata of a proposal
4 | // This metadata is supposed to live off-chain when submitted in a proposal
5 | type ProposalMetadata struct {
6 | Title string `json:"title"`
7 | Authors []string `json:"authors"`
8 | Summary string `json:"summary"`
9 | Details string `json:"details"`
10 | ProposalForumUrl string `json:"proposal_forum_url"` //nolint:revive // named 'Url' instead of 'URL' for avoiding the camel case split
11 | VoteOptionContext string `json:"vote_option_context"`
12 | }
13 |
--------------------------------------------------------------------------------
/x/gov/types/v1/content.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/gogoproto/proto"
7 |
8 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
9 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
10 |
11 | "github.com/atomone-hub/atomone/x/gov/types/v1beta1"
12 | )
13 |
14 | // NewLegacyContent creates a new MsgExecLegacyContent from a legacy Content
15 | // interface.
16 | func NewLegacyContent(content v1beta1.Content, authority string) (*MsgExecLegacyContent, error) {
17 | msg, ok := content.(proto.Message)
18 | if !ok {
19 | return nil, fmt.Errorf("%T does not implement proto.Message", content)
20 | }
21 |
22 | any, err := codectypes.NewAnyWithValue(msg)
23 | if err != nil {
24 | return nil, err
25 | }
26 |
27 | return NewMsgExecLegacyContent(any, authority), nil
28 | }
29 |
30 | // LegacyContentFromMessage extracts the legacy Content interface from a
31 | // MsgExecLegacyContent.
32 | func LegacyContentFromMessage(msg *MsgExecLegacyContent) (v1beta1.Content, error) {
33 | content, ok := msg.Content.GetCachedValue().(v1beta1.Content)
34 | if !ok {
35 | return nil, sdkerrors.ErrInvalidType.Wrapf("expected %T, got %T", (*v1beta1.Content)(nil), msg.Content.GetCachedValue())
36 | }
37 |
38 | return content, nil
39 | }
40 |
--------------------------------------------------------------------------------
/x/gov/types/v1/deposit.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // NewDeposit creates a new Deposit instance
10 | //
11 | //nolint:interfacer
12 | func NewDeposit(proposalID uint64, depositor sdk.AccAddress, amount sdk.Coins) Deposit {
13 | return Deposit{proposalID, depositor.String(), amount}
14 | }
15 |
16 | // Deposits is a collection of Deposit objects
17 | type Deposits []*Deposit
18 |
19 | // Equal returns true if two slices (order-dependant) of deposits are equal.
20 | func (d Deposits) Equal(other Deposits) bool {
21 | if len(d) != len(other) {
22 | return false
23 | }
24 |
25 | for i, deposit := range d {
26 | if deposit.String() != other[i].String() {
27 | return false
28 | }
29 | }
30 |
31 | return true
32 | }
33 |
34 | // String implements stringer interface
35 | func (d Deposits) String() string {
36 | if len(d) == 0 {
37 | return "[]"
38 | }
39 | out := fmt.Sprintf("Deposits for Proposal %d:", d[0].ProposalId)
40 | for _, dep := range d {
41 | out += fmt.Sprintf("\n %s: %s", dep.Depositor, dep.Amount)
42 | }
43 | return out
44 | }
45 |
--------------------------------------------------------------------------------
/x/gov/types/v1/min_deposit.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import sdk "github.com/cosmos/cosmos-sdk/types"
4 |
5 | func GetNewMinDeposit(minDepositFloor, lastMinDeposit sdk.Coins, percChange sdk.Dec) sdk.Coins {
6 | newMinDeposit := sdk.Coins{}
7 | minDepositFloorDenomsSeen := make(map[string]bool)
8 | for _, lastMinDepositCoin := range lastMinDeposit {
9 | minDepositFloorCoinAmt := minDepositFloor.AmountOf(lastMinDepositCoin.Denom)
10 | if minDepositFloorCoinAmt.IsZero() {
11 | // minDepositFloor was changed since last update,
12 | // and this coin was removed.
13 | // reflect this also in the current min initial deposit,
14 | // i.e. remove this coin
15 | continue
16 | }
17 | minDepositFloorDenomsSeen[lastMinDepositCoin.Denom] = true
18 | minDepositCoinAmt := lastMinDepositCoin.Amount.ToLegacyDec().Mul(percChange).TruncateInt()
19 | if minDepositCoinAmt.LT(minDepositFloorCoinAmt) {
20 | newMinDeposit = append(newMinDeposit, sdk.NewCoin(lastMinDepositCoin.Denom, minDepositFloorCoinAmt))
21 | } else {
22 | newMinDeposit = append(newMinDeposit, sdk.NewCoin(lastMinDepositCoin.Denom, minDepositCoinAmt))
23 | }
24 | }
25 |
26 | // make sure any new denoms in minDepositFloor are added to minDeposit
27 | for _, minDepositFloorCoin := range minDepositFloor {
28 | if _, seen := minDepositFloorDenomsSeen[minDepositFloorCoin.Denom]; !seen {
29 | minDepositCoinAmt := minDepositFloorCoin.Amount.ToLegacyDec().Mul(percChange).TruncateInt()
30 | if minDepositCoinAmt.LT(minDepositFloorCoin.Amount) {
31 | newMinDeposit = append(newMinDeposit, minDepositFloorCoin)
32 | } else {
33 | newMinDeposit = append(newMinDeposit, sdk.NewCoin(minDepositFloorCoin.Denom, minDepositCoinAmt))
34 | }
35 | }
36 | }
37 |
38 | return newMinDeposit
39 | }
40 |
--------------------------------------------------------------------------------
/x/gov/types/v1/proposals_test.go:
--------------------------------------------------------------------------------
1 | package v1_test
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | "time"
7 |
8 | "github.com/stretchr/testify/require"
9 |
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 |
12 | v1 "github.com/atomone-hub/atomone/x/gov/types/v1"
13 | "github.com/atomone-hub/atomone/x/gov/types/v1beta1"
14 | )
15 |
16 | func TestProposalStatus_Format(t *testing.T) {
17 | statusDepositPeriod, _ := v1.ProposalStatusFromString("PROPOSAL_STATUS_DEPOSIT_PERIOD")
18 | tests := []struct {
19 | pt v1.ProposalStatus
20 | sprintFArgs string
21 | expectedStringOutput string
22 | }{
23 | {statusDepositPeriod, "%s", "PROPOSAL_STATUS_DEPOSIT_PERIOD"},
24 | {statusDepositPeriod, "%v", "1"},
25 | }
26 | for _, tt := range tests {
27 | got := fmt.Sprintf(tt.sprintFArgs, tt.pt)
28 | require.Equal(t, tt.expectedStringOutput, got)
29 | }
30 | }
31 |
32 | // TestNestedAnys tests that we can call .String() on a struct with nested Anys.
33 | // Here, we're creating a proposal which has a Msg (1st any) with a legacy
34 | // content (2nd any).
35 | func TestNestedAnys(t *testing.T) {
36 | // TODO https://github.com/cosmos/cosmos-sdk/issues/10965
37 | t.Skip()
38 | testProposal := v1beta1.NewTextProposal("Proposal", "testing proposal")
39 | msgContent, err := v1.NewLegacyContent(testProposal, "cosmos1govacct")
40 | require.NoError(t, err)
41 | proposal, err := v1.NewProposal([]sdk.Msg{msgContent}, 1, time.Now(), time.Now(), "", "title", "summary", sdk.AccAddress("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r"))
42 | require.NoError(t, err)
43 |
44 | require.Equal(t, "TODO Fix panic here", proposal.String())
45 | }
46 |
--------------------------------------------------------------------------------
/x/gov/types/v1/quorum_check.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | time "time"
5 | )
6 |
7 | func NewQuorumCheckQueueEntry(quorumTimeoutTime time.Time, quorumCheckCount uint64) QuorumCheckQueueEntry {
8 | return QuorumCheckQueueEntry{
9 | QuorumTimeoutTime: &quorumTimeoutTime,
10 | QuorumCheckCount: quorumCheckCount,
11 | QuorumChecksDone: 0,
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/x/gov/types/v1/tally.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "cosmossdk.io/math"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | // NewTallyResult creates a new TallyResult instance
10 | func NewTallyResult(yes, abstain, no math.Int) TallyResult {
11 | return TallyResult{
12 | YesCount: yes.String(),
13 | AbstainCount: abstain.String(),
14 | NoCount: no.String(),
15 | }
16 | }
17 |
18 | // NewTallyResultFromMap creates a new TallyResult instance from a Option -> Dec map
19 | func NewTallyResultFromMap(results map[VoteOption]sdk.Dec) TallyResult {
20 | return NewTallyResult(
21 | results[OptionYes].TruncateInt(),
22 | results[OptionAbstain].TruncateInt(),
23 | results[OptionNo].TruncateInt(),
24 | )
25 | }
26 |
27 | // EmptyTallyResult returns an empty TallyResult.
28 | func EmptyTallyResult() TallyResult {
29 | return NewTallyResult(math.ZeroInt(), math.ZeroInt(), math.ZeroInt())
30 | }
31 |
32 | // Equals returns if two tally results are equal.
33 | func (tr TallyResult) Equals(comp TallyResult) bool {
34 | return tr.YesCount == comp.YesCount &&
35 | tr.AbstainCount == comp.AbstainCount &&
36 | tr.NoCount == comp.NoCount
37 | }
38 |
--------------------------------------------------------------------------------
/x/gov/types/v1beta1/content.go:
--------------------------------------------------------------------------------
1 | package v1beta1
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | sdkgovtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
6 | )
7 |
8 | // Content defines an interface that a proposal must implement. It contains
9 | // information such as the title and description along with the type and routing
10 | // information for the appropriate handler to process the proposal. Content can
11 | // have additional fields, which will handled by a proposal's Handler.
12 | type Content interface {
13 | GetTitle() string
14 | GetDescription() string
15 | ProposalRoute() string
16 | ProposalType() string
17 | ValidateBasic() error
18 | String() string
19 | }
20 |
21 | // Handler defines a function that handles a proposal after it has passed the
22 | // governance process.
23 | type Handler func(ctx sdk.Context, content Content) error
24 |
25 | // WrapSDKHandler converts a Cosmos SDK gov Handler to GovGen gov Handler
26 | func WrapSDKHandler(sdkHandler sdkgovtypes.Handler) Handler {
27 | return func(ctx sdk.Context, content Content) error {
28 | return sdkHandler(ctx, content)
29 | }
30 | }
31 |
32 | type HandlerRoute struct {
33 | Handler Handler
34 | RouteKey string
35 | }
36 |
37 | // IsManyPerContainerType implements the depinject.ManyPerContainerType interface.
38 | func (HandlerRoute) IsManyPerContainerType() {}
39 |
--------------------------------------------------------------------------------
/x/gov/types/v1beta1/deposit.go:
--------------------------------------------------------------------------------
1 | package v1beta1
2 |
3 | import (
4 | "fmt"
5 |
6 | "sigs.k8s.io/yaml"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | // NewDeposit creates a new Deposit instance
12 | //
13 | //nolint:interfacer
14 | func NewDeposit(proposalID uint64, depositor sdk.AccAddress, amount sdk.Coins) Deposit {
15 | return Deposit{proposalID, depositor.String(), amount}
16 | }
17 |
18 | func (d Deposit) String() string {
19 | out, _ := yaml.Marshal(d)
20 | return string(out)
21 | }
22 |
23 | // Empty returns whether a deposit is empty.
24 | func (d Deposit) Empty() bool {
25 | return d.String() == Deposit{}.String()
26 | }
27 |
28 | // Deposits is a collection of Deposit objects
29 | type Deposits []Deposit
30 |
31 | // Equal returns true if two slices (order-dependant) of deposits are equal.
32 | func (d Deposits) Equal(other Deposits) bool {
33 | if len(d) != len(other) {
34 | return false
35 | }
36 |
37 | for i, deposit := range d {
38 | if deposit.String() != other[i].String() {
39 | return false
40 | }
41 | }
42 |
43 | return true
44 | }
45 |
46 | // String implements stringer interface
47 | func (d Deposits) String() string {
48 | if len(d) == 0 {
49 | return "[]"
50 | }
51 | out := fmt.Sprintf("Deposits for Proposal %d:", d[0].ProposalId)
52 | for _, dep := range d {
53 | out += fmt.Sprintf("\n %s: %s", dep.Depositor, dep.Amount)
54 | }
55 | return out
56 | }
57 |
--------------------------------------------------------------------------------
/x/gov/types/v1beta1/proposals_test.go:
--------------------------------------------------------------------------------
1 | package v1beta1_test
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 |
9 | "github.com/atomone-hub/atomone/x/gov/types/v1beta1"
10 | )
11 |
12 | func TestProposalStatus_Format(t *testing.T) {
13 | statusDepositPeriod, _ := v1beta1.ProposalStatusFromString("PROPOSAL_STATUS_DEPOSIT_PERIOD")
14 | tests := []struct {
15 | pt v1beta1.ProposalStatus
16 | sprintFArgs string
17 | expectedStringOutput string
18 | }{
19 | {statusDepositPeriod, "%s", "PROPOSAL_STATUS_DEPOSIT_PERIOD"},
20 | {statusDepositPeriod, "%v", "1"},
21 | }
22 | for _, tt := range tests {
23 | got := fmt.Sprintf(tt.sprintFArgs, tt.pt)
24 | require.Equal(t, tt.expectedStringOutput, got)
25 | }
26 | }
27 |
28 | func TestContentFromProposalType(t *testing.T) {
29 | tests := []struct {
30 | proposalType string
31 | expectedType string
32 | }{
33 | {
34 | proposalType: "TextProposal",
35 | expectedType: "",
36 | },
37 | {
38 | proposalType: "text",
39 | expectedType: v1beta1.ProposalTypeText,
40 | },
41 | {
42 | proposalType: "Text",
43 | expectedType: v1beta1.ProposalTypeText,
44 | },
45 | }
46 |
47 | for _, test := range tests {
48 | content, ok := v1beta1.ContentFromProposalType("title", "foo", test.proposalType)
49 | if test.expectedType == "" {
50 | require.False(t, ok)
51 | continue
52 | }
53 |
54 | require.True(t, ok)
55 | require.NotNil(t, content)
56 | require.Equal(t, test.expectedType, content.ProposalType())
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/x/gov/types/v1beta1/router.go:
--------------------------------------------------------------------------------
1 | package v1beta1
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | )
8 |
9 | var _ Router = (*router)(nil)
10 |
11 | // Router implements a governance Handler router.
12 | //
13 | // TODO: Use generic router (ref #3976).
14 | type Router interface {
15 | AddRoute(r string, h Handler) (rtr Router)
16 | HasRoute(r string) bool
17 | GetRoute(path string) (h Handler)
18 | Seal()
19 | }
20 |
21 | type router struct {
22 | routes map[string]Handler
23 | sealed bool
24 | }
25 |
26 | // NewRouter creates a new Router interface instance
27 | func NewRouter() Router {
28 | return &router{
29 | routes: make(map[string]Handler),
30 | }
31 | }
32 |
33 | // Seal seals the router which prohibits any subsequent route handlers to be
34 | // added. Seal will panic if called more than once.
35 | func (rtr *router) Seal() {
36 | if rtr.sealed {
37 | panic("router already sealed")
38 | }
39 | rtr.sealed = true
40 | }
41 |
42 | // AddRoute adds a governance handler for a given path. It returns the Router
43 | // so AddRoute calls can be linked. It will panic if the router is sealed.
44 | func (rtr *router) AddRoute(path string, h Handler) Router {
45 | if rtr.sealed {
46 | panic("router sealed; cannot add route handler")
47 | }
48 |
49 | if !sdk.IsAlphaNumeric(path) {
50 | panic("route expressions can only contain alphanumeric characters")
51 | }
52 | if rtr.HasRoute(path) {
53 | panic(fmt.Sprintf("route %s has already been initialized", path))
54 | }
55 |
56 | rtr.routes[path] = h
57 | return rtr
58 | }
59 |
60 | // HasRoute returns true if the router has a path registered or false otherwise.
61 | func (rtr *router) HasRoute(path string) bool {
62 | return rtr.routes[path] != nil
63 | }
64 |
65 | // GetRoute returns a Handler for a given path.
66 | func (rtr *router) GetRoute(path string) Handler {
67 | if !rtr.HasRoute(path) {
68 | panic(fmt.Sprintf("route \"%s\" does not exist", path))
69 | }
70 |
71 | return rtr.routes[path]
72 | }
73 |
--------------------------------------------------------------------------------
/x/gov/types/v1beta1/tally.go:
--------------------------------------------------------------------------------
1 | package v1beta1
2 |
3 | import (
4 | "sigs.k8s.io/yaml"
5 |
6 | "cosmossdk.io/math"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | // ValidatorGovInfo used for tallying
12 | type ValidatorGovInfo struct {
13 | Address sdk.ValAddress // address of the validator operator
14 | BondedTokens math.Int // Power of a Validator
15 | DelegatorShares math.LegacyDec // Total outstanding delegator shares
16 | DelegatorDeductions math.LegacyDec // Delegator deductions from validator's delegators voting independently
17 | Vote WeightedVoteOptions // Vote of the validator
18 | }
19 |
20 | // NewValidatorGovInfo creates a ValidatorGovInfo instance
21 | func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens math.Int, delegatorShares,
22 | delegatorDeductions sdk.Dec, options WeightedVoteOptions,
23 | ) ValidatorGovInfo {
24 | return ValidatorGovInfo{
25 | Address: address,
26 | BondedTokens: bondedTokens,
27 | DelegatorShares: delegatorShares,
28 | DelegatorDeductions: delegatorDeductions,
29 | Vote: options,
30 | }
31 | }
32 |
33 | // NewTallyResult creates a new TallyResult instance
34 | func NewTallyResult(yes, abstain, no, noWithVeto math.Int) TallyResult {
35 | return TallyResult{
36 | Yes: yes,
37 | Abstain: abstain,
38 | No: no,
39 | NoWithVeto: noWithVeto,
40 | }
41 | }
42 |
43 | // NewTallyResultFromMap creates a new TallyResult instance from a Option -> Dec map
44 | func NewTallyResultFromMap(results map[VoteOption]sdk.Dec) TallyResult {
45 | return NewTallyResult(
46 | results[OptionYes].TruncateInt(),
47 | results[OptionAbstain].TruncateInt(),
48 | results[OptionNo].TruncateInt(),
49 | results[OptionNoWithVeto].TruncateInt(),
50 | )
51 | }
52 |
53 | // EmptyTallyResult returns an empty TallyResult.
54 | func EmptyTallyResult() TallyResult {
55 | return NewTallyResult(math.ZeroInt(), math.ZeroInt(), math.ZeroInt(), math.ZeroInt())
56 | }
57 |
58 | // Equals returns if two proposals are equal.
59 | func (tr TallyResult) Equals(comp TallyResult) bool {
60 | return tr.Yes.Equal(comp.Yes) &&
61 | tr.Abstain.Equal(comp.Abstain) &&
62 | tr.No.Equal(comp.No) &&
63 | tr.NoWithVeto.Equal(comp.NoWithVeto)
64 | }
65 |
66 | // String implements stringer interface
67 | func (tr TallyResult) String() string {
68 | out, _ := yaml.Marshal(tr)
69 | return string(out)
70 | }
71 |
--------------------------------------------------------------------------------
/x/photon/ante/ante.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | errorsmod "cosmossdk.io/errors"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
8 |
9 | "github.com/atomone-hub/atomone/x/photon/types"
10 | )
11 |
12 | var _ sdk.AnteDecorator = ValidateFeeDecorator{}
13 |
14 | type ValidateFeeDecorator struct {
15 | k PhotonKeeper
16 | }
17 |
18 | func NewValidateFeeDecorator(k PhotonKeeper) ValidateFeeDecorator {
19 | return ValidateFeeDecorator{k: k}
20 | }
21 |
22 | // AnteHandle implements the sdk.AnteDecorator interface.
23 | // It returns an error if the tx fee denom is not photon, with some exceptions:
24 | // - tx has no fees or 0 fees.
25 | // - tx messages' type URLs match the `TxFeeExceptions` field of the
26 | // [types.Params].
27 | func (vfd ValidateFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
28 | feeTx, ok := tx.(sdk.FeeTx)
29 | if !ok {
30 | return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
31 | }
32 | feeCoins := feeTx.GetFee()
33 | if feeCoins.IsZero() {
34 | // Skip if no fees
35 | return next(ctx, tx, simulate)
36 | }
37 |
38 | if AllowsAnyTxFee(tx, vfd.k.GetParams(ctx).TxFeeExceptions) {
39 | // Skip if tx is declared in TxFeeExceptions (any fee coins are allowed).
40 | return next(ctx, tx, simulate)
41 | }
42 |
43 | if len(feeCoins) > 1 {
44 | return ctx, types.ErrTooManyFeeCoins
45 | }
46 | if feeDenom := feeCoins[0].Denom; feeDenom != types.Denom {
47 | // feeDenom not allowed
48 | return ctx, errorsmod.Wrapf(types.ErrInvalidFeeToken, "fee denom %s not allowed", feeDenom)
49 | }
50 | // feeDenom photon is allowed
51 | return next(ctx, tx, simulate)
52 | }
53 |
54 | // AllowsAnyTxFee returns true if all tx messages type URL are presents in
55 | // txFeeExceptions, or if it starts with a wildcard "*".
56 | func AllowsAnyTxFee(tx sdk.Tx, txFeeExceptions []string) bool {
57 | if len(txFeeExceptions) > 0 && txFeeExceptions[0] == "*" {
58 | // wildcard detected, all tx fees are allowed.
59 | return true
60 | }
61 | var anyTxFeeMsgCount int
62 | for _, msg := range tx.GetMsgs() {
63 | msgTypeURL := sdk.MsgTypeURL(msg)
64 | for _, exception := range txFeeExceptions {
65 | if exception == msgTypeURL {
66 | anyTxFeeMsgCount++
67 | break
68 | }
69 | }
70 | }
71 | return anyTxFeeMsgCount == len(tx.GetMsgs())
72 | }
73 |
--------------------------------------------------------------------------------
/x/photon/ante/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package ante
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | photontypes "github.com/atomone-hub/atomone/x/photon/types"
7 | )
8 |
9 | // PhotonKeeper defines the expected photon keeper.
10 | type PhotonKeeper interface {
11 | GetParams(ctx sdk.Context) photontypes.Params
12 | }
13 |
--------------------------------------------------------------------------------
/x/photon/ante/expected_keepers_mocks_test.go:
--------------------------------------------------------------------------------
1 | // Code generated by MockGen. DO NOT EDIT.
2 | // Source: x/photon/ante/expected_keepers.go
3 |
4 | // Package ante_test is a generated GoMock package.
5 | package ante_test
6 |
7 | import (
8 | reflect "reflect"
9 |
10 | types "github.com/atomone-hub/atomone/x/photon/types"
11 | types0 "github.com/cosmos/cosmos-sdk/types"
12 | gomock "github.com/golang/mock/gomock"
13 | )
14 |
15 | // MockPhotonKeeper is a mock of PhotonKeeper interface.
16 | type MockPhotonKeeper struct {
17 | ctrl *gomock.Controller
18 | recorder *MockPhotonKeeperMockRecorder
19 | }
20 |
21 | // MockPhotonKeeperMockRecorder is the mock recorder for MockPhotonKeeper.
22 | type MockPhotonKeeperMockRecorder struct {
23 | mock *MockPhotonKeeper
24 | }
25 |
26 | // NewMockPhotonKeeper creates a new mock instance.
27 | func NewMockPhotonKeeper(ctrl *gomock.Controller) *MockPhotonKeeper {
28 | mock := &MockPhotonKeeper{ctrl: ctrl}
29 | mock.recorder = &MockPhotonKeeperMockRecorder{mock}
30 | return mock
31 | }
32 |
33 | // EXPECT returns an object that allows the caller to indicate expected use.
34 | func (m *MockPhotonKeeper) EXPECT() *MockPhotonKeeperMockRecorder {
35 | return m.recorder
36 | }
37 |
38 | // GetParams mocks base method.
39 | func (m *MockPhotonKeeper) GetParams(ctx types0.Context) types.Params {
40 | m.ctrl.T.Helper()
41 | ret := m.ctrl.Call(m, "GetParams", ctx)
42 | ret0, _ := ret[0].(types.Params)
43 | return ret0
44 | }
45 |
46 | // GetParams indicates an expected call of GetParams.
47 | func (mr *MockPhotonKeeperMockRecorder) GetParams(ctx interface{}) *gomock.Call {
48 | mr.mock.ctrl.T.Helper()
49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParams", reflect.TypeOf((*MockPhotonKeeper)(nil).GetParams), ctx)
50 | }
51 |
--------------------------------------------------------------------------------
/x/photon/client/cli/query.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 |
11 | "github.com/atomone-hub/atomone/x/photon/types"
12 | )
13 |
14 | // GetQueryCmd returns the cli query commands for this module
15 | func GetQueryCmd(queryRoute string) *cobra.Command {
16 | // Group photon queries under a subcommand
17 | cmd := &cobra.Command{
18 | Use: types.ModuleName,
19 | Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
20 | DisableFlagParsing: true,
21 | SuggestionsMinimumDistance: 2,
22 | RunE: client.ValidateCmd,
23 | }
24 |
25 | cmd.AddCommand(
26 | GetQueryParamsCmd(),
27 | GetQueryConversionRateCmd(),
28 | )
29 | return cmd
30 | }
31 |
32 | func GetQueryParamsCmd() *cobra.Command {
33 | cmd := &cobra.Command{
34 | Use: "params",
35 | Short: "shows the parameters of the module",
36 | Args: cobra.NoArgs,
37 | RunE: func(cmd *cobra.Command, args []string) error {
38 | clientCtx, err := client.GetClientQueryContext(cmd)
39 | if err != nil {
40 | return err
41 | }
42 | queryClient := types.NewQueryClient(clientCtx)
43 | res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
44 | if err != nil {
45 | return err
46 | }
47 | return clientCtx.PrintProto(res)
48 | },
49 | }
50 | flags.AddQueryFlagsToCmd(cmd)
51 | return cmd
52 | }
53 |
54 | func GetQueryConversionRateCmd() *cobra.Command {
55 | cmd := &cobra.Command{
56 | Use: "conversion-rate",
57 | Short: "shows the atone to photon conversion rate",
58 | Args: cobra.NoArgs,
59 | RunE: func(cmd *cobra.Command, args []string) error {
60 | clientCtx, err := client.GetClientQueryContext(cmd)
61 | if err != nil {
62 | return err
63 | }
64 | queryClient := types.NewQueryClient(clientCtx)
65 | res, err := queryClient.ConversionRate(cmd.Context(), &types.QueryConversionRateRequest{})
66 | if err != nil {
67 | return err
68 | }
69 | return clientCtx.PrintProto(res)
70 | },
71 | }
72 | flags.AddQueryFlagsToCmd(cmd)
73 | return cmd
74 | }
75 |
--------------------------------------------------------------------------------
/x/photon/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/tx"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 |
13 | "github.com/atomone-hub/atomone/x/photon/types"
14 | )
15 |
16 | // GetTxCmd returns the transaction commands for this module
17 | func GetTxCmd() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: types.ModuleName,
20 | Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName),
21 | DisableFlagParsing: true,
22 | SuggestionsMinimumDistance: 2,
23 | RunE: client.ValidateCmd,
24 | }
25 | cmd.AddCommand(GetTxMintPhotonCmd())
26 | return cmd
27 | }
28 |
29 | func GetTxMintPhotonCmd() *cobra.Command {
30 | cmd := &cobra.Command{
31 | Use: "mint [amount]",
32 | Short: "Broadcast MintPhoton message which burns [amount] and mint photons.",
33 | Args: cobra.ExactArgs(1),
34 | RunE: func(cmd *cobra.Command, args []string) (err error) {
35 | clientCtx, err := client.GetClientTxContext(cmd)
36 | if err != nil {
37 | return err
38 | }
39 | toBurn, err := sdk.ParseCoinNormalized(args[0])
40 | if err != nil {
41 | return err
42 | }
43 | msg := types.NewMsgMintPhoton(
44 | clientCtx.GetFromAddress(),
45 | toBurn,
46 | )
47 | if err := msg.ValidateBasic(); err != nil {
48 | return err
49 | }
50 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
51 | },
52 | }
53 | flags.AddTxFlagsToCmd(cmd)
54 | return cmd
55 | }
56 |
--------------------------------------------------------------------------------
/x/photon/genesis.go:
--------------------------------------------------------------------------------
1 | package photon
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | "github.com/atomone-hub/atomone/x/photon/keeper"
9 | "github.com/atomone-hub/atomone/x/photon/types"
10 | )
11 |
12 | // InitGenesis initializes the module's state from a provided genesis state.
13 | func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
14 | if err := k.SetParams(ctx, genState.Params); err != nil {
15 | panic(fmt.Sprintf("%s module params has not been set", types.ModuleName))
16 | }
17 | }
18 |
19 | // ExportGenesis returns the module's exported genesis
20 | func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
21 | genesis := types.DefaultGenesis()
22 | genesis.Params = k.GetParams(ctx)
23 | return genesis
24 | }
25 |
--------------------------------------------------------------------------------
/x/photon/genesis_test.go:
--------------------------------------------------------------------------------
1 | package photon_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/require"
7 |
8 | "github.com/atomone-hub/atomone/x/photon"
9 | "github.com/atomone-hub/atomone/x/photon/testutil"
10 | "github.com/atomone-hub/atomone/x/photon/types"
11 | )
12 |
13 | func TestGenesis(t *testing.T) {
14 | genesisState := types.GenesisState{
15 | Params: types.DefaultParams(),
16 | }
17 | k, _, ctx := testutil.SetupPhotonKeeper(t)
18 |
19 | photon.InitGenesis(ctx, *k, genesisState)
20 | got := photon.ExportGenesis(ctx, *k)
21 |
22 | require.NotNil(t, got)
23 | require.Equal(t, genesisState, *got)
24 | }
25 |
--------------------------------------------------------------------------------
/x/photon/keeper/grpc_query.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "context"
5 |
6 | "google.golang.org/grpc/codes"
7 | "google.golang.org/grpc/status"
8 |
9 | sdk "github.com/cosmos/cosmos-sdk/types"
10 |
11 | "github.com/atomone-hub/atomone/x/photon/types"
12 | )
13 |
14 | var _ types.QueryServer = Keeper{}
15 |
16 | func (k Keeper) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
17 | if req == nil {
18 | return nil, status.Error(codes.InvalidArgument, "invalid request")
19 | }
20 | ctx := sdk.UnwrapSDKContext(goCtx)
21 |
22 | return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil
23 | }
24 |
25 | // ConversionRate returns the staking denom to photon conversion ratio.
26 | func (k Keeper) ConversionRate(goCtx context.Context, req *types.QueryConversionRateRequest) (*types.QueryConversionRateResponse, error) {
27 | var (
28 | ctx = sdk.UnwrapSDKContext(goCtx)
29 | bondDenom = k.stakingKeeper.BondDenom(ctx)
30 | stakingDenomSupply = k.bankKeeper.GetSupply(ctx, bondDenom).Amount.ToLegacyDec()
31 | uphotonSupply = k.bankKeeper.GetSupply(ctx, types.Denom).Amount.ToLegacyDec()
32 | cr = k.conversionRate(ctx, stakingDenomSupply, uphotonSupply)
33 | )
34 | return &types.QueryConversionRateResponse{ConversionRate: cr.String()}, nil
35 | }
36 |
--------------------------------------------------------------------------------
/x/photon/keeper/grpc_query_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "testing"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | appparams "github.com/atomone-hub/atomone/app/params"
9 | "github.com/atomone-hub/atomone/x/photon/testutil"
10 | "github.com/atomone-hub/atomone/x/photon/types"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | func TestParamsQuery(t *testing.T) {
15 | k, _, ctx := testutil.SetupPhotonKeeper(t)
16 | params := types.DefaultParams()
17 | k.SetParams(ctx, params)
18 |
19 | resp, err := k.Params(ctx, &types.QueryParamsRequest{})
20 |
21 | require.NoError(t, err)
22 | require.Equal(t, &types.QueryParamsResponse{Params: params}, resp)
23 | }
24 |
25 | func TestConversionRateQuery(t *testing.T) {
26 | tests := []struct {
27 | name string
28 | uatoneSupply int64
29 | uphotonSupply int64
30 | expectedResponse *types.QueryConversionRateResponse
31 | }{
32 | {
33 | name: "nominal case",
34 | uatoneSupply: 100_000_000_000_000, // 100,000,000atone
35 | uphotonSupply: 100_000_000_000, // 100,000photon
36 | expectedResponse: &types.QueryConversionRateResponse{
37 | ConversionRate: "9.999000000000000000",
38 | },
39 | },
40 | {
41 | name: "max supply of photon exceeded",
42 | uatoneSupply: 100_000_000_000_000, // 100,000,000atone
43 | uphotonSupply: types.MaxSupply + 1,
44 | expectedResponse: &types.QueryConversionRateResponse{
45 | ConversionRate: "0.000000000000000000",
46 | },
47 | },
48 | }
49 | for _, tt := range tests {
50 | t.Run(tt.name, func(t *testing.T) {
51 | k, m, ctx := testutil.SetupPhotonKeeper(t)
52 | m.StakingKeeper.EXPECT().BondDenom(ctx).Return(appparams.BondDenom)
53 | m.BankKeeper.EXPECT().GetSupply(ctx, appparams.BondDenom).
54 | Return(sdk.NewInt64Coin(appparams.BondDenom, tt.uatoneSupply))
55 | m.BankKeeper.EXPECT().GetSupply(ctx, types.Denom).
56 | Return(sdk.NewInt64Coin(appparams.BondDenom, tt.uphotonSupply))
57 |
58 | resp, err := k.ConversionRate(ctx, &types.QueryConversionRateRequest{})
59 |
60 | require.NoError(t, err)
61 | require.Equal(t, tt.expectedResponse, resp)
62 | })
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/x/photon/keeper/keeper.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cometbft/cometbft/libs/log"
7 |
8 | "github.com/cosmos/cosmos-sdk/codec"
9 | storetypes "github.com/cosmos/cosmos-sdk/store/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 |
12 | "github.com/atomone-hub/atomone/x/photon/types"
13 | )
14 |
15 | type Keeper struct {
16 | cdc codec.BinaryCodec
17 | storeKey storetypes.StoreKey
18 | authority string
19 |
20 | bankKeeper types.BankKeeper
21 | accountKeeper types.AccountKeeper
22 | stakingKeeper types.StakingKeeper
23 | }
24 |
25 | func NewKeeper(
26 | cdc codec.BinaryCodec,
27 | storeKey storetypes.StoreKey,
28 | authority string,
29 | bankKeeper types.BankKeeper,
30 | accountKeeper types.AccountKeeper,
31 | stakingKeeper types.StakingKeeper,
32 | ) *Keeper {
33 | return &Keeper{
34 | cdc: cdc,
35 | storeKey: storeKey,
36 | authority: authority,
37 | bankKeeper: bankKeeper,
38 | accountKeeper: accountKeeper,
39 | stakingKeeper: stakingKeeper,
40 | }
41 | }
42 |
43 | func (k Keeper) Logger(ctx sdk.Context) log.Logger {
44 | return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
45 | }
46 |
47 | // conversionRate returns the conversion rate for converting bond denom to
48 | // photon.
49 | func (k Keeper) conversionRate(_ sdk.Context, bondDenomSupply, uphotonSupply sdk.Dec) sdk.Dec {
50 | remainMintableUphotons := sdk.NewDec(types.MaxSupply).Sub(uphotonSupply)
51 | if remainMintableUphotons.IsNegative() {
52 | // If for any reason the max supply is exceeded, avoid returning a negative number
53 | return sdk.ZeroDec()
54 | }
55 | return remainMintableUphotons.Quo(bondDenomSupply)
56 | }
57 |
--------------------------------------------------------------------------------
/x/photon/keeper/params.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 |
6 | "github.com/atomone-hub/atomone/x/photon/types"
7 | )
8 |
9 | // GetParams get all parameters as types.Params
10 | func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
11 | store := ctx.KVStore(k.storeKey)
12 | bz := store.Get(types.ParamsKey)
13 | if bz == nil {
14 | return params
15 | }
16 | k.cdc.MustUnmarshal(bz, ¶ms)
17 | return params
18 | }
19 |
20 | // SetParams set the params
21 | func (k Keeper) SetParams(ctx sdk.Context, params types.Params) error {
22 | store := ctx.KVStore(k.storeKey)
23 | bz, err := k.cdc.Marshal(¶ms)
24 | if err != nil {
25 | return err
26 | }
27 | store.Set(types.ParamsKey, bz)
28 | return nil
29 | }
30 |
--------------------------------------------------------------------------------
/x/photon/keeper/params_test.go:
--------------------------------------------------------------------------------
1 | package keeper_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/atomone-hub/atomone/x/photon/testutil"
7 | "github.com/atomone-hub/atomone/x/photon/types"
8 | "github.com/stretchr/testify/require"
9 | )
10 |
11 | func TestGetParams(t *testing.T) {
12 | k, _, ctx := testutil.SetupPhotonKeeper(t)
13 | params := types.DefaultParams()
14 |
15 | k.SetParams(ctx, params)
16 | got := k.GetParams(ctx)
17 |
18 | require.EqualValues(t, params, got)
19 | }
20 |
--------------------------------------------------------------------------------
/x/photon/keeper/resolver.go:
--------------------------------------------------------------------------------
1 | package keeper
2 |
3 | import (
4 | "fmt"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 |
8 | "github.com/atomone-hub/atomone/x/photon/types"
9 | )
10 |
11 | // ConvertToDenom returns "coin.Amount denom" for all coins that are not the denom.
12 | func (k Keeper) ConvertToDenom(ctx sdk.Context, coin sdk.DecCoin, denom string) (sdk.DecCoin, error) {
13 | if coin.Denom == denom {
14 | return coin, nil
15 | }
16 |
17 | if denom == k.stakingKeeper.BondDenom(ctx) {
18 | // use the conversion rate to convert bond denom to photon
19 | bondDenomSupply := k.bankKeeper.GetSupply(ctx, denom).Amount.ToLegacyDec()
20 | uphotonSupply := k.bankKeeper.GetSupply(ctx, types.Denom).Amount.ToLegacyDec()
21 | conversionRate := k.conversionRate(ctx, bondDenomSupply, uphotonSupply)
22 |
23 | // convert bond denom to photon
24 | amount := coin.Amount.Quo(conversionRate)
25 | return sdk.NewDecCoinFromDec(denom, amount), nil
26 | }
27 |
28 | return sdk.DecCoin{}, fmt.Errorf("error resolving denom")
29 | }
30 |
31 | func (k Keeper) ExtraDenoms(ctx sdk.Context) ([]string, error) {
32 | return []string{
33 | k.stakingKeeper.BondDenom(ctx),
34 | }, nil
35 | }
36 |
--------------------------------------------------------------------------------
/x/photon/module_simulation.go:
--------------------------------------------------------------------------------
1 | package photon
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | "github.com/cosmos/cosmos-sdk/types/module"
6 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
7 |
8 | "github.com/atomone-hub/atomone/x/photon/simulation"
9 | "github.com/atomone-hub/atomone/x/photon/types"
10 | )
11 |
12 | // GenerateGenesisState creates a randomized GenState of the module.
13 | func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
14 | simulation.RandomizedGenState(simState)
15 | }
16 |
17 | // RegisterStoreDecoder registers a decoder.
18 | func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
19 | sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc)
20 | }
21 |
22 | func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
23 | return simulation.ProposalMsgs()
24 | }
25 |
26 | // WeightedOperations returns the all the module operations with their respective weights.
27 | func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
28 | return simulation.WeightedOperations(simState.AppParams, simState.Cdc,
29 | am.accountKeeper, am.bankKeeper, am.stakingKeeper, am.keeper)
30 | }
31 |
--------------------------------------------------------------------------------
/x/photon/simulation/decoder.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/cosmos/cosmos-sdk/codec"
7 | "github.com/cosmos/cosmos-sdk/types/kv"
8 | )
9 |
10 | // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
11 | // Value to the corresponding gov type.
12 | func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string {
13 | return func(kvA, kvB kv.Pair) string {
14 | panic(fmt.Sprintf("invalid photon key prefix %X", kvA.Key[:1]))
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/x/photon/simulation/genesis.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "math/rand"
5 |
6 | "github.com/cosmos/cosmos-sdk/types/module"
7 |
8 | "github.com/atomone-hub/atomone/x/photon/types"
9 | )
10 |
11 | const (
12 | MintDisabled = "mint_disabled"
13 | TxFeeExceptions = "tx_fee_exceptions"
14 | )
15 |
16 | // GenMintDisabled returns a randomized MintDisabled param.
17 | func GenMintDisabled(r *rand.Rand) bool {
18 | return r.Int63n(101) <= 15 // 15% chance of mint being disabled
19 | }
20 |
21 | // GenTxFeeExceptions returns a wildcard to allow all transactions to use any
22 | // fee denom.
23 | // This is needed because other modules' simulations do not allow the fee coins
24 | // to be changed, so w/o this configuration all transactions would fail.
25 | func GenTxFeeExceptions(r *rand.Rand) []string {
26 | return []string{"*"}
27 | }
28 |
29 | // RandomizedGenState generates a random GenesisState for gov
30 | func RandomizedGenState(simState *module.SimulationState) {
31 | var mintDisabled bool
32 | simState.AppParams.GetOrGenerate(
33 | simState.Cdc, MintDisabled, &mintDisabled, simState.Rand,
34 | func(r *rand.Rand) { mintDisabled = GenMintDisabled(r) },
35 | )
36 | var txFeeExceptions []string
37 | simState.AppParams.GetOrGenerate(
38 | simState.Cdc, TxFeeExceptions, &txFeeExceptions, simState.Rand,
39 | func(r *rand.Rand) { txFeeExceptions = GenTxFeeExceptions(r) },
40 | )
41 |
42 | photonGenesis := types.NewGenesisState(
43 | types.NewParams(mintDisabled, txFeeExceptions),
44 | )
45 |
46 | simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(photonGenesis)
47 | }
48 |
--------------------------------------------------------------------------------
/x/photon/simulation/proposals.go:
--------------------------------------------------------------------------------
1 | package simulation
2 |
3 | import (
4 | "math/rand"
5 |
6 | sdk "github.com/cosmos/cosmos-sdk/types"
7 | "github.com/cosmos/cosmos-sdk/types/address"
8 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
9 | "github.com/cosmos/cosmos-sdk/x/simulation"
10 |
11 | "github.com/atomone-hub/atomone/x/photon/types"
12 | )
13 |
14 | // Simulation operation weights constants
15 | const (
16 | DefaultWeightMsgUpdateParams int = 100
17 |
18 | OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec
19 | )
20 |
21 | // ProposalMsgs defines the module weighted proposals' contents
22 | func ProposalMsgs() []simtypes.WeightedProposalMsg {
23 | return []simtypes.WeightedProposalMsg{
24 | simulation.NewWeightedProposalMsg(
25 | OpWeightMsgUpdateParams,
26 | DefaultWeightMsgUpdateParams,
27 | SimulateMsgUpdateParams,
28 | ),
29 | }
30 | }
31 |
32 | // SimulateMsgUpdateParams returns a random MsgUpdateParams
33 | func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg {
34 | // use the default gov module account address as authority
35 | var authority sdk.AccAddress = address.Module("gov")
36 |
37 | params := types.DefaultParams()
38 | params.MintDisabled = r.Intn(2) == 0
39 | return &types.MsgUpdateParams{
40 | Authority: authority.String(),
41 | Params: params,
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/x/photon/testutil/keeper.go:
--------------------------------------------------------------------------------
1 | package testutil
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/golang/mock/gomock"
7 |
8 | tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
9 | tmtime "github.com/cometbft/cometbft/types/time"
10 |
11 | "github.com/cosmos/cosmos-sdk/testutil"
12 | sdk "github.com/cosmos/cosmos-sdk/types"
13 | moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
14 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
15 |
16 | govtypes "github.com/atomone-hub/atomone/x/gov/types"
17 | "github.com/atomone-hub/atomone/x/photon/keeper"
18 | "github.com/atomone-hub/atomone/x/photon/types"
19 | )
20 |
21 | type Mocks struct {
22 | AccountKeeper *MockAccountKeeper
23 | BankKeeper *MockBankKeeper
24 | StakingKeeper *MockStakingKeeper
25 | }
26 |
27 | func SetupMsgServer(t *testing.T) (types.MsgServer, *keeper.Keeper, Mocks, sdk.Context) {
28 | t.Helper()
29 | k, m, ctx := SetupPhotonKeeper(t)
30 | return keeper.NewMsgServerImpl(*k), k, m, ctx
31 | }
32 |
33 | func SetupPhotonKeeper(t *testing.T) (
34 | *keeper.Keeper,
35 | Mocks,
36 | sdk.Context,
37 | ) {
38 | t.Helper()
39 | ctrl := gomock.NewController(t)
40 | m := Mocks{
41 | AccountKeeper: NewMockAccountKeeper(ctrl),
42 | BankKeeper: NewMockBankKeeper(ctrl),
43 | StakingKeeper: NewMockStakingKeeper(ctrl),
44 | }
45 |
46 | key := sdk.NewKVStoreKey(types.StoreKey)
47 | testCtx := testutil.DefaultContextWithDB(t, key, sdk.NewTransientStoreKey("transient_test"))
48 | ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()})
49 | encCfg := moduletestutil.MakeTestEncodingConfig()
50 | types.RegisterInterfaces(encCfg.InterfaceRegistry)
51 | // banktypes.RegisterInterfaces(encCfg.InterfaceRegistry)
52 | authority := authtypes.NewModuleAddress(govtypes.ModuleName).String()
53 | return keeper.NewKeeper(encCfg.Codec, key, authority, m.BankKeeper, m.AccountKeeper, m.StakingKeeper), m, ctx
54 | }
55 |
--------------------------------------------------------------------------------
/x/photon/types/codec.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/codec"
5 | "github.com/cosmos/cosmos-sdk/codec/legacy"
6 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
7 | cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | "github.com/cosmos/cosmos-sdk/types/msgservice"
10 | )
11 |
12 | func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
13 | legacy.RegisterAminoMsg(cdc, &MsgMintPhoton{}, "atomone/photon/v1/MsgMintPhoton")
14 | legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "atomone/x/photon/v1/MsgUpdateParams")
15 | cdc.RegisterConcrete(&Params{}, "atomone/photon/v1/Params", nil)
16 | }
17 |
18 | func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
19 | registry.RegisterImplementations((*sdk.Msg)(nil),
20 | &MsgMintPhoton{}, &MsgUpdateParams{},
21 | )
22 | msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
23 | }
24 |
25 | var (
26 | amino = codec.NewLegacyAmino()
27 | ModuleCdc = codec.NewAminoCodec(amino)
28 | )
29 |
30 | func init() {
31 | RegisterLegacyAminoCodec(amino)
32 | cryptocodec.RegisterCrypto(amino)
33 | sdk.RegisterLegacyAminoCodec(amino)
34 | }
35 |
--------------------------------------------------------------------------------
/x/photon/types/const.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 |
5 | // Denom name
6 | Denom = "uphoton"
7 |
8 | // Photon max supply is 1B
9 | MaxSupply int64 = 1_000_000_000 * 1_000_000
10 | )
11 |
--------------------------------------------------------------------------------
/x/photon/types/errors.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | errorsmod "cosmossdk.io/errors"
5 | )
6 |
7 | // x/photon module sentinel errors
8 | var (
9 | ErrMintDisabled = errorsmod.Register(ModuleName, 1, "photon mint disabled")
10 | ErrBurnInvalidDenom = errorsmod.Register(ModuleName, 2, "invalid burned amount denom: expected bond denom")
11 | ErrZeroMintPhotons = errorsmod.Register(ModuleName, 3, "no mintable photon after rounding, try higher burn")
12 | ErrTooManyFeeCoins = errorsmod.Register(ModuleName, 5, "too many fee coins, only accepts fees in one denom")
13 | ErrInvalidFeeToken = errorsmod.Register(ModuleName, 6, "invalid fee token")
14 | )
15 |
--------------------------------------------------------------------------------
/x/photon/types/events.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // Photon module event types
4 | const (
5 | EventTypeMintPhoton = "mint_photon"
6 |
7 | AttributeKeyBurned = "burned"
8 | AttributeKeyMinted = "minted"
9 | )
10 |
--------------------------------------------------------------------------------
/x/photon/types/expected_keepers.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import (
4 | sdk "github.com/cosmos/cosmos-sdk/types"
5 | "github.com/cosmos/cosmos-sdk/x/auth/types"
6 | )
7 |
8 | // AccountKeeper defines the expected account keeper used for simulations (noalias)
9 | type AccountKeeper interface {
10 | GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
11 | }
12 |
13 | // StakingKeeper defines the expected staking keeper.
14 | type StakingKeeper interface {
15 | BondDenom(sdk.Context) string
16 | }
17 |
18 | // BankKeeper defines the expected interface needed to retrieve account balances.
19 | type BankKeeper interface {
20 | SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
21 | MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
22 | BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
23 | SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
24 | SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
25 | GetSupply(ctx sdk.Context, denom string) sdk.Coin
26 | }
27 |
--------------------------------------------------------------------------------
/x/photon/types/genesis.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // NewGenesisState creates a new genesis state for the governance module
4 | func NewGenesisState(params Params) *GenesisState {
5 | return &GenesisState{
6 | Params: params,
7 | }
8 | }
9 |
10 | // DefaultGenesis returns the default genesis state
11 | func DefaultGenesis() *GenesisState {
12 | return NewGenesisState(DefaultParams())
13 | }
14 |
15 | // Validate performs basic genesis state validation returning an error upon any
16 | // failure.
17 | func (gs GenesisState) Validate() error {
18 | return gs.Params.ValidateBasic()
19 | }
20 |
--------------------------------------------------------------------------------
/x/photon/types/genesis_test.go:
--------------------------------------------------------------------------------
1 | package types_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/atomone-hub/atomone/x/photon/types"
7 | "github.com/stretchr/testify/require"
8 | )
9 |
10 | func TestGenesisState_Validate(t *testing.T) {
11 | tests := []struct {
12 | desc string
13 | genState *types.GenesisState
14 | valid bool
15 | }{
16 | {
17 | desc: "default is valid",
18 | genState: types.DefaultGenesis(),
19 | valid: true,
20 | },
21 | {
22 | desc: "valid genesis state",
23 | genState: &types.GenesisState{},
24 | valid: true,
25 | },
26 | }
27 | for _, tc := range tests {
28 | t.Run(tc.desc, func(t *testing.T) {
29 | err := tc.genState.Validate()
30 | if tc.valid {
31 | require.NoError(t, err)
32 | } else {
33 | require.Error(t, err)
34 | }
35 | })
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/x/photon/types/keys.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | const (
4 | // ModuleName defines the module name
5 | ModuleName = "photon"
6 |
7 | // StoreKey defines the primary module store key
8 | StoreKey = ModuleName
9 |
10 | // RouterKey defines the module's message routing key
11 | RouterKey = ModuleName
12 | )
13 |
14 | var ParamsKey = []byte{0x00}
15 |
--------------------------------------------------------------------------------
/x/photon/types/params.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | // NewParams creates a new Params instance
4 | func NewParams(mintDisabled bool, txFeeExceptions []string) Params {
5 | return Params{
6 | MintDisabled: mintDisabled,
7 | TxFeeExceptions: txFeeExceptions,
8 | }
9 | }
10 |
11 | const (
12 | defaultMintDisabled = false
13 | )
14 |
15 | // NOTE(tb): Not possible to use `sdk.MsgTypeURL(types.MsgMintPhoton{})`
16 | // instead of plain text because at this step the msg is not registered yet.
17 | var defaultTxFeeExceptions = []string{"/atomone.photon.v1.MsgMintPhoton"}
18 |
19 | // DefaultParams returns a default set of parameters
20 | func DefaultParams() Params {
21 | return NewParams(defaultMintDisabled, defaultTxFeeExceptions)
22 | }
23 |
24 | // Validate validates the set of params
25 | func (p Params) ValidateBasic() error {
26 | return nil
27 | }
28 |
--------------------------------------------------------------------------------
/x/photon/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
--------------------------------------------------------------------------------