├── buf.work.yaml
├── interchaintest
├── test-artifacts
│ ├── cw721_base.wasm
│ ├── ics721_base.wasm
│ └── cw_ics721_incoming_proxy_base.wasm
├── utils
│ ├── setup.go
│ ├── t.go
│ ├── interchainvalues.go
│ └── helpers.go
├── local-interchain
│ └── localinterslothchain.go
├── ics721
│ └── ics721_test.go
├── ics20
│ └── ics20_test.go
└── go.mod
├── .gitignore
├── testutil
├── sample
│ └── sample.go
├── nullify
│ └── nullify.go
└── network
│ └── network.go
├── .github
└── workflows
│ ├── build.yaml
│ ├── lint.yml
│ └── interslothtest.yaml
├── cmd
└── lazychaind
│ ├── cmd
│ ├── lazycommandutils
│ │ ├── flags.go
│ │ ├── networks.go
│ │ ├── ics20.go
│ │ ├── ics721.go
│ │ └── helper.go
│ ├── lazylogger.go
│ ├── tia
│ │ ├── query.go
│ │ └── tx.go
│ ├── config.go
│ ├── sloths
│ │ ├── query.go
│ │ └── tx.go
│ ├── root.go
│ └── commands.go
│ └── main.go
├── proto
├── buf.gen.swagger.yaml
├── buf.gen.sta.yaml
├── buf.gen.ts.yaml
├── buf.gen.gogo.yaml
├── buf.gen.pulsar.yaml
├── buf.yaml
└── buf.lock
├── config.yml
├── scripts
├── build-ics721-proxy.sh
└── build-cw.sh
├── app
├── genesis.go
├── upgrades
│ ├── types.go
│ └── v1.1
│ │ └── upgrade.go
├── upgrades.go
├── genesis_account.go
├── tokenfactory.go
├── ante.go
├── sim_bench_test.go
├── wasm.go
├── ibc.go
├── export.go
├── app_config.go
└── sim_test.go
├── tools
└── tools.go
├── docs
├── docs.go
└── template
│ └── index.tpl
├── Dockerfile
├── .golangci.yml
├── init.sh
├── README.md
└── Makefile
/buf.work.yaml:
--------------------------------------------------------------------------------
1 | version: v1
2 | directories:
3 | - proto
4 |
--------------------------------------------------------------------------------
/interchaintest/test-artifacts/cw721_base.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lazychain/lazychain/HEAD/interchaintest/test-artifacts/cw721_base.wasm
--------------------------------------------------------------------------------
/interchaintest/test-artifacts/ics721_base.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lazychain/lazychain/HEAD/interchaintest/test-artifacts/ics721_base.wasm
--------------------------------------------------------------------------------
/interchaintest/test-artifacts/cw_ics721_incoming_proxy_base.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lazychain/lazychain/HEAD/interchaintest/test-artifacts/cw_ics721_incoming_proxy_base.wasm
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vue/node_modules
2 | vue/dist
3 | release/
4 | .idea/
5 | .vscode/
6 | .DS_Store
7 | *.dot
8 | *.log
9 | *.ign
10 |
11 | cw-ics721/
12 | cw-ics721-proxy/
13 | cw-nfts/
14 | astral/
15 |
16 | artifacts/
17 | build/
18 | restart-lazychaind.sh
--------------------------------------------------------------------------------
/testutil/sample/sample.go:
--------------------------------------------------------------------------------
1 | package sample
2 |
3 | import (
4 | "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 | )
7 |
8 | // AccAddress returns a sample account address
9 | func AccAddress() string {
10 | pk := ed25519.GenPrivKey().PubKey()
11 | addr := pk.Address()
12 | return sdk.AccAddress(addr).String()
13 | }
14 |
--------------------------------------------------------------------------------
/.github/workflows/build.yaml:
--------------------------------------------------------------------------------
1 | name: "Build LazyChain 💤"
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | push:
7 | branches:
8 | - main
9 |
10 | env:
11 | GOFLAGS: '-buildvcs=false'
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Build LazyChain
20 | run: make build
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazycommandutils/flags.go:
--------------------------------------------------------------------------------
1 | package lazycommandutils
2 |
3 | const (
4 | FlagWaitForTx = "wait-for-tx"
5 | FlagMainnet = "mainnet"
6 | FlagTestnet = "testnet"
7 |
8 | FlagNFTContract = "nft-contract"
9 | FlagICS721Contract = "ics721-contract"
10 | FlagICS721Channel = "ics721-channel"
11 |
12 | FlagICS20Denom = "ics20-denom"
13 | FlagICS20Channel = "ics20-channel"
14 | )
15 |
--------------------------------------------------------------------------------
/proto/buf.gen.swagger.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.gen.swagger.yaml
5 | #
6 | version: v1
7 | plugins:
8 | - name: openapiv2
9 | out: .
10 | opt:
11 | - logtostderr=true
12 | - openapi_naming_strategy=fqn
13 | - json_names_for_fields=false
14 | - generate_unbound_methods=true
--------------------------------------------------------------------------------
/proto/buf.gen.sta.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.gen.sta.yaml
5 | #
6 | version: v1
7 | plugins:
8 | - name: openapiv2
9 | out: .
10 | opt:
11 | - logtostderr=true
12 | - openapi_naming_strategy=simple
13 | - ignore_comments=true
14 | - simple_operation_ids=false
15 | - json_names_for_fields=false
16 |
--------------------------------------------------------------------------------
/config.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | validation: sovereign
3 | accounts:
4 | - name: alice
5 | coins:
6 | - 20000token
7 | - 200000000stake
8 | - name: bob
9 | coins:
10 | - 10000token
11 | - 100000000stake
12 | client:
13 | openapi:
14 | path: docs/static/openapi.yml
15 | faucet:
16 | name: bob
17 | coins:
18 | - 5token
19 | - 100000stake
20 | validators:
21 | - name: alice
22 | bonded: 100000000stake
23 | build:
24 | main: ./cmd/lazychaind
--------------------------------------------------------------------------------
/scripts/build-ics721-proxy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o errexit -o nounset -o pipefail
4 |
5 | echo "Get the repo for ICS721 proxy contracts"
6 |
7 | if [ ! -d "cw-ics721-proxy" ]; then
8 | git clone https://github.com/gjermundgaraba/cw-ics721-proxy.git
9 | fi
10 |
11 | cd cw-ics721-proxy
12 | git checkout gjermund/incoming-proxy-whitelist
13 | ./build.sh
14 | cp ./artifacts/cw_ics721_incoming_proxy_base.wasm ../interchaintest/test-artifacts/cw_ics721_incoming_proxy_base.wasm
--------------------------------------------------------------------------------
/proto/buf.gen.ts.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.gen.ts.yaml
5 | #
6 | version: v1
7 | managed:
8 | enabled: true
9 | plugins:
10 | - plugin: buf.build/community/stephenh-ts-proto
11 | out: .
12 | opt:
13 | - logtostderr=true
14 | - allow_merge=true
15 | - json_names_for_fields=false
16 | - ts_proto_opt=snakeToCamel=true
17 | - ts_proto_opt=esModuleInterop=true
18 | - ts_proto_out=.
19 |
--------------------------------------------------------------------------------
/proto/buf.gen.gogo.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.gen.gogo.yaml
5 | #
6 | version: v1
7 | plugins:
8 | - name: gocosmos
9 | out: .
10 | opt:
11 | - plugins=grpc
12 | - Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types
13 | - Mcosmos/orm/v1/orm.proto=cosmossdk.io/orm
14 | - name: grpc-gateway
15 | out: .
16 | opt:
17 | - logtostderr=true
18 | - allow_colon_final_segments=true
19 |
--------------------------------------------------------------------------------
/app/genesis.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | )
6 |
7 | // GenesisState of the blockchain is represented here as a map of raw json
8 | // messages key'd by a identifier string.
9 | // The identifier is used to determine which module genesis information belongs
10 | // to so it may be appropriately routed during init chain.
11 | // Within this application default genesis information is retrieved from
12 | // the ModuleBasicManager which populates json from each BasicModule
13 | // object provided to it during init.
14 | type GenesisState map[string]json.RawMessage
15 |
--------------------------------------------------------------------------------
/proto/buf.gen.pulsar.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.gen.pulsar.yaml
5 | #
6 | version: v1
7 | managed:
8 | enabled: true
9 | go_package_prefix:
10 | default: cosmossdk.io/api
11 | except:
12 | - buf.build/googleapis/googleapis
13 | - buf.build/cosmos/gogo-proto
14 | - buf.build/cosmos/cosmos-proto
15 | override:
16 | plugins:
17 | - name: go-pulsar
18 | out: ./api
19 | opt: paths=source_relative
20 | - name: go-grpc
21 | out: ./api
22 | opt: paths=source_relative
23 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazycommandutils/networks.go:
--------------------------------------------------------------------------------
1 | package lazycommandutils
2 |
3 | const (
4 | testnetLazyChainChainID = "lazynet-1"
5 | testnetLazyChainNode = "tcp://51.159.101.58:26657"
6 | testnetLazyChainGasPrices = "0.025ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA"
7 |
8 | testnetStargazeChainID = "elgafar-1"
9 | testnetStargazeNode = "https://rpc.elgafar-1.stargaze-apis.com:443"
10 | testnetStargazeGasPrices = "0.025ustars"
11 |
12 | testnetCelestiaChainID = "mocha-4"
13 | testnetCelestiaNode = "https://celestia-testnet-rpc.publicnode.com:443"
14 | testnetCelestiaGasPrices = "0.1utia"
15 | )
16 |
--------------------------------------------------------------------------------
/tools/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 |
3 | package tools
4 |
5 | import (
6 | _ "github.com/bufbuild/buf/cmd/buf"
7 | _ "github.com/cosmos/cosmos-proto/cmd/protoc-gen-go-pulsar"
8 | _ "github.com/cosmos/gogoproto/protoc-gen-gocosmos"
9 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint"
10 | _ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway"
11 | _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
12 | _ "golang.org/x/tools/cmd/goimports"
13 | _ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
14 | _ "google.golang.org/protobuf/cmd/protoc-gen-go"
15 | _ "github.com/golangci/golangci-lint/cmd/golangci-lint"
16 | )
17 |
--------------------------------------------------------------------------------
/proto/buf.yaml:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite. You can edit
2 | # the file content but do not change the file name or path.
3 | #
4 | # buf.yaml
5 | #
6 | version: v1
7 | deps:
8 | - buf.build/protocolbuffers/wellknowntypes
9 | - buf.build/cosmos/cosmos-sdk
10 | - buf.build/cosmos/cosmos-proto
11 | - buf.build/cosmos/gogo-proto
12 | - buf.build/googleapis/googleapis
13 | - buf.build/cosmos/ics23
14 | breaking:
15 | use:
16 | - FILE
17 | lint:
18 | use:
19 | - DEFAULT
20 | - COMMENTS
21 | - FILE_LOWER_SNAKE_CASE
22 | except:
23 | - UNARY_RPC
24 | - COMMENT_FIELD
25 | - SERVICE_SUFFIX
26 | - PACKAGE_VERSION_SUFFIX
27 | - RPC_REQUEST_STANDARD_NAME
28 | ignore:
29 | - tendermint
30 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: golangci-lint
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request:
7 | permissions:
8 | contents: read
9 | # Optional: allow read access to pull request. Use with `only-new-issues` option.
10 | pull-requests: read
11 |
12 | jobs:
13 | golangci:
14 | name: lint
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/setup-go@v5
18 | with:
19 | go-version: '1.22'
20 | - uses: actions/checkout@v4
21 | with:
22 | fetch-depth: 0
23 | - name: golangci-lint
24 | uses: golangci/golangci-lint-action@v6.0.1
25 | with:
26 | version: v1.57.2
27 | only-new-issues: true
28 | args: --timeout 10m
29 |
--------------------------------------------------------------------------------
/scripts/build-cw.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # There are some tool requirements here like "just", "cargo make"
4 |
5 | set -o errexit -o nounset -o pipefail
6 |
7 | echo "Get the repos for the contracts we need"
8 |
9 | if [ ! -d "cw-ics721" ]; then
10 | git clone https://github.com/public-awesome/cw-ics721.git
11 | fi
12 |
13 | if [ ! -d "cw-nfts" ]; then
14 | git clone https://github.com/CosmWasm/cw-nfts.git
15 | fi
16 |
17 | # TODO: Fix so the architecture is not hardcoded
18 | cd cw-ics721
19 | git checkout v0.1.9
20 | just optimize
21 | cp artifacts/ics721_base-aarch64.wasm ../interchaintest/test-artifacts/ics721_base.wasm
22 | cd ..
23 |
24 | cd cw-nfts
25 | cargo make optimize
26 | cp artifacts/cw721_base-aarch64.wasm ../interchaintest/test-artifacts/cw721_base.wasm
--------------------------------------------------------------------------------
/proto/buf.lock:
--------------------------------------------------------------------------------
1 | # This file is auto-generated from Ignite.
2 | # DO NOT EDIT
3 | #
4 | # buf.lock
5 | #
6 | version: v1
7 | deps:
8 | - remote: buf.build
9 | owner: cosmos
10 | repository: cosmos-proto
11 | commit: 1935555c206d4afb9e94615dfd0fad31
12 | - remote: buf.build
13 | owner: cosmos
14 | repository: cosmos-sdk
15 | commit: 954f7b05f38440fc8250134b15adec47
16 | - remote: buf.build
17 | owner: cosmos
18 | repository: gogo-proto
19 | commit: 34d970b699f84aa382f3c29773a60836
20 | - remote: buf.build
21 | owner: cosmos
22 | repository: ics23
23 | commit: 3c44d8daa8b44059ac744cd17d4a49d7
24 | - remote: buf.build
25 | owner: googleapis
26 | repository: googleapis
27 | commit: 75b4300737fb4efca0831636be94e517
28 | - remote: buf.build
29 | owner: protocolbuffers
30 | repository: wellknowntypes
31 | commit: 44e83bc050a4497fa7b36b34d95ca156
32 |
--------------------------------------------------------------------------------
/docs/docs.go:
--------------------------------------------------------------------------------
1 | package docs
2 |
3 | import (
4 | "embed"
5 | httptemplate "html/template"
6 | "net/http"
7 |
8 | "github.com/gorilla/mux"
9 | )
10 |
11 | const (
12 | apiFile = "/static/openapi.yml"
13 | indexFile = "template/index.tpl"
14 | )
15 |
16 | //go:embed static
17 | var Static embed.FS
18 |
19 | //go:embed template
20 | var template embed.FS
21 |
22 | func RegisterOpenAPIService(appName string, rtr *mux.Router) {
23 | rtr.Handle(apiFile, http.FileServer(http.FS(Static)))
24 | rtr.HandleFunc("/", handler(appName))
25 | }
26 |
27 | // handler returns an http handler that servers OpenAPI console for an OpenAPI spec at specURL.
28 | func handler(title string) http.HandlerFunc {
29 | t, _ := httptemplate.ParseFS(template, indexFile)
30 |
31 | return func(w http.ResponseWriter, req *http.Request) {
32 | _ = t.Execute(w, struct {
33 | Title string
34 | URL string
35 | }{
36 | title,
37 | apiFile,
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/interchaintest/utils/setup.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | testifysuite "github.com/stretchr/testify/suite"
5 | )
6 |
7 | // Not const because we need to give them as pointers later
8 | var (
9 | lazyVals = 1
10 | lazyFullNodes = 0
11 | celestialVals = 1
12 | celestialFullNodes = 0
13 | stargazeVals = 1
14 | stargazeFullNodes = 0
15 |
16 | votingPeriod = "15s"
17 | maxDepositPeriod = "10s"
18 |
19 | lazyChainId = "lazytestchain-1"
20 | celestiaChainID = "celestiatest-1"
21 | sgChainID = "stargazetest-1"
22 | )
23 |
24 | type E2ETestSuite struct {
25 | testifysuite.Suite
26 | InterchainValues
27 | }
28 |
29 | func (s *E2ETestSuite) SetupSuite() {
30 | s.testifySuiteRef = &s.Suite // See comment on the InterchainValues struct
31 | s.SetupInterchainValues()
32 | }
33 |
34 | func (s *E2ETestSuite) TearDownSuite() {
35 | s.T().Log("tearing down e2e test suite")
36 | if s.Interchain != nil {
37 | _ = s.Interchain.Close()
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/docs/template/index.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ .Title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
25 |
26 | Footer
27 | © 2022 GitHub, Inc.
28 | Footer navigation
29 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazycommandutils/ics20.go:
--------------------------------------------------------------------------------
1 | package lazycommandutils
2 |
3 | type ICS20Networks struct {
4 | Celestia StaticICS20NetworkInfo
5 | LazyChain StaticICS20NetworkInfo
6 | }
7 |
8 | type StaticICS20NetworkInfo struct {
9 | ChainID string
10 | Node string
11 | GasPrices string
12 | ICS20Denom string
13 | ICS20Channel string
14 | }
15 |
16 | var (
17 | ICS20Mainnets = ICS20Networks{} // TODO: Update once mainnet
18 | ICS20Testnets = ICS20Networks{
19 | Celestia: StaticICS20NetworkInfo{
20 | ChainID: testnetCelestiaChainID,
21 | Node: testnetCelestiaNode,
22 | GasPrices: testnetCelestiaGasPrices,
23 | ICS20Denom: "utia",
24 | ICS20Channel: "channel-95",
25 | },
26 | LazyChain: StaticICS20NetworkInfo{
27 | ChainID: testnetLazyChainChainID,
28 | Node: testnetLazyChainNode,
29 | GasPrices: testnetLazyChainGasPrices,
30 | ICS20Denom: "ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA",
31 | ICS20Channel: "channel-0",
32 | },
33 | }
34 | )
35 |
--------------------------------------------------------------------------------
/app/upgrades/types.go:
--------------------------------------------------------------------------------
1 | package upgrades
2 |
3 | import (
4 | store "cosmossdk.io/store/types"
5 | upgradetypes "cosmossdk.io/x/upgrade/types"
6 | "github.com/cosmos/cosmos-sdk/types/module"
7 | )
8 |
9 | // Upgrade defines a struct containing necessary fields that a SoftwareUpgradeProposal
10 | // must have written, in order for the state migration to go smoothly.
11 | // An upgrade must implement this struct, and then set it in the app.go.
12 | // The app.go will then define the handler.
13 | type Upgrade struct {
14 | // UpgradeName defines the on-chain upgrade name for the upgrade, e.g. "v1.8", "v1.9", etc.
15 | UpgradeName string
16 |
17 | // CreateUpgradeHandler defines the function that creates an upgrade handler
18 | // mm *module.Manager, computeModule *computetypes.AppModule, configurator module.Configurator
19 | CreateUpgradeHandler func(
20 | mm *module.Manager,
21 | configurator module.Configurator,
22 | ) upgradetypes.UpgradeHandler
23 |
24 | // Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed.
25 | StoreUpgrades store.StoreUpgrades
26 | }
27 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM golang:1.22-alpine as builder
2 |
3 | USER root
4 | WORKDIR /code
5 |
6 | RUN apk add --no-cache ca-certificates build-base git libusb-dev linux-headers
7 |
8 | ADD go.mod go.sum ./
9 | RUN set -eux; \
10 | export ARCH=$(uname -m); \
11 | WASM_VERSION=$(go list -m all | grep github.com/CosmWasm/wasmvm/v2 | awk '{print $2}'); \
12 | if [ ! -z "${WASM_VERSION}" ]; then \
13 | mkdir -p /code/downloads; \
14 | wget -O /code/downloads/libwasmvm_muslc.a https://github.com/CosmWasm/wasmvm/releases/download/${WASM_VERSION}/libwasmvm_muslc.${ARCH}.a; \
15 | fi; \
16 | cp /code/downloads/libwasmvm_muslc.a /usr/lib/libwasmvm_muslc.${ARCH}.a; \
17 | cp /code/downloads/libwasmvm_muslc.a /usr/lib/libwasmvm_muslc.a;
18 |
19 | RUN go mod download;
20 |
21 | COPY . .
22 |
23 | RUN LEDGER_ENABLED=true BUILD_TAGS=muslc LINK_STATICALLY=true make build
24 |
25 | FROM alpine:3.16
26 |
27 | RUN apk --update add jq
28 |
29 | COPY --from=builder /code/build/lazychaind /usr/bin/lazychaind
30 |
31 | WORKDIR /opt
32 |
33 | # rest server, tendermint p2p, tendermint rpc
34 | EXPOSE 1317 26656 26657
35 |
36 | ENTRYPOINT ["/bin/sh"]
37 |
--------------------------------------------------------------------------------
/app/upgrades.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "fmt"
5 |
6 | upgradetypes "cosmossdk.io/x/upgrade/types"
7 |
8 | "github.com/Lazychain/lazychain/app/upgrades"
9 | v1_1 "github.com/Lazychain/lazychain/app/upgrades/v1.1"
10 | )
11 |
12 | var Upgrades = []upgrades.Upgrade{
13 | v1_1.Upgrade,
14 | }
15 |
16 | func (app *LazyApp) setupUpgradeHandlers() {
17 | // register upgrade handlers
18 | for _, upgradeDetails := range Upgrades {
19 | app.UpgradeKeeper.SetUpgradeHandler(
20 | upgradeDetails.UpgradeName,
21 | upgradeDetails.CreateUpgradeHandler(
22 | app.ModuleManager,
23 | app.Configurator(),
24 | ),
25 | )
26 | }
27 |
28 | // register store loaders
29 | upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
30 | if err != nil {
31 | panic(fmt.Sprintf("Failed to read upgrade info from disk %s", err))
32 | }
33 |
34 | if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
35 | return
36 | }
37 |
38 | for i := range Upgrades {
39 | if upgradeInfo.Name == Upgrades[i].UpgradeName {
40 | app.BaseApp.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &Upgrades[i].StoreUpgrades))
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/cmd/lazychaind/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strings"
7 |
8 | svrcmd "github.com/cosmos/cosmos-sdk/server/cmd"
9 |
10 | "github.com/Lazychain/lazychain/app"
11 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd"
12 | )
13 |
14 | func main() {
15 | // Hack to be able to use the same binary for custom commands that send txs to stargaze
16 | if prefixOverride := getAddressPrefixOverride(); prefixOverride != "" {
17 | app.AccountAddressPrefix = prefixOverride
18 | }
19 |
20 | rootCmd := cmd.NewRootCmd()
21 | if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
22 | _, _ = fmt.Fprintln(rootCmd.OutOrStderr(), err)
23 | os.Exit(1)
24 | }
25 | }
26 |
27 | func getAddressPrefixOverride() string {
28 | args := os.Args[1:]
29 | if len(args) > 3 &&
30 | args[1] == "sloths" &&
31 | (args[2] == "transfer" || args[2] == "owned-by") {
32 | if strings.HasPrefix(args[3], "stars") {
33 | return "stars"
34 | }
35 | }
36 |
37 | if len(args) > 3 &&
38 | args[1] == "tia" &&
39 | (args[2] == "transfer" || args[2] == "balance") {
40 | if strings.HasPrefix(args[3], "celestia") {
41 | return "celestia"
42 | }
43 | }
44 |
45 | return ""
46 | }
47 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazylogger.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "io"
5 |
6 | "github.com/rs/zerolog"
7 |
8 | "cosmossdk.io/log"
9 |
10 | "github.com/cosmos/cosmos-sdk/client/flags"
11 | "github.com/cosmos/cosmos-sdk/server"
12 | )
13 |
14 | func CreateLazyLogger(ctx *server.Context, out io.Writer) (log.Logger, error) {
15 | var opts []log.Option
16 | if ctx.Viper.GetString(flags.FlagLogFormat) == flags.OutputFormatJSON {
17 | opts = append(opts, log.OutputJSONOption())
18 | }
19 | opts = append(opts,
20 | log.ColorOption(!ctx.Viper.GetBool(flags.FlagLogNoColor)),
21 | // We use CometBFT flag (cmtcli.TraceFlag) for trace logging.
22 | log.TraceOption(ctx.Viper.GetBool(server.FlagTrace)),
23 | func(config *log.Config) {
24 | config.TimeFormat = "🦥 3:04PM"
25 | },
26 | )
27 |
28 | // check and set filter level or keys for the logger if any
29 | logLvlStr := ctx.Viper.GetString(flags.FlagLogLevel)
30 | if logLvlStr == "" {
31 | return log.NewLogger(out, opts...), nil
32 | }
33 |
34 | logLvl, err := zerolog.ParseLevel(logLvlStr)
35 | switch {
36 | case err != nil:
37 | // If the log level is not a valid zerolog level, then we try to parse it as a key filter.
38 | filterFunc, err := log.ParseLogLevel(logLvlStr)
39 | if err != nil {
40 | return nil, err
41 | }
42 |
43 | opts = append(opts, log.FilterOption(filterFunc))
44 | default:
45 | opts = append(opts, log.LevelOption(logLvl))
46 | }
47 |
48 | return log.NewLogger(out, opts...), nil
49 | }
50 |
--------------------------------------------------------------------------------
/interchaintest/utils/t.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | var _ CustomT = &FakeT{}
9 |
10 | type CustomT interface {
11 | Name() string
12 | Cleanup(func())
13 |
14 | Skip(...any)
15 |
16 | Parallel()
17 |
18 | Log(args ...any)
19 | Logf(format string, args ...any)
20 | Errorf(string, ...interface{})
21 |
22 | Fail()
23 | FailNow()
24 |
25 | Helper()
26 |
27 | Failed() bool
28 | Skipped() bool
29 | }
30 |
31 | type FakeT struct {
32 | FakeName string
33 | CleanupFuncs []func()
34 | }
35 |
36 | func (f *FakeT) Errorf(s string, i ...interface{}) {
37 | fmt.Printf(s, i...)
38 | }
39 |
40 | func (f *FakeT) Fail() {
41 | fmt.Println("Failed!")
42 | }
43 |
44 | func (f *FakeT) FailNow() {
45 | panic("FailNow!")
46 | }
47 |
48 | func (f *FakeT) Skip(a ...any) {}
49 |
50 | func (f *FakeT) Parallel() {}
51 |
52 | func (f *FakeT) Skipped() bool {
53 | return false
54 | }
55 |
56 | func (f *FakeT) Name() string {
57 | return f.FakeName
58 | }
59 |
60 | func (f *FakeT) Helper() {}
61 |
62 | func (f *FakeT) Failed() bool {
63 | return false
64 | }
65 |
66 | func (f *FakeT) Cleanup(foo func()) {
67 | f.CleanupFuncs = append(f.CleanupFuncs, foo)
68 | }
69 |
70 | func (f *FakeT) ActuallyRunCleanups() {
71 | fmt.Println("Actually running cleanups from FakeT...")
72 | for _, foo := range f.CleanupFuncs {
73 | foo()
74 | }
75 |
76 | time.Sleep(1 * time.Second)
77 |
78 | f.CleanupFuncs = []func(){}
79 | }
80 |
81 | func (f *FakeT) Log(args ...any) {
82 | fmt.Println(args...)
83 | }
84 |
85 | func (f *FakeT) Logf(format string, args ...any) {
86 | fmt.Printf(format, args...)
87 | }
88 |
--------------------------------------------------------------------------------
/testutil/nullify/nullify.go:
--------------------------------------------------------------------------------
1 | // Package nullify provides methods to init nil values structs for test assertion.
2 | package nullify
3 |
4 | import (
5 | "reflect"
6 | "unsafe"
7 |
8 | sdk "github.com/cosmos/cosmos-sdk/types"
9 | )
10 |
11 | var (
12 | coinType = reflect.TypeOf(sdk.Coin{})
13 | coinsType = reflect.TypeOf(sdk.Coins{})
14 | )
15 |
16 | // Fill analyze all struct fields and slices with
17 | // reflection and initialize the nil and empty slices,
18 | // structs, and pointers.
19 | func Fill(x interface{}) interface{} {
20 | v := reflect.Indirect(reflect.ValueOf(x))
21 | switch v.Kind() {
22 | case reflect.Slice:
23 | for i := 0; i < v.Len(); i++ {
24 | obj := v.Index(i)
25 | objPt := reflect.NewAt(obj.Type(), unsafe.Pointer(obj.UnsafeAddr())).Interface()
26 | objPt = Fill(objPt)
27 | obj.Set(reflect.ValueOf(objPt))
28 | }
29 | case reflect.Struct:
30 | for i := 0; i < v.NumField(); i++ {
31 | f := reflect.Indirect(v.Field(i))
32 | if !f.CanSet() {
33 | continue
34 | }
35 | switch f.Kind() {
36 | case reflect.Slice:
37 | f.Set(reflect.MakeSlice(f.Type(), 0, 0))
38 | case reflect.Struct:
39 | switch f.Type() {
40 | case coinType:
41 | coin := reflect.New(coinType).Interface()
42 | s := reflect.ValueOf(coin).Elem()
43 | f.Set(s)
44 | case coinsType:
45 | coins := reflect.New(coinsType).Interface()
46 | s := reflect.ValueOf(coins).Elem()
47 | f.Set(s)
48 | default:
49 | objPt := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Interface()
50 | s := Fill(objPt)
51 | f.Set(reflect.ValueOf(s))
52 | }
53 | }
54 | }
55 | }
56 | return reflect.Indirect(v).Interface()
57 | }
58 |
--------------------------------------------------------------------------------
/.github/workflows/interslothtest.yaml:
--------------------------------------------------------------------------------
1 | name: "E2E Test LazyChain 💤"
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | push:
7 | branches:
8 | - main
9 |
10 | env:
11 | REGISTRY: ghcr.io
12 | IMAGE_NAME: lazychain
13 | LAZYCHAIN_IMAGE_REPOSITORY: ghcr.io/lazychain/lazychain
14 | LAZYCHAIN_IMAGE_VERSION: latest # TODO: It would be better to get a specific version of the image
15 |
16 | jobs:
17 | build-docker-image:
18 | runs-on: ubuntu-latest
19 | steps:
20 | - uses: actions/checkout@v4
21 |
22 | - name: Set up Docker Buildx
23 | uses: docker/setup-buildx-action@v3
24 |
25 | - name: Log in to the Container registry
26 | uses: docker/login-action@v3
27 | with:
28 | registry: ${{ env.REGISTRY }}
29 | username: ${{ github.actor }}
30 | password: ${{ secrets.GITHUB_TOKEN }}
31 |
32 | - name: Build Docker image
33 | uses: docker/build-push-action@v5
34 | with:
35 | push: true
36 | tags: ghcr.io/lazychain/lazychain:latest # TODO: It would better to create a commit specific tag
37 |
38 | interchaintest:
39 | runs-on: ubuntu-latest
40 | needs: [build-docker-image]
41 | steps:
42 | - uses: actions/checkout@v4
43 | - name: Log in to the Container registry
44 | uses: docker/login-action@v3
45 | with:
46 | registry: ${{ env.REGISTRY }}
47 | username: ${{ github.actor }}
48 | password: ${{ secrets.GITHUB_TOKEN }}
49 |
50 | - uses: actions/setup-go@v5
51 | with:
52 | go-version: '1.22'
53 | cache-dependency-path: 'interchaintest/go.sum'
54 |
55 | - name: Load Docker Image
56 | run: docker pull ${{ env.LAZYCHAIN_IMAGE_REPOSITORY }}:${{ env.LAZYCHAIN_IMAGE_VERSION }}
57 |
58 | - name: Run interchaintest
59 | run: make interchaintest
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazycommandutils/ics721.go:
--------------------------------------------------------------------------------
1 | package lazycommandutils
2 |
3 | type ICS721Networks struct {
4 | LazyChain StaticICS721NetworkInfo
5 | Stargaze StaticICS721NetworkInfo
6 | }
7 |
8 | type StaticICS721NetworkInfo struct {
9 | ChainID string
10 | Node string
11 | GasPrices string
12 | NFTContract string
13 | ICS721Contract string
14 | ICS721Channel string
15 | }
16 |
17 | var (
18 | ICS721Mainnets = ICS721Networks{} // TODO: Update once mainnet
19 | ICS721Testnets = ICS721Networks{
20 | LazyChain: StaticICS721NetworkInfo{
21 | ChainID: testnetLazyChainChainID,
22 | Node: testnetLazyChainNode,
23 | GasPrices: testnetLazyChainGasPrices,
24 | NFTContract: "lazy1enc8mxs5tsu6zzmvu0uh9snj28yp4nt2xycv3l6054p339gweavqgd224r",
25 | ICS721Contract: "lazy1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtq8xhtac",
26 | ICS721Channel: "channel-1",
27 | // ICS721Contract: "lazy1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqnzqkf5", // Base, connected with channel-1 and Base ICS721 contract
28 | // ICS721Channel: "channel-2", // Connected with base version of ICS721
29 | },
30 | Stargaze: StaticICS721NetworkInfo{
31 | ChainID: testnetStargazeChainID,
32 | Node: testnetStargazeNode,
33 | GasPrices: testnetStargazeGasPrices,
34 | NFTContract: "stars1z5vs00kvjwr3h050twnul5pd2sftk42ajy7xp6sg59gux4cvprvq08eryl",
35 | ICS721Contract: "stars1338rc4fn2r3k9z9x783pmtgcwcqmz5phaksurrznnu9dnu4dmctqr2gyzl", // Proxy for SG-721 (wasm.stars1cxnwk637xwee9gcw0v2ua00gnyhvzxkte8ucnxzfxj0ea8nxkppsgacht3)
36 | ICS721Channel: "channel-979", // SG
37 | // ICS721Contract: "stars1n2nejlcr3758rh5yfsg8jkq7xv6kv9ls00wu5ja66qcw26ka4npszpng5v", // Base ICS721 contract
38 | // ICS721Channel: "channel-980", // Base ICS721 channel
39 | },
40 | }
41 | )
42 |
--------------------------------------------------------------------------------
/app/genesis_account.go:
--------------------------------------------------------------------------------
1 | package app
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 = (*GenesisAccount)(nil)
11 |
12 | // GenesisAccount defines a type that implements the GenesisAccount interface
13 | // to be used for simulation accounts in the genesis state.
14 | type GenesisAccount 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 GenesisAccount) Validate() error {
31 | if !sga.OriginalVesting.IsZero() {
32 | if sga.StartTime >= sga.EndTime {
33 | return errors.New("vesting start-time cannot be before end-time")
34 | }
35 | }
36 |
37 | if sga.ModuleName != "" {
38 | ma := authtypes.ModuleAccount{
39 | BaseAccount: sga.BaseAccount, Name: sga.ModuleName, Permissions: sga.ModulePermissions,
40 | }
41 | if err := ma.Validate(); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return sga.BaseAccount.Validate()
47 | }
48 |
--------------------------------------------------------------------------------
/app/tokenfactory.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "cosmossdk.io/core/appmodule"
5 | storetypes "cosmossdk.io/store/types"
6 |
7 | "github.com/Stride-Labs/tokenfactory/tokenfactory"
8 | tokenfactorykeeper "github.com/Stride-Labs/tokenfactory/tokenfactory/keeper"
9 | tokenfactorytypes "github.com/Stride-Labs/tokenfactory/tokenfactory/types"
10 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
11 | "github.com/cosmos/cosmos-sdk/types/module"
12 | )
13 |
14 | // registerTokenFactoryModule register the tokenfactory keeper and non dependency inject modules
15 | func (app *LazyApp) registerTokenFactoryModule() error {
16 | // set up non depinject support modules store keys
17 | if err := app.RegisterStores(
18 | storetypes.NewKVStoreKey(tokenfactorytypes.StoreKey),
19 | ); err != nil {
20 | panic(err)
21 | }
22 |
23 | // register the key tables for legacy param subspaces
24 | app.ParamsKeeper.Subspace(tokenfactorytypes.ModuleName)
25 |
26 | // Cast module account permissions
27 | maccPerms := make(map[string][]string)
28 | for _, modulePerms := range moduleAccPerms {
29 | maccPerms[modulePerms.Account] = modulePerms.Permissions
30 | }
31 |
32 | // Token factory keeper
33 | app.TokenFactoryKeeper = tokenfactorykeeper.NewKeeper(
34 | app.GetKey(tokenfactorytypes.StoreKey),
35 | app.GetSubspace(tokenfactorytypes.ModuleName),
36 | maccPerms,
37 | app.AccountKeeper,
38 | app.BankKeeper,
39 | app.DistrKeeper,
40 | )
41 |
42 | // register tokenfactory module
43 | if err := app.RegisterModules(
44 | tokenfactory.NewAppModule(app.TokenFactoryKeeper, app.AccountKeeper, app.BankKeeper)); err != nil {
45 | return err
46 | }
47 |
48 | return nil
49 | }
50 |
51 | // RegisterTokenFactory Since the tokenfactory doesn't support dependency injection,
52 | // we need to manually register the modules on the client side.
53 | func RegisterTokenFactory(registry cdctypes.InterfaceRegistry) (string, appmodule.AppModule) {
54 | name := tokenfactorytypes.ModuleName
55 | mod := tokenfactory.AppModule{}
56 | module.CoreAppModuleBasicAdaptor(name, mod).RegisterInterfaces(registry)
57 | return name, mod
58 | }
59 |
--------------------------------------------------------------------------------
/testutil/network/network.go:
--------------------------------------------------------------------------------
1 | package network
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/require"
8 |
9 | "github.com/cosmos/cosmos-sdk/testutil/network"
10 |
11 | "github.com/Lazychain/lazychain/app"
12 | )
13 |
14 | type (
15 | Network = network.Network
16 | Config = network.Config
17 | )
18 |
19 | // New creates instance with fully configured cosmos network.
20 | // Accepts optional config, that will be used in place of the DefaultConfig() if provided.
21 | func New(t *testing.T, configs ...Config) *Network {
22 | t.Helper()
23 | if len(configs) > 1 {
24 | panic("at most one config should be provided")
25 | }
26 | var cfg network.Config
27 | if len(configs) == 0 {
28 | cfg = DefaultConfig()
29 | } else {
30 | cfg = configs[0]
31 | }
32 | net, err := network.New(t, t.TempDir(), cfg)
33 | require.NoError(t, err)
34 | _, err = net.WaitForHeight(1)
35 | require.NoError(t, err)
36 | t.Cleanup(net.Cleanup)
37 | return net
38 | }
39 |
40 | // DefaultConfig will initialize config for the network with custom application,
41 | // genesis and single validator. All other parameters are inherited from cosmos-sdk/testutil/network.DefaultConfig
42 | func DefaultConfig() network.Config {
43 | cfg, err := network.DefaultConfigWithAppConfig(app.Config())
44 | if err != nil {
45 | panic(err)
46 | }
47 | ports, err := freePorts(3)
48 | if err != nil {
49 | panic(err)
50 | }
51 | if cfg.APIAddress == "" {
52 | cfg.APIAddress = fmt.Sprintf("tcp://0.0.0.0:%s", ports[0])
53 | }
54 | if cfg.RPCAddress == "" {
55 | cfg.RPCAddress = fmt.Sprintf("tcp://0.0.0.0:%s", ports[1])
56 | }
57 | if cfg.GRPCAddress == "" {
58 | cfg.GRPCAddress = fmt.Sprintf("0.0.0.0:%s", ports[2])
59 | }
60 | return cfg
61 | }
62 |
63 | // freePorts return the available ports based on the number of requested ports.
64 | func freePorts(n int) ([]string, error) {
65 | closeFns := make([]func() error, n)
66 | ports := make([]string, n)
67 | for i := 0; i < n; i++ {
68 | _, port, closeFn, err := network.FreeTCPAddr()
69 | if err != nil {
70 | return nil, err
71 | }
72 | ports[i] = port
73 | closeFns[i] = closeFn
74 | }
75 | for _, closeFn := range closeFns {
76 | if err := closeFn(); err != nil {
77 | return nil, err
78 | }
79 | }
80 | return ports, nil
81 | }
82 |
--------------------------------------------------------------------------------
/app/ante.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "errors"
5 |
6 | wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
7 | wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types"
8 | ibcante "github.com/cosmos/ibc-go/v8/modules/core/ante"
9 | "github.com/cosmos/ibc-go/v8/modules/core/keeper"
10 |
11 | corestoretypes "cosmossdk.io/core/store"
12 | circuitante "cosmossdk.io/x/circuit/ante"
13 | circuitkeeper "cosmossdk.io/x/circuit/keeper"
14 |
15 | sdk "github.com/cosmos/cosmos-sdk/types"
16 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
17 | )
18 |
19 | // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC
20 | // channel keeper.
21 | type HandlerOptions struct {
22 | ante.HandlerOptions
23 |
24 | IBCKeeper *keeper.Keeper
25 | WasmConfig *wasmTypes.WasmConfig
26 | WasmKeeper *wasmkeeper.Keeper
27 | TXCounterStoreService corestoretypes.KVStoreService
28 | CircuitKeeper *circuitkeeper.Keeper
29 | }
30 |
31 | // NewAnteHandler constructor
32 | func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
33 | if options.AccountKeeper == nil {
34 | return nil, errors.New("account keeper is required for ante builder")
35 | }
36 | if options.BankKeeper == nil {
37 | return nil, errors.New("bank keeper is required for ante builder")
38 | }
39 | if options.SignModeHandler == nil {
40 | return nil, errors.New("sign mode handler is required for ante builder")
41 | }
42 | if options.WasmConfig == nil {
43 | return nil, errors.New("wasm config is required for ante builder")
44 | }
45 | if options.TXCounterStoreService == nil {
46 | return nil, errors.New("wasm store service is required for ante builder")
47 | }
48 | if options.CircuitKeeper == nil {
49 | return nil, errors.New("circuit keeper is required for ante builder")
50 | }
51 |
52 | anteDecorators := []sdk.AnteDecorator{
53 | ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
54 | wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), // after setup context to enforce limits early
55 | wasmkeeper.NewCountTXDecorator(options.TXCounterStoreService),
56 | wasmkeeper.NewGasRegisterDecorator(options.WasmKeeper.GetGasRegister()),
57 | circuitante.NewCircuitBreakerDecorator(options.CircuitKeeper),
58 | ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
59 | ante.NewValidateBasicDecorator(),
60 | ante.NewTxTimeoutHeightDecorator(),
61 | ante.NewValidateMemoDecorator(options.AccountKeeper),
62 | ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
63 | ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
64 | ante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
65 | ante.NewValidateSigCountDecorator(options.AccountKeeper),
66 | ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
67 | ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
68 | ante.NewIncrementSequenceDecorator(options.AccountKeeper),
69 | ibcante.NewRedundantRelayDecorator(options.IBCKeeper),
70 | }
71 |
72 | return sdk.ChainAnteDecorators(anteDecorators...), nil
73 | }
74 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/tia/query.go:
--------------------------------------------------------------------------------
1 | package tia
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/spf13/cobra"
8 |
9 | "github.com/cosmos/cosmos-sdk/client"
10 | sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
13 |
14 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/lazycommandutils"
15 | )
16 |
17 | func GetQueryCmd() *cobra.Command {
18 | cmd := &cobra.Command{
19 | Use: "tia",
20 | Short: "Query commands for TIA",
21 | DisableFlagParsing: true,
22 | RunE: client.ValidateCmd,
23 | }
24 |
25 | cmd.AddCommand(QueryTIABalanceCmd())
26 |
27 | return cmd
28 | }
29 |
30 | func QueryTIABalanceCmd() *cobra.Command {
31 | cmd := &cobra.Command{
32 | Use: "balance [address]",
33 | Short: "Query tia balance of an address",
34 | Args: cobra.ExactArgs(1),
35 | RunE: func(cmd *cobra.Command, args []string) error {
36 | address := args[0]
37 |
38 | node, _ := cmd.Flags().GetString(sdkflags.FlagNode)
39 | denom, _ := cmd.Flags().GetString(lazycommandutils.FlagICS20Denom)
40 | mainnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagMainnet)
41 | testnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagTestnet)
42 |
43 | if !mainnet && !testnet && node == "" {
44 | return fmt.Errorf("missing required flags. Either set --mainnet or --testnet or provide the manual flags (--%s --%s)",
45 | sdkflags.FlagNode, lazycommandutils.FlagNFTContract)
46 | }
47 |
48 | isCelestia := strings.HasPrefix(address, "celestia")
49 | if mainnet {
50 | return fmt.Errorf("mainnet not supported yet")
51 | } else if testnet {
52 | var networkInfo lazycommandutils.StaticICS20NetworkInfo
53 | if isCelestia {
54 | networkInfo = lazycommandutils.ICS20Testnets.Celestia
55 | } else {
56 | networkInfo = lazycommandutils.ICS20Testnets.LazyChain
57 | }
58 |
59 | denom = networkInfo.ICS20Denom
60 | node = networkInfo.Node
61 | // Needed because this flag is picked up later by the clientCtx
62 | if err := cmd.Flags().Set(sdkflags.FlagNode, node); err != nil {
63 | return err
64 | }
65 | }
66 |
67 | clientCtx, err := client.GetClientQueryContext(cmd)
68 | if err != nil {
69 | return err
70 | }
71 |
72 | queryClient := banktypes.NewQueryClient(clientCtx)
73 | accAddr, err := sdk.AccAddressFromBech32(address)
74 | if err != nil {
75 | return err
76 | }
77 | params := banktypes.NewQueryBalanceRequest(accAddr, denom)
78 | res, err := queryClient.Balance(cmd.Context(), params)
79 | if err != nil {
80 | return err
81 | }
82 |
83 | return clientCtx.PrintProto(res.Balance)
84 | },
85 | }
86 |
87 | cmd.Flags().Bool(lazycommandutils.FlagMainnet, false, "Use mainnet values")
88 | cmd.Flags().Bool(lazycommandutils.FlagTestnet, false, "Use testnet values")
89 | cmd.Flags().String(lazycommandutils.FlagICS20Denom, "", "Denom of ICS20 token (optional if using --testnet or --mainnet)")
90 |
91 | sdkflags.AddQueryFlagsToCmd(cmd)
92 |
93 | nodeFlag := cmd.Flags().Lookup(sdkflags.FlagNode)
94 | nodeFlag.DefValue = ""
95 | nodeFlag.Usage = "RPC endpoint of chain to query (Celestia or LazyChain)"
96 |
97 | return cmd
98 | }
99 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/config.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | serverconfig "github.com/cosmos/cosmos-sdk/server/config"
5 | sdk "github.com/cosmos/cosmos-sdk/types"
6 |
7 | cmtcfg "github.com/cometbft/cometbft/config"
8 |
9 | "github.com/Lazychain/lazychain/app"
10 | )
11 |
12 | func initSDKConfig() {
13 | // Set prefixes
14 | accountPubKeyPrefix := app.AccountAddressPrefix + "pub"
15 | validatorAddressPrefix := app.AccountAddressPrefix + "valoper"
16 | validatorPubKeyPrefix := app.AccountAddressPrefix + "valoperpub"
17 | consNodeAddressPrefix := app.AccountAddressPrefix + "valcons"
18 | consNodePubKeyPrefix := app.AccountAddressPrefix + "valconspub"
19 |
20 | // Set and seal config
21 | config := sdk.GetConfig()
22 | config.SetBech32PrefixForAccount(app.AccountAddressPrefix, accountPubKeyPrefix)
23 | config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix)
24 | config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix)
25 | config.Seal()
26 | }
27 |
28 | // initCometBFTConfig helps to override default CometBFT Config values.
29 | // return cmtcfg.DefaultConfig if no custom configuration is required for the application.
30 | func initCometBFTConfig() *cmtcfg.Config {
31 | cfg := cmtcfg.DefaultConfig()
32 |
33 | // these values put a higher strain on node memory
34 | // cfg.P2P.MaxNumInboundPeers = 100
35 | // cfg.P2P.MaxNumOutboundPeers = 40
36 |
37 | return cfg
38 | }
39 |
40 | // initAppConfig helps to override default appConfig template and configs.
41 | // return "", nil if no custom configuration is required for the application.
42 | func initAppConfig() (string, interface{}) {
43 | // The following code snippet is just for reference.
44 | type CustomAppConfig struct {
45 | serverconfig.Config `mapstructure:",squash"`
46 | }
47 |
48 | // Optionally allow the chain developer to overwrite the SDK's default
49 | // server config.
50 | srvCfg := serverconfig.DefaultConfig()
51 | // The SDK's default minimum gas price is set to "" (empty value) inside
52 | // app.toml. If left empty by validators, the node will halt on startup.
53 | // However, the chain developer can set a default app.toml value for their
54 | // validators here.
55 | //
56 | // In summary:
57 | // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their
58 | // own app.toml config,
59 | // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their
60 | // own app.toml to override, or use this default value.
61 | //
62 | // In tests, we set the min gas prices to 0.
63 | // srvCfg.MinGasPrices = "0stake"
64 | // srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default
65 |
66 | customAppConfig := CustomAppConfig{
67 | Config: *srvCfg,
68 | }
69 |
70 | customAppTemplate := serverconfig.DefaultConfigTemplate
71 | // Edit the default template file
72 | //
73 | // customAppTemplate := serverconfig.DefaultConfigTemplate + `
74 | // [wasm]
75 | // # This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries
76 | // query_gas_limit = 300000
77 | // # This is the number of wasm vm instances we keep cached in memory for speed-up
78 | // # Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally
79 | // lru_size = 0`
80 |
81 | return customAppTemplate, customAppConfig
82 | }
83 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | tests: true
3 | timeout: 10m
4 |
5 | linters:
6 | disable-all: true
7 | enable:
8 | - exportloopref
9 | - errcheck
10 | - gci
11 | - goconst
12 | - gocritic
13 | - gofumpt
14 | - gosec
15 | - gosimple
16 | - govet
17 | - ineffassign
18 | - misspell
19 | - nakedret
20 | - staticcheck
21 | - thelper
22 | - typecheck
23 | - stylecheck
24 | - revive
25 | - typecheck
26 | - tenv
27 | - unconvert
28 | # Prefer unparam over revive's unused param. It is more thorough in its checking.
29 | - unparam
30 | - unused
31 | - misspell
32 |
33 | issues:
34 | exclude-rules:
35 | - text: 'differs only by capitalization to method'
36 | linters:
37 | - revive
38 | - text: 'Use of weak random number generator'
39 | linters:
40 | - gosec
41 | - linters:
42 | - staticcheck
43 | text: "SA1019:" # silence errors on usage of deprecated funcs
44 |
45 | max-issues-per-linter: 10000
46 | max-same-issues: 10000
47 |
48 | linters-settings:
49 | gci:
50 | sections:
51 | - standard # Standard section: captures all standard packages.
52 | - default # Default section: contains all imports that could not be matched to another section type.
53 | - blank # blank imports
54 | - dot # dot imports
55 | - prefix(cosmossdk.io)
56 | - prefix(github.com/cosmos/cosmos-sdk)
57 | - prefix(github.com/cometbft/cometbft)
58 | - prefix(github.com/Lazychain/lazychain)
59 | custom-order: true
60 | revive:
61 | enable-all-rules: true
62 | # Do NOT whine about the following, full explanation found in:
63 | # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#description-of-available-rules
64 | rules:
65 | - name: use-any
66 | disabled: true
67 | - name: if-return
68 | disabled: true
69 | - name: max-public-structs
70 | disabled: true
71 | - name: cognitive-complexity
72 | disabled: true
73 | - name: argument-limit
74 | disabled: true
75 | - name: cyclomatic
76 | disabled: true
77 | - name: file-header
78 | disabled: true
79 | - name: function-length
80 | disabled: true
81 | - name: function-result-limit
82 | disabled: true
83 | - name: line-length-limit
84 | disabled: true
85 | - name: flag-parameter
86 | disabled: true
87 | - name: add-constant
88 | disabled: true
89 | - name: empty-lines
90 | disabled: true
91 | - name: banned-characters
92 | disabled: true
93 | - name: deep-exit
94 | disabled: true
95 | - name: confusing-results
96 | disabled: true
97 | - name: unused-parameter
98 | disabled: true
99 | - name: modifies-value-receiver
100 | disabled: true
101 | - name: early-return
102 | disabled: true
103 | - name: confusing-naming
104 | disabled: true
105 | - name: defer
106 | disabled: true
107 | # Disabled in favour of unparam.
108 | - name: unused-parameter
109 | disabled: true
110 | - name: unhandled-error
111 | disabled: false
112 | arguments:
113 | - 'fmt.Printf'
114 | - 'fmt.Print'
115 | - 'fmt.Println'
116 | - 'myFunction'
117 |
--------------------------------------------------------------------------------
/app/upgrades/v1.1/upgrade.go:
--------------------------------------------------------------------------------
1 | package v1_1
2 |
3 | import (
4 | "context"
5 |
6 | storetypes "cosmossdk.io/store/types"
7 | upgradetypes "cosmossdk.io/x/upgrade/types"
8 | "github.com/Lazychain/lazychain/app/upgrades"
9 | tokenfactorytypes "github.com/Stride-Labs/tokenfactory/tokenfactory/types"
10 | sdk "github.com/cosmos/cosmos-sdk/types"
11 | "github.com/cosmos/cosmos-sdk/types/module"
12 | )
13 |
14 | const upgradeName = "v1.1"
15 |
16 | var Upgrade = upgrades.Upgrade{
17 | UpgradeName: upgradeName,
18 | CreateUpgradeHandler: createUpgradeHandler,
19 | StoreUpgrades: storetypes.StoreUpgrades{
20 | Added: []string{tokenfactorytypes.StoreKey},
21 | },
22 | }
23 |
24 | // CreateUpgradeHandler creates an SDK upgrade handler for v1.1
25 | func createUpgradeHandler(
26 | mm *module.Manager,
27 | configurator module.Configurator,
28 | ) upgradetypes.UpgradeHandler {
29 | return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
30 | sdkCtx := sdk.UnwrapSDKContext(ctx)
31 |
32 | sdkCtx.Logger().Info(` _ _ _____ _____ _____ _____ ______ `)
33 | sdkCtx.Logger().Info(` | | | | __ \ / ____| __ \ /\ | __ \| ____| `)
34 | sdkCtx.Logger().Info(` | | | | |__) | | __| |__) | / \ | | | | |__ `)
35 | sdkCtx.Logger().Info(` | | | | ___/| | |_ | _ / / /\ \ | | | | __| `)
36 | sdkCtx.Logger().Info(` | |__| | | | |__| | | \ \ / ____ \| |__| | |____ `)
37 | sdkCtx.Logger().Info(` \____/|_| \_____|_| \_\/_/ \_\_____/|______| `)
38 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⠖⢶⣦⣄⡀⠀⢀⣴⣶⠟⠓⣶⣦⣄⡀⠀⠀⠀⠀⠀⣀⣤⣤⣀⡀⠀⠀⢠⣤⣤⣄⡀⠀⠀⠀⠀⠀")
39 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡿⣿⡄⠀⣿⠈⢻⣤⣾⠏⠀⠀⠀⠈⢷⡈⠻⣦⡀⠀⣠⣾⠟⠋⠀⠙⣿⣶⣴⠏⢠⣿⠋⠉⣷⡄⠀⠀⠀")
40 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⠁⠈⣿⠀⣿⠃⢸⣿⡏⠀⠀⠀⠀⠀⢸⡻⣦⣹⣇⢠⣿⠃⠀⠀⠀⠀⠘⣇⠙⣧⡿⢁⣴⠞⠛⢿⡆⠀⠀")
41 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⢰⣿⠃⠀⠀⢹⣷⣿⣰⡿⢿⡇⠀⠀⠀⠀⠀⢸⢻⣜⣷⣿⣿⡇⠀⠀⠀⠀⠀⠀⣟⣷⣹⣁⡞⠁⠀⠀⠘⣿⡄⠀")
42 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⣿⡟⠀⠀⠀⠈⠉⢹⡟⠁⢸⡇⠀⠀⠀⠀⠀⢸⡆⠙⠃⢀⣿⠀⠀⠀⠀⠀⠀⠀⣿⠛⣿⠛⠀⠀⠀⠀⠀⢹⡇⠀")
43 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠈⣇⠀⢸⡇⠀⠀⠀⠀⠀⠀⣇⠀⠀⠘⣿⡄⠀⠀⠀⠀⠀⠀⢹⡀⢸⡇⠀⠀⠀⠀⠀⠘⣿⠀")
44 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⣿⡀⢸⣷⠀⠀⠀⠀⠀⠀⢻⡆⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠸⣧⢸⣿⠀⠀⠀⠀⠀⠀⢿⡆")
45 | sdkCtx.Logger().Info("⠀⠀⠀⠀⣠⣤⣶⣶⣿⠿⢶⣶⣤⣄⠀⠀⠘⡇⠀⢻⡄⠀⠀⠀⠀⠀⠀⢳⡀⠀⢻⣧⠀⠀⠀⠀⠀⠀⠀⢿⣾⣿⠀⠀⠀⠀⠀⠀⢸⡇")
46 | sdkCtx.Logger().Info("⠀⠀⣴⣿⢟⣯⣭⡎⠀⠀⢀⣤⡟⠻⣷⣄⠀⢹⡄⢸⣇⠀⠀⠀⠀⠀⠀⠈⣷⡀⠘⣿⡄⠀⠀⠀⠀⠀⠀⠀⢿⡏⠀⠀⠀⠀⠀⠀⢸⣧")
47 | sdkCtx.Logger().Info("⢀⣾⢏⠞⠉⠀⠀⠀⠀⠀⠻⢿⣿⣀⠼⢿⣶⣶⣷⡀⣿⡀⠀⠀⠀⠀⠀⠀⢸⣇⠀⢻⣷⠀⠀⠀⠀⠀⠀⠀⠈⢿⣆⠀⠀⠀⠀⠀⢸⣿")
48 | sdkCtx.Logger().Info("⣸⡷⠋⠀⠀⠀⠀⣠⣶⣿⠦⣤⠄⠀⠀⠀⣿⣿⣦⡀⣿⠇⠀⠀⠀⠀⠀⠀⠀⢻⡀⠈⣿⡆⠀⠀⠀⠀⠀⠀⠀⠈⢻⣆⠀⠀⠀⠀⢸⣿")
49 | sdkCtx.Logger().Info("⣿⢁⡴⣾⣿⡆⠀⠙⢛⣡⡾⠋⠀⠀⠀⢠⠇⠈⠛⣿⠏⠀⠀⠀⠀⠀⠀⠰⣄⠸⡗⠛⢻⣿⠀⠀⠀⠀⠀⠀⠀⠀⠈⢻⣆⠀⠀⠀⣼⣿")
50 | sdkCtx.Logger().Info("⢿⡞⠀⠈⢉⡇⠉⠉⠉⠉⠀⠀⠀⠀⣠⠊⠀⢀⡾⠋⠀⠀⠀⠀⠀⢀⡀⠀⣿⠳⠇⠀⢸⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡄⠀⠀⣿⡇")
51 | sdkCtx.Logger().Info("⠸⣷⠀⢠⠎⠀⠀⠀⠀⠀⠀⣀⠴⠋⠀⠖⠚⠋⠀⠀⠀⠀⠀⢀⡄⢸⣷⡀⣿⠀⠀⠀⣸⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⢰⣿⠇")
52 | sdkCtx.Logger().Info("⠀⢻⣷⣯⣀⣀⣀⣀⣠⠤⠚⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠛⠿⣷⠇⠀⠀⢠⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⣾⡟⠀")
53 | sdkCtx.Logger().Info("⠀⠈⢻⣷⡉⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⡿⠃⠀")
54 | sdkCtx.Logger().Info("⠀⠀⠀⢻⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⠃⠀⠀")
55 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠙⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⠇⠀⠀⠀")
56 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠈⠻⣿⣷⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⡿⠃⠀⠀⠀⠀")
57 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠈⠛⢿⣿⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⠟⠁⠀⠀⠀⠀⠀")
58 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠻⢿⣿⣶⣦⣄⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣴⣶⣿⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀")
59 | sdkCtx.Logger().Info("⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⡻⠿⠿⣿⣿⣷⣶⣶⣶⣶⣶⣶⣶⣶⣶⣿⣿⠿⠿⢛⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀")
60 |
61 | sdkCtx.Logger().Info("Running module migrations for %s...", upgradeName)
62 | return mm.RunMigrations(ctx, configurator, fromVM)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/sloths/query.go:
--------------------------------------------------------------------------------
1 | package sloths
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "strings"
7 |
8 | wasmdtypes "github.com/CosmWasm/wasmd/x/wasm/types"
9 | "github.com/spf13/cobra"
10 |
11 | "github.com/cosmos/cosmos-sdk/client"
12 | sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
13 |
14 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/lazycommandutils"
15 | )
16 |
17 | type Data struct {
18 | Tokens []string `json:"tokens"`
19 | }
20 |
21 | type queryNFTSOwnedResponse struct {
22 | Data Data `json:"data"`
23 | }
24 |
25 | func GetQueryCmd() *cobra.Command {
26 | cmd := &cobra.Command{
27 | Use: "sloths",
28 | Short: "Query commands for sloths",
29 | DisableFlagParsing: true,
30 | RunE: client.ValidateCmd,
31 | }
32 |
33 | cmd.AddCommand(QuerySlothsCmd())
34 |
35 | return cmd
36 | }
37 |
38 | func QuerySlothsCmd() *cobra.Command {
39 | cmd := &cobra.Command{
40 | Use: "owned-by [owner]",
41 | Short: "Query sloths owned by an address",
42 | Args: cobra.ExactArgs(1),
43 | RunE: func(cmd *cobra.Command, args []string) error {
44 | owner := args[0]
45 |
46 | node, _ := cmd.Flags().GetString(sdkflags.FlagNode)
47 | nftContract, _ := cmd.Flags().GetString(lazycommandutils.FlagNFTContract)
48 | mainnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagMainnet)
49 | testnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagTestnet)
50 |
51 | if !mainnet && !testnet &&
52 | (node == "" || nftContract == "") {
53 | return fmt.Errorf("missing required flags. Either set --mainnet or --testnet or provide the manual flags (--%s --%s)",
54 | sdkflags.FlagNode, lazycommandutils.FlagNFTContract)
55 | }
56 |
57 | isStargaze := strings.HasPrefix(owner, "stars")
58 | if mainnet {
59 | return fmt.Errorf("mainnet not supported yet")
60 | } else if testnet {
61 | var networkInfo lazycommandutils.StaticICS721NetworkInfo
62 | if isStargaze {
63 | networkInfo = lazycommandutils.ICS721Testnets.Stargaze
64 | } else {
65 | networkInfo = lazycommandutils.ICS721Testnets.LazyChain
66 | }
67 |
68 | nftContract = networkInfo.NFTContract
69 | node = networkInfo.Node
70 |
71 | // Needed because this flag is picked up later by the clientCtx
72 | if err := cmd.Flags().Set(sdkflags.FlagNode, node); err != nil {
73 | return err
74 | }
75 | }
76 |
77 | clientCtx, err := client.GetClientQueryContext(cmd)
78 | if err != nil {
79 | return err
80 | }
81 | queryClient := wasmdtypes.NewQueryClient(clientCtx)
82 | query := fmt.Sprintf(`{"tokens":{"owner":"%s"}}`, owner)
83 | res, err := queryClient.SmartContractState(
84 | cmd.Context(),
85 | &wasmdtypes.QuerySmartContractStateRequest{
86 | Address: nftContract,
87 | QueryData: []byte(query),
88 | },
89 | )
90 | if err != nil {
91 | return err
92 | }
93 |
94 | _ = clientCtx.PrintProto(res)
95 |
96 | queryNFTSStringOutput, err := clientCtx.Codec.MarshalJSON(res)
97 | if err != nil {
98 | return err
99 | }
100 |
101 | var nftsOwnedResponse queryNFTSOwnedResponse
102 | if err := json.Unmarshal(queryNFTSStringOutput, &nftsOwnedResponse); err != nil {
103 | return err
104 | }
105 |
106 | cmd.Printf("%d... sloths... found... for... %s...\n", len(nftsOwnedResponse.Data.Tokens), owner)
107 | for _, nft := range nftsOwnedResponse.Data.Tokens {
108 | cmd.Printf("🦥 #%s\n", nft)
109 | }
110 | if len(nftsOwnedResponse.Data.Tokens) != 0 {
111 | cmd.Println("too... much... work... time... to... 💤")
112 | }
113 |
114 | return nil
115 | },
116 | }
117 |
118 | cmd.Flags().Bool(lazycommandutils.FlagMainnet, false, "Use mainnet values")
119 | cmd.Flags().Bool(lazycommandutils.FlagTestnet, false, "Use testnet values")
120 | cmd.Flags().String(lazycommandutils.FlagNFTContract, "", "NFT contract address (optional if using --testnet or --mainnet)")
121 |
122 | sdkflags.AddQueryFlagsToCmd(cmd)
123 | nodeFlag := cmd.Flags().Lookup(sdkflags.FlagNode)
124 | nodeFlag.DefValue = ""
125 | nodeFlag.Usage = "RPC endpoint of chain to query (Stargaze or LazyChain)"
126 |
127 | return cmd
128 | }
129 |
--------------------------------------------------------------------------------
/interchaintest/local-interchain/localinterslothchain.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "cosmossdk.io/math"
5 | "fmt"
6 | "github.com/Lazychain/lazychain/interchaintest/utils"
7 | "github.com/strangelove-ventures/interchaintest/v8"
8 | "github.com/strangelove-ventures/interchaintest/v8/ibc"
9 | "github.com/strangelove-ventures/interchaintest/v8/testutil"
10 | "os"
11 | "os/signal"
12 | "syscall"
13 | )
14 |
15 | const mnemonic = "curve govern feature draw giggle one enemy shop wonder cross castle oxygen business obscure rule detail chaos dirt pause parrot tail lunch merit rely"
16 |
17 | type LocalInterchain struct {
18 | utils.InterchainValues
19 | }
20 |
21 | func main() {
22 | fmt.Println("Running LocalInterchain... 💤")
23 |
24 | interchainValues := LocalInterchain{}
25 | interchainValues.SetupFakeT("LocalInterchain")
26 |
27 | defer func() {
28 | interchainValues.GetFakeT().ActuallyRunCleanups()
29 | }()
30 |
31 | c := make(chan os.Signal)
32 | signal.Notify(c, os.Interrupt, syscall.SIGTERM)
33 | go func() {
34 | <-c
35 | interchainValues.GetFakeT().ActuallyRunCleanups()
36 | os.Exit(1)
37 | }()
38 |
39 | interchainValues.SetupInterchainValues()
40 | interchainValues.TestLocalInterChain()
41 | }
42 |
43 | func (s *LocalInterchain) TestLocalInterChain() {
44 |
45 | slothUser, err := interchaintest.GetAndFundTestUserWithMnemonic(s.Ctx, "user", mnemonic, math.NewInt(10_000_000_000), s.LazyChain)
46 | s.NoError(err)
47 |
48 | sgUser, err := interchaintest.GetAndFundTestUserWithMnemonic(s.Ctx, "user", mnemonic, math.NewInt(10_000_000_000), s.Stargaze)
49 | s.NoError(err)
50 |
51 | celestiaUser, err := interchaintest.GetAndFundTestUserWithMnemonic(s.Ctx, "user", mnemonic, math.NewInt(10_000_000_000), s.Celestia)
52 | s.NoError(err)
53 |
54 | nftSetup := s.DeployNFTSetup(sgUser, slothUser, "./test-artifacts")
55 |
56 | s.NoError(s.Relayer.StartRelayer(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath))
57 | s.TT().Cleanup(
58 | func() {
59 | err := s.Relayer.StopRelayer(s.Ctx, s.RelayerExecRep)
60 | if err != nil {
61 | s.TT().Logf("an error occurred while stopping the relayer: %s", err)
62 | }
63 | },
64 | )
65 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.Stargaze, s.LazyChain))
66 |
67 | celestiaToLazyChainChannel, err := ibc.GetTransferChannel(s.Ctx, s.Relayer, s.RelayerExecRep, s.Celestia.Config().ChainID, s.LazyChain.Config().ChainID)
68 | s.NoError(err)
69 |
70 | slothContainer, err := s.LazyChain.GetNode().DockerClient.ContainerInspect(s.Ctx, s.LazyChain.GetNode().ContainerID())
71 | s.NoError(err)
72 |
73 | stargazeContainer, err := s.Stargaze.GetNode().DockerClient.ContainerInspect(s.Ctx, s.Stargaze.GetNode().ContainerID())
74 | s.NoError(err)
75 |
76 | celestialContainer, err := s.Celestia.GetNode().DockerClient.ContainerInspect(s.Ctx, s.Celestia.GetNode().ContainerID())
77 | s.NoError(err)
78 |
79 | fmt.Println("Local interchain is now running...")
80 | fmt.Println()
81 | fmt.Println("Users, all with the mnemonic:", mnemonic)
82 | fmt.Println("Sloth user address:", slothUser.FormattedAddress())
83 | fmt.Println("Stargaze user address:", sgUser.FormattedAddress())
84 | fmt.Println("Celestia user address:", celestiaUser.FormattedAddress())
85 | fmt.Println()
86 | fmt.Println("LazyChain chain-id:", s.LazyChain.Config().ChainID)
87 | fmt.Printf("LazyChain RPC address: tcp://localhost:%s\n", slothContainer.NetworkSettings.Ports["26657/tcp"][0].HostPort)
88 | fmt.Println("Stargaze chain-id:", s.Stargaze.Config().ChainID)
89 | fmt.Printf("Stargaze RPC address: tcp://localhost:%s\n", stargazeContainer.NetworkSettings.Ports["26657/tcp"][0].HostPort)
90 | fmt.Println("Celestia chain-id:", s.Celestia.Config().ChainID)
91 | fmt.Printf("Celestia RPC address: tcp://localhost:%s\n", celestialContainer.NetworkSettings.Ports["26657/tcp"][0].HostPort)
92 | fmt.Println()
93 | fmt.Println("ICS721 setup deployed")
94 | fmt.Println("ICS721 contract on Stargaze:", nftSetup.SGICS721Contract)
95 | fmt.Println("ICS721 contract on Sloth chain:", nftSetup.LazyChainICS721Contract)
96 | fmt.Println("Sloth contract:", nftSetup.CelestineSlothsContract)
97 | fmt.Println("Stargaze to Sloth channel:", nftSetup.SGChannel)
98 | fmt.Println("Sloth chain to Stargaze channel:", nftSetup.LazyChainChannel)
99 | fmt.Println("Celestia to Sloth channel:", celestiaToLazyChainChannel.ChannelID)
100 | fmt.Println()
101 | fmt.Println("Press Ctrl+C to stop...")
102 |
103 | select {}
104 | }
105 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/lazycommandutils/helper.go:
--------------------------------------------------------------------------------
1 | package lazycommandutils
2 |
3 | import (
4 | "bufio"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "os"
9 | "time"
10 |
11 | "github.com/spf13/pflag"
12 |
13 | "github.com/cosmos/cosmos-sdk/client"
14 | "github.com/cosmos/cosmos-sdk/client/input"
15 | "github.com/cosmos/cosmos-sdk/client/tx"
16 | sdk "github.com/cosmos/cosmos-sdk/types"
17 | authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
18 | )
19 |
20 | // SendAndWaitForTx is a helper function to send a series of messages and wait for a transaction to be included in a block.
21 | // The code here is copied of the tx.go file from the Cosmos SDK and modified to wait for the transaction to be included and then return the response
22 | func SendAndWaitForTx(clientCtx client.Context, flagSet *pflag.FlagSet, msgs ...sdk.Msg) error {
23 | txf, err := tx.NewFactoryCLI(clientCtx, flagSet)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | // Validate all msgs before generating or broadcasting the tx.
29 | // We were calling ValidateBasic separately in each CLI handler before.
30 | // Right now, we're factorizing that call inside this function.
31 | // ref: https://github.com/cosmos/cosmos-sdk/pull/9236#discussion_r623803504
32 | for _, msg := range msgs {
33 | m, ok := msg.(sdk.HasValidateBasic)
34 | if !ok {
35 | continue
36 | }
37 |
38 | if err := m.ValidateBasic(); err != nil {
39 | return err
40 | }
41 | }
42 |
43 | if clientCtx.GenerateOnly {
44 | return txf.PrintUnsignedTx(clientCtx, msgs...)
45 | }
46 |
47 | txf, err = txf.Prepare(clientCtx)
48 | if err != nil {
49 | return err
50 | }
51 |
52 | if txf.SimulateAndExecute() || clientCtx.Simulate {
53 | if clientCtx.Offline {
54 | return errors.New("cannot estimate gas in offline mode")
55 | }
56 |
57 | _, adjusted, err := tx.CalculateGas(clientCtx, txf, msgs...)
58 | if err != nil {
59 | return err
60 | }
61 |
62 | txf = txf.WithGas(adjusted)
63 | _, _ = fmt.Fprintf(os.Stderr, "%s\n", tx.GasEstimateResponse{GasEstimate: txf.Gas()})
64 | }
65 |
66 | if clientCtx.Simulate {
67 | return nil
68 | }
69 |
70 | unsignedTx, err := txf.BuildUnsignedTx(msgs...)
71 | if err != nil {
72 | return err
73 | }
74 |
75 | if !clientCtx.SkipConfirm {
76 | encoder := clientCtx.TxConfig.TxJSONEncoder()
77 | if encoder == nil {
78 | return errors.New("failed to encode transaction: tx json encoder is nil")
79 | }
80 |
81 | txBytes, err := encoder(unsignedTx.GetTx())
82 | if err != nil {
83 | return fmt.Errorf("failed to encode transaction: %w", err)
84 | }
85 |
86 | if err := clientCtx.PrintRaw(json.RawMessage(txBytes)); err != nil {
87 | _, _ = fmt.Fprintf(os.Stderr, "error: %v\n%s\n", err, txBytes)
88 | }
89 |
90 | buf := bufio.NewReader(os.Stdin)
91 | ok, err := input.GetConfirmation("confirm transaction before signing and broadcasting", buf, os.Stderr)
92 | if err != nil {
93 | _, _ = fmt.Fprintf(os.Stderr, "error: %v\ncanceled transaction\n", err)
94 | return err
95 | }
96 | if !ok {
97 | _, _ = fmt.Fprintln(os.Stderr, "canceled transaction")
98 | return nil
99 | }
100 | }
101 |
102 | if err = tx.Sign(clientCtx.CmdContext, txf, clientCtx.FromName, unsignedTx, true); err != nil {
103 | return err
104 | }
105 |
106 | txBytes, err := clientCtx.TxConfig.TxEncoder()(unsignedTx.GetTx())
107 | if err != nil {
108 | return err
109 | }
110 |
111 | // broadcast to a CometBFT node
112 | res, err := clientCtx.BroadcastTx(txBytes)
113 | if err != nil {
114 | return err
115 | }
116 |
117 | if res.Code != 0 {
118 | return fmt.Errorf(res.RawLog)
119 | }
120 | try := 1
121 | maxTries := 200
122 | for {
123 | if try > maxTries {
124 | return fmt.Errorf("failed to wait for %s. Maximum number of tries reached", res.TxHash)
125 | }
126 |
127 | txResp, err := authtx.QueryTx(clientCtx, res.TxHash)
128 | if err != nil {
129 | fmt.Print("\033[G\033[K") // move the cursor left and clear the line
130 | fmt.Printf("🦥 taking... soo... long... for... %s - attempt %d/%d 💤", res.TxHash, try, maxTries)
131 | time.Sleep(500 * time.Millisecond)
132 | try++
133 | continue
134 | }
135 |
136 | if txResp.Code != 0 {
137 | panic(fmt.Errorf("transaction failed: %s", txResp.RawLog))
138 | }
139 |
140 | fmt.Print("\033[G\033[K") // move the cursor left and clear the line
141 | fmt.Printf("🦥 tx... %s... completed...\n", res.TxHash)
142 |
143 | // TODO: Add a flag for IBC transfers to wait for the packet to be received
144 |
145 | return nil
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/interchaintest/ics721/ics721_test.go:
--------------------------------------------------------------------------------
1 | package ics721
2 |
3 | import (
4 | "cosmossdk.io/math"
5 | "github.com/Lazychain/lazychain/interchaintest/utils"
6 | "github.com/strangelove-ventures/interchaintest/v8"
7 | "github.com/strangelove-ventures/interchaintest/v8/testutil"
8 | testifysuite "github.com/stretchr/testify/suite"
9 | "testing"
10 | )
11 |
12 | type ICS721TestSuite struct {
13 | utils.E2ETestSuite
14 | }
15 |
16 | func TestICS721TestSuite(t *testing.T) {
17 | testifysuite.Run(t, new(ICS721TestSuite))
18 | }
19 |
20 | func (s *ICS721TestSuite) TestICS721() {
21 | users := interchaintest.GetAndFundTestUsers(s.T(), s.Ctx, s.T().Name(), math.NewInt(10_000_000_000), s.Stargaze, s.LazyChain)
22 | sgUser, slothUser := users[0], users[1]
23 |
24 | nftSetup := s.DeployNFTSetup(sgUser, slothUser, "../test-artifacts")
25 |
26 | s.NoError(s.Relayer.StartRelayer(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath))
27 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.Stargaze, s.LazyChain))
28 |
29 | classID, lazyChainCW721 := s.TransferSlothToLazyChain(
30 | nftSetup,
31 | sgUser,
32 | slothUser,
33 | "1")
34 | _ = classID // wasm.lazy1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtq8xhtac/channel-2/stars14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srsl6sm
35 | // wasm.lazyics721/slothchannel/starscontract
36 |
37 | s.AssertPacketRelayed(s.Stargaze, nftSetup.LazyChainPort, nftSetup.LazyChainChannel, 1)
38 |
39 | tokens := s.AllNFTs(s.LazyChain, lazyChainCW721)
40 | s.Len(tokens, 1)
41 | s.Equal("1", tokens[0]) // 🦥🚀
42 |
43 | s.TransferSlothToStargaze(nftSetup, slothUser, sgUser, "1", lazyChainCW721)
44 | }
45 |
46 | func (s *ICS721TestSuite) TestIncomingProxy() {
47 | users := interchaintest.GetAndFundTestUsers(s.T(), s.Ctx, s.T().Name(), math.NewInt(10_000_000_000), s.Stargaze, s.LazyChain)
48 | sgUser, slothUser := users[0], users[1]
49 |
50 | nftSetup := s.DeployNFTSetup(sgUser, slothUser, "../test-artifacts")
51 | nonSlothCW721CodeID := s.StoreCW721(s.Stargaze, sgUser.KeyName(), "../test-artifacts")
52 | nonSlothContractAddress := s.InstantiateCW721(nonSlothCW721CodeID, sgUser.KeyName(), "NOT A SLOTH", "NAS", sgUser.FormattedAddress())
53 |
54 | s.MintNFTs(nonSlothContractAddress, sgUser.KeyName(), sgUser.FormattedAddress(), []string{"1", "2", "3"})
55 |
56 | s.NoError(s.Relayer.StartRelayer(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath))
57 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.Stargaze, s.LazyChain))
58 |
59 | err := s.TransferNFT(s.Stargaze, sgUser, slothUser, "1", nonSlothContractAddress, nftSetup.SGICS721Contract, nftSetup.SGChannel)
60 | s.NoError(err) // The transfer message itself on stargaze should succeed
61 |
62 | s.NoError(testutil.WaitForBlocks(s.Ctx, 10, s.Stargaze, s.LazyChain, s.Celestia))
63 |
64 | // Check that the token fails to actually transfer
65 | s.AssertPacketRelayed(s.Stargaze, nftSetup.LazyChainPort, nftSetup.LazyChainChannel, 1)
66 |
67 | cmd := "message.action='/ibc.core.channel.v1.MsgRecvPacket'"
68 | // cmd := "message.action=/ibc.core.channel.v1.MsgRecvPacket"
69 | txSearchRes, err := s.QueryTxsByEvents(s.LazyChain, 1, 10, cmd, "")
70 | s.Require().NoError(err)
71 | s.Require().Len(txSearchRes.Txs, 1)
72 |
73 | errorMessage, isFound := s.ExtractValueFromEvents(
74 | txSearchRes.Txs[0].Events,
75 | "write_acknowledgement",
76 | "packet_ack",
77 | )
78 |
79 | s.Require().True(isFound)
80 | s.Require().Equal(errorMessage, "{\"error\":\"codespace: wasm, code: 5\"}")
81 |
82 | type Response struct {
83 | Data [][]string `json:"data"`
84 | }
85 | var resp Response
86 | s.NoError(s.LazyChain.QueryContract(s.Ctx, nftSetup.LazyChainICS721Contract, "{\"nft_contracts\": {}}", &resp))
87 | s.Len(resp.Data, 0)
88 | // Update the incoming proxy with the non-sloth contract address to verify it works after the update
89 | s.MigrateICS721IncomingProxy(
90 | s.LazyChain,
91 | slothUser.KeyName(),
92 | "../test-artifacts",
93 | nftSetup.LazyChainICS721IncomingProxyContract,
94 | nonSlothContractAddress,
95 | nftSetup.LazyChainICS721Contract,
96 | nftSetup.LazyChainChannel,
97 | )
98 |
99 | err = s.TransferNFT(s.Stargaze, sgUser, slothUser, "1", nonSlothContractAddress, nftSetup.SGICS721Contract, nftSetup.SGChannel)
100 | s.NoError(err)
101 |
102 | s.NoError(testutil.WaitForBlocks(s.Ctx, 10, s.Stargaze, s.LazyChain, s.Celestia))
103 |
104 | // Check that the token fails to actually transfer
105 | s.AssertPacketRelayed(s.Stargaze, nftSetup.LazyChainPort, nftSetup.LazyChainChannel, 1)
106 |
107 | s.NoError(s.LazyChain.QueryContract(s.Ctx, nftSetup.LazyChainICS721Contract, "{\"nft_contracts\": {}}", &resp))
108 | s.Len(resp.Data, 1)
109 |
110 | tokens := s.AllNFTs(s.LazyChain, resp.Data[0][1])
111 | s.Len(tokens, 1)
112 | s.Equal("1", tokens[0]) // 🦥🚀
113 | }
114 |
--------------------------------------------------------------------------------
/init.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | # set variables for the chain
6 | VALIDATOR_NAME=validator1
7 | CHAIN_ID=sloth
8 | BINARY=lazychaind
9 | KEY_NAME=slothy
10 | TOKEN_AMOUNT=10000000000000000000000000stake
11 | STAKING_AMOUNT=1000000000stake
12 | RELAYER_ADDRESS=lazy1avl4q6s02pss5q2ftrkjqaft3jk75q4ldesnwe
13 |
14 | echo -e "\n Deleting existing $BINARY data... \n"
15 | rm -rf ~/.lazychain/
16 |
17 | echo -e "\n Installing the chain...\n"
18 | make install
19 |
20 | # query the DA Layer start height, in this case we are querying
21 | # an RPC endpoint provided by Celestia Labs. The RPC endpoint is
22 | # to allow users to interact with Celestia's core network by querying
23 | # the node's state and broadcasting transactions on the Celestia
24 | # network.
25 |
26 | # Mocha
27 | DA_BLOCK_HEIGHT=$(curl public-celestia-mocha4-consensus.numia.xyz:26657/block |jq -r '.result.block.header.height')
28 | AUTH_TOKEN=$(celestia light auth write --p2p.network mocha)
29 | # Arabica
30 | #DA_BLOCK_HEIGHT=$(curl https://rpc.celestia-arabica-11.com/block |jq -r '.result.block.header.height')
31 | #AUTH_TOKEN=$(celestia light auth write --p2p.network arabica)
32 |
33 | echo -e "\n Your DA_BLOCK_HEIGHT is $DA_BLOCK_HEIGHT \n"
34 | echo -e "\n Your DA AUTH_TOKEN is $AUTH_TOKEN \n"
35 |
36 | # reset any existing genesis/chain data
37 | $BINARY tendermint unsafe-reset-all
38 | $BINARY init $VALIDATOR_NAME --chain-id $CHAIN_ID
39 |
40 | # update $BINARY configuration files to set chain details and enable necessary settings
41 | # the sed commands here are editing various configuration settings for the $BINARY instance
42 | # such as setting minimum gas prices, enabling the api, setting the chain id, setting the rpc address,
43 | # adjusting time constants, and setting the denomination for bonds and minting.
44 | sed -i'' -e 's/^minimum-gas-prices *= .*/minimum-gas-prices = "0stake"/' "$HOME"/.lazychain/config/app.toml
45 | sed -i'' -e '/\[api\]/,+3 s/enable *= .*/enable = true/' "$HOME"/.lazychain/config/app.toml
46 | sed -i'' -e "s/^chain-id *= .*/chain-id = \"$CHAIN_ID\"/" "$HOME"/.lazychain/config/client.toml
47 | sed -i'' -e '/\[rpc\]/,+3 s/laddr *= .*/laddr = "tcp:\/\/0.0.0.0:26657"/' "$HOME"/.lazychain/config/config.toml
48 | sed -i'' -e 's/"time_iota_ms": "1000"/"time_iota_ms": "10"/' "$HOME"/.lazychain/config/genesis.json
49 | sed -i'' -e 's/bond_denom": ".*"/bond_denom": "stake"/' "$HOME"/.lazychain/config/genesis.json
50 | sed -i'' -e 's/mint_denom": ".*"/mint_denom": "stake"/' "$HOME"/.lazychain/config/genesis.json
51 |
52 | # add a key to keyring-backend test
53 | $BINARY keys add $KEY_NAME --keyring-backend test
54 |
55 | # add a genesis account
56 | $BINARY genesis add-genesis-account $KEY_NAME $TOKEN_AMOUNT --keyring-backend test
57 | $BINARY genesis add-genesis-account $RELAYER_ADDRESS $TOKEN_AMOUNT
58 |
59 | # set the staking amounts in the genesis transaction
60 | $BINARY genesis gentx $KEY_NAME $STAKING_AMOUNT --chain-id $CHAIN_ID --keyring-backend test
61 |
62 | # collect gentxs
63 | $BINARY genesis collect-gentxs
64 |
65 | # copy centralized sequencer address into genesis.json
66 | # Note: validator and sequencer are used interchangeably here
67 | ADDRESS=$(jq -r '.address' ~/.lazychain/config/priv_validator_key.json)
68 | PUB_KEY=$(jq -r '.pub_key' ~/.lazychain/config/priv_validator_key.json)
69 | jq --argjson pubKey "$PUB_KEY" '.consensus["validators"]=[{"address": "'$ADDRESS'", "pub_key": $pubKey, "power": "1", "name": "Rollkit Sequencer"}]' ~/.lazychain/config/genesis.json > temp.json && mv temp.json ~/.lazychain/config/genesis.json
70 | PUB_KEY_VALUE=$(jq -r '.pub_key .value' ~/.lazychain/config/priv_validator_key.json)
71 | jq --arg pubKey $PUB_KEY_VALUE '.app_state .sequencer["sequencers"]=[{"name": "test-1", "consensus_pubkey": {"@type": "/cosmos.crypto.ed25519.PubKey","key":$pubKey}}]' ~/.lazychain/config/genesis.json >temp.json && mv temp.json ~/.lazychain/config/genesis.json
72 |
73 |
74 | # create a restart-testnet.sh file to restart the chain later
75 | [ -f restart-$BINARY.sh ] && rm restart-$BINARY.sh
76 | echo "DA_BLOCK_HEIGHT=$DA_BLOCK_HEIGHT" >> restart-$BINARY.sh
77 | echo "AUTH_TOKEN=$AUTH_TOKEN" >> restart-$BINARY.sh
78 |
79 | echo "$BINARY start --rollkit.lazy_aggregator --rollkit.aggregator --rollkit.da_auth_token=\$AUTH_TOKEN --rollkit.da_namespace 00000000000000000000000000000000000000000008e5f679bf7116cb --rollkit.da_start_height \$DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:26657 --grpc.address 127.0.0.1:9290 --p2p.laddr \"0.0.0.0:26656\" --minimum-gas-prices="0stake" --api.enable --api.enabled-unsafe-cors" >> restart-$BINARY.sh
80 |
81 | # start the chain
82 | $BINARY genesis validate
83 | $BINARY start --rollkit.aggregator --rollkit.da_auth_token=$AUTH_TOKEN --rollkit.da_namespace 00000000000000000000000000000000000000000008e5f679bf7116cb --rollkit.da_start_height $DA_BLOCK_HEIGHT --rpc.laddr tcp://127.0.0.1:26657 --grpc.address 127.0.0.1:9290 --p2p.laddr "0.0.0.0:26656" --minimum-gas-prices="0stake" --api.enable --api.enabled-unsafe-cors
--------------------------------------------------------------------------------
/app/sim_bench_test.go:
--------------------------------------------------------------------------------
1 | package app_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "testing"
7 |
8 | "github.com/stretchr/testify/require"
9 |
10 | "github.com/cosmos/cosmos-sdk/client/flags"
11 | "github.com/cosmos/cosmos-sdk/server"
12 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
13 | simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
14 | "github.com/cosmos/cosmos-sdk/x/simulation"
15 | simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
16 |
17 | cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
18 |
19 | "github.com/Lazychain/lazychain/app"
20 | )
21 |
22 | // Profile with:
23 | // `go test -benchmem -run=^$ -bench ^BenchmarkFullAppSimulation ./app -Commit=true -cpuprofile cpu.out`
24 | func BenchmarkFullAppSimulation(b *testing.B) {
25 | b.ReportAllocs()
26 |
27 | config := simcli.NewConfigFromFlags()
28 | config.ChainID = SimAppChainID
29 |
30 | db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "goleveldb-app-sim", "Simulation", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
31 | if err != nil {
32 | b.Fatalf("simulation setup failed: %s", err.Error())
33 | }
34 |
35 | if skip {
36 | b.Skip("skipping benchmark application simulation")
37 | }
38 |
39 | defer func() {
40 | require.NoError(b, db.Close())
41 | require.NoError(b, os.RemoveAll(dir))
42 | }()
43 |
44 | appOptions := make(simtestutil.AppOptionsMap, 0)
45 | appOptions[flags.FlagHome] = app.DefaultNodeHome
46 | appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue
47 |
48 | bApp, err := app.New(logger, db, nil, true, appOptions, interBlockCacheOpt())
49 | require.NoError(b, err)
50 | require.Equal(b, app.Name, bApp.Name())
51 |
52 | // run randomized simulation
53 | _, simParams, simErr := simulation.SimulateFromSeed(
54 | b,
55 | os.Stdout,
56 | bApp.BaseApp,
57 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
58 | simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
59 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
60 | app.BlockedAddresses(),
61 | config,
62 | bApp.AppCodec(),
63 | )
64 |
65 | // export state and simParams before the simulation error is checked
66 | if err = simtestutil.CheckExportSimulation(bApp, config, simParams); err != nil {
67 | b.Fatal(err)
68 | }
69 |
70 | if simErr != nil {
71 | b.Fatal(simErr)
72 | }
73 |
74 | if config.Commit {
75 | simtestutil.PrintStats(db)
76 | }
77 | }
78 |
79 | func BenchmarkInvariants(b *testing.B) {
80 | b.ReportAllocs()
81 |
82 | config := simcli.NewConfigFromFlags()
83 | config.ChainID = SimAppChainID
84 |
85 | db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-invariant-bench", "Simulation", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
86 | if err != nil {
87 | b.Fatalf("simulation setup failed: %s", err.Error())
88 | }
89 |
90 | if skip {
91 | b.Skip("skipping benchmark application simulation")
92 | }
93 |
94 | config.AllInvariants = false
95 |
96 | defer func() {
97 | require.NoError(b, db.Close())
98 | require.NoError(b, os.RemoveAll(dir))
99 | }()
100 |
101 | appOptions := make(simtestutil.AppOptionsMap, 0)
102 | appOptions[flags.FlagHome] = app.DefaultNodeHome
103 | appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue
104 |
105 | bApp, err := app.New(logger, db, nil, true, appOptions, interBlockCacheOpt())
106 | require.NoError(b, err)
107 | require.Equal(b, app.Name, bApp.Name())
108 |
109 | // run randomized simulation
110 | _, simParams, simErr := simulation.SimulateFromSeed(
111 | b,
112 | os.Stdout,
113 | bApp.BaseApp,
114 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
115 | simtypes.RandomAccounts, // Replace with own random account function if using keys other than secp256k1
116 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
117 | app.BlockedAddresses(),
118 | config,
119 | bApp.AppCodec(),
120 | )
121 |
122 | // export state and simParams before the simulation error is checked
123 | if err = simtestutil.CheckExportSimulation(bApp, config, simParams); err != nil {
124 | b.Fatal(err)
125 | }
126 |
127 | if simErr != nil {
128 | b.Fatal(simErr)
129 | }
130 |
131 | if config.Commit {
132 | simtestutil.PrintStats(db)
133 | }
134 |
135 | ctx := bApp.NewContextLegacy(true, cmtproto.Header{Height: bApp.LastBlockHeight() + 1})
136 |
137 | // 3. Benchmark each invariant separately
138 | //
139 | // NOTE: We use the crisis keeper as it has all the invariants registered with
140 | // their respective metadata which makes it useful for testing/benchmarking.
141 | for _, cr := range bApp.CrisisKeeper.Routes() {
142 | cr := cr
143 | b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) {
144 | if res, stop := cr.Invar(ctx); stop {
145 | b.Fatalf(
146 | "broken invariant at block %d of %d\n%s",
147 | ctx.BlockHeight()-1, config.NumBlocks, res,
148 | )
149 | }
150 | })
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/app/wasm.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/CosmWasm/wasmd/x/wasm"
7 | wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
8 | wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
9 | ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee"
10 | porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types"
11 |
12 | storetypes "cosmossdk.io/store/types"
13 |
14 | "github.com/cosmos/cosmos-sdk/client"
15 | "github.com/cosmos/cosmos-sdk/runtime"
16 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
17 | "github.com/cosmos/cosmos-sdk/x/auth/ante"
18 | "github.com/cosmos/cosmos-sdk/x/auth/posthandler"
19 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
20 | distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
21 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
22 | )
23 |
24 | // AllCapabilities returns all capabilities available with the current wasmvm
25 | // See https://github.com/CosmWasm/cosmwasm/blob/main/docs/CAPABILITIES-BUILT-IN.md
26 | // This functionality is going to be moved upstream: https://github.com/CosmWasm/wasmvm/issues/425
27 | func AllCapabilities() []string {
28 | return []string{
29 | "iterator",
30 | "staking",
31 | "stargate",
32 | "cosmwasm_1_1",
33 | "cosmwasm_1_2",
34 | "cosmwasm_1_3",
35 | "cosmwasm_1_4",
36 | }
37 | }
38 |
39 | // registerWasmModules register CosmWasm keepers and non dependency inject modules.
40 | func (app *LazyApp) registerWasmModules(
41 | appOpts servertypes.AppOptions,
42 | wasmOpts ...wasmkeeper.Option,
43 | ) (porttypes.IBCModule, error) {
44 | // set up non depinject support modules store keys
45 | if err := app.RegisterStores(
46 | storetypes.NewKVStoreKey(wasmtypes.StoreKey),
47 | ); err != nil {
48 | panic(err)
49 | }
50 |
51 | scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName)
52 |
53 | wasmConfig, err := wasm.ReadWasmConfig(appOpts)
54 | if err != nil {
55 | return nil, fmt.Errorf("error while reading wasm config: %s", err)
56 | }
57 |
58 | // The last arguments can contain custom message handlers, and custom query handlers,
59 | // if we want to allow any custom callbacks
60 | app.WasmKeeper = wasmkeeper.NewKeeper(
61 | app.AppCodec(),
62 | runtime.NewKVStoreService(app.GetKey(wasmtypes.StoreKey)),
63 | app.AccountKeeper,
64 | app.BankKeeper,
65 | app.StakingKeeper,
66 | distrkeeper.NewQuerier(app.DistrKeeper),
67 | app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware
68 | app.IBCKeeper.ChannelKeeper,
69 | app.IBCKeeper.PortKeeper,
70 | scopedWasmKeeper,
71 | app.TransferKeeper,
72 | app.MsgServiceRouter(),
73 | app.GRPCQueryRouter(),
74 | DefaultNodeHome,
75 | wasmConfig,
76 | AllCapabilities(),
77 | authtypes.NewModuleAddress(govtypes.ModuleName).String(),
78 | wasmOpts...,
79 | )
80 |
81 | // register IBC modules
82 | if err := app.RegisterModules(
83 | wasm.NewAppModule(
84 | app.AppCodec(),
85 | &app.WasmKeeper,
86 | app.StakingKeeper,
87 | app.AccountKeeper,
88 | app.BankKeeper,
89 | app.MsgServiceRouter(),
90 | app.GetSubspace(wasmtypes.ModuleName),
91 | )); err != nil {
92 | return nil, err
93 | }
94 |
95 | if err := app.setAnteHandler(app.txConfig, wasmConfig, app.GetKey(wasmtypes.StoreKey)); err != nil {
96 | return nil, err
97 | }
98 |
99 | if manager := app.SnapshotManager(); manager != nil {
100 | err := manager.RegisterExtensions(
101 | wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmKeeper),
102 | )
103 | if err != nil {
104 | return nil, fmt.Errorf("failed to register snapshot extension: %s", err)
105 | }
106 | }
107 | app.ScopedWasmKeeper = scopedWasmKeeper
108 |
109 | if err := app.setPostHandler(); err != nil {
110 | return nil, err
111 | }
112 |
113 | // Create fee enabled wasm ibc Stack
114 | var wasmStack porttypes.IBCModule
115 | wasmStack = wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCFeeKeeper)
116 | wasmStack = ibcfee.NewIBCMiddleware(wasmStack, app.IBCFeeKeeper)
117 |
118 | return wasmStack, nil
119 | }
120 |
121 | func (app *LazyApp) setPostHandler() error {
122 | postHandler, err := posthandler.NewPostHandler(
123 | posthandler.HandlerOptions{},
124 | )
125 | if err != nil {
126 | return err
127 | }
128 | app.SetPostHandler(postHandler)
129 | return nil
130 | }
131 |
132 | func (app *LazyApp) setAnteHandler(txConfig client.TxConfig, wasmConfig wasmtypes.WasmConfig, txCounterStoreKey *storetypes.KVStoreKey) error {
133 | anteHandler, err := NewAnteHandler(
134 | HandlerOptions{
135 | HandlerOptions: ante.HandlerOptions{
136 | AccountKeeper: app.AccountKeeper,
137 | BankKeeper: app.BankKeeper,
138 | SignModeHandler: txConfig.SignModeHandler(),
139 | FeegrantKeeper: app.FeeGrantKeeper,
140 | SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
141 | },
142 | IBCKeeper: app.IBCKeeper,
143 | WasmConfig: &wasmConfig,
144 | WasmKeeper: &app.WasmKeeper,
145 | TXCounterStoreService: runtime.NewKVStoreService(txCounterStoreKey),
146 | CircuitKeeper: &app.CircuitBreakerKeeper,
147 | },
148 | )
149 | if err != nil {
150 | return fmt.Errorf("failed to create AnteHandler: %s", err)
151 | }
152 |
153 | // Set the AnteHandler for the app
154 | app.SetAnteHandler(anteHandler)
155 | return nil
156 | }
157 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LazyChain 🦥
2 |
3 | LM... 🦥💤
4 |
5 | ## Installation
6 |
7 | ```bash
8 | $ make install
9 | ```
10 |
11 | ## Interchaintest
12 |
13 | The interchaintest directory contains an e2e test suite for the LazyChain IBC setup:
14 | - LazyChain
15 | - Stargaze
16 | - Celestia
17 |
18 | The test suite uses Interchaintest to spin up a full environment with ICS721 and all you need to test the full
19 | sloth journey end-to-end.
20 |
21 | First you need to build the local docker image:
22 | ```bash
23 | $ make local-docker
24 | ```
25 |
26 | > You can also specify the image with environment variables `LAZYCHAIN_IMAGE_REPOSITORY` and `LAZYCHAIN_IMAGE_VERSION`.
27 | > For instance, you can run the latest built in CI with `LAZYCHAIN_IMAGE_REPOSITORY=ghcr.io/Lazychain/lazychain` and `LAZYCHAIN_IMAGE_VERSION=latest`.
28 |
29 | You can run the test suite with the following command:
30 | ```bash
31 | $ cd interchaintest
32 | $ go test -v -p 1 ./...
33 | ```
34 |
35 | ### Run a lazy 💤 local interlazychain environment
36 |
37 | The repo has a very lazy option if you want to run a full local environment with a single command.
38 |
39 | The environment consists of:
40 | - LazyChain (duh... 🦥)
41 | - Stargaze
42 | - Celestia
43 | - Relayer
44 |
45 | The environment sets up all the above components and configures:
46 | - User with funds on all chains (mnemonic: `curve govern feature draw giggle one enemy shop wonder cross castle oxygen business obscure rule detail chaos dirt pause parrot tail lunch merit rely`)
47 | - An NFT contract on Stargaze (to mimic the Sloth collection)
48 | - ICS721 deployed on Stargaze and LazyChain
49 | - IBC connection between LazyChain and Stargaze
50 | - Channels for both ICS20 between all chains
51 | - Channels for ICS721 between LazyChain and Stargaze
52 |
53 | To transfer, see the command section below.
54 |
55 | There are some pre-requisites to run the interlazychain environment:
56 | - Go
57 | - Docker
58 | - lazychain:local image built (`make local-docker`)
59 |
60 | To run it:
61 | ```bash
62 | $ cd interchaintest
63 | $ go run ./local-interchain
64 | ```
65 |
66 | It takes a while to spin up everything, deploy the contracts and whatnot, but once it is finished it will output something like following:
67 | ```shell
68 | Users, all with the mnemonic: curve govern feature draw giggle one enemy shop wonder cross castle oxygen business obscure rule detail chaos dirt pause parrot tail lunch merit rely
69 | Sloth user address: lazy1ct9r7k20kp7z2m90066h6h2anq0rvmmrhwcl0w
70 | Stargaze user address: stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk
71 | Celestia user address: celestia1ct9r7k20kp7z2m90066h6h2anq0rvmmrtnldz2
72 |
73 | LazyChain chain-id: lazytestchain-1
74 | LazyChain RPC address: tcp://localhost:63921
75 | Stargaze chain-id: stargazetest-1
76 | Stargaze RPC address: tcp://localhost:63910
77 | Celestia chain-id: celestiatest-1
78 | Celestia RPC address: tcp://localhost:63915
79 |
80 | ICS721 setup deployed
81 | ICS721 contract on Stargaze: stars1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq096cja
82 | ICS721 contract on Sloth chain: lazy1wug8sewp6cedgkmrmvhl3lf3tulagm9hnvy8p0rppz9yjw0g4wtq8xhtac
83 | Sloth contract: stars14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srsl6sm
84 | Stargaze to Sloth channel: channel-1
85 | Sloth chain to Stargaze channel: channel-2
86 | Celestia to Sloth channel: channel-0
87 |
88 | Press Ctrl+C to stop...
89 | ```
90 |
91 | ### Running just LazyChain locally
92 |
93 | You can also spin up LazyChain alone (without using interhcaintest and docker) using the `init.sh` script.
94 |
95 | Prerequisites:
96 | - `jq` installed
97 | - `LazyChain` installed (install with `make install`)
98 | - A running celestia light client on mocha testnet (see [Setting up a Celestia light node](https://docs.celestia.org/nodes/light-node))
99 |
100 | ```Bash
101 | $ ./init.sh
102 | ```
103 |
104 | ### Commands
105 |
106 | The `lazychaind` binary has some built-in commands to interact directly with the sloths.
107 | - `lazychaind tx sloths transfer [from] [to] [nft-id] [--flags]`
108 | - `lazychaind q sloths owned-by [address] [--flags]`
109 |
110 | Both commands have a `--mainnet` and `--testnet` flag to fill in all the necessary flags for the respective chain.
111 | They are not implemented at the moment, but will be once testnet and mainnet are live.
112 |
113 | #### Transfer transaction
114 |
115 | This command will transfer an NFT from one chain to another using ICS721 (it supports both Stargaze->LazyChain and LazyChain->Stargaze).
116 | It does not currently support transfer between two addresses on the same chain.
117 |
118 | With `--mainnet` or `--testnet` flag from Stargaze to LazyChain
119 | ```bash
120 | $ lazychaind tx sloths transfer stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk lazy1u0g894r00fu3rnh7ft35yzk9smyaxscyhax3vs 1 --testnet
121 | ```
122 |
123 | With `--mainnet` or `--testnet` flag from LazyChain to Stargaze
124 | ```bash
125 | $ lazychaind tx sloths transfer lazy1u0g894r00fu3rnh7ft35yzk9smyaxscyhax3vs stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk 1 --testnet
126 | ```
127 |
128 | With all override flags (necessary for local interchain environment)
129 | ```bash
130 | $ lazychaind tx sloths transfer stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk lazy1ct9r7k20kp7z2m90066h6h2anq0rvmmrhwcl0w 1 --node tcp://localhost:57023 --chain-id stargazetest-1 --nft-contract stars14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srsl6sm --ics721-contract stars1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq096cja --ics721-channel channel-1 --gas auto --gas-adjustment 1.5 --keyring-backend test
131 | ```
132 |
133 | #### Owned By query
134 |
135 | This command will query all the NFTs owned by a specific address on a specific chain.
136 |
137 | With `--mainnet` or `--testnet` flag:
138 | ```bash
139 | $ lazychaind q sloths owned-by stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk --testnet
140 | ```
141 |
142 | With all override flags (necessary for local interlazychain):
143 | ```bash
144 | $ lazychaind q sloths owned-by stars1ct9r7k20kp7z2m90066h6h2anq0rvmmrw9eqnk --node tcp://localhost:57023 --nft-contract stars14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9srsl6sm
145 | ```
146 | ## 💤
147 | Too... Lazy... To... Write... More... 🦥
148 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/tia/tx.go:
--------------------------------------------------------------------------------
1 | package tia
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | "time"
8 |
9 | transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
10 | clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
11 | "github.com/spf13/cobra"
12 |
13 | sdkmath "cosmossdk.io/math"
14 |
15 | "github.com/cosmos/cosmos-sdk/client"
16 | sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
17 | "github.com/cosmos/cosmos-sdk/client/tx"
18 | sdk "github.com/cosmos/cosmos-sdk/types"
19 |
20 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/lazycommandutils"
21 | )
22 |
23 | func GetTxCmd() *cobra.Command {
24 | cmd := &cobra.Command{
25 | Use: "tia",
26 | Short: "Transaction commands for TIA",
27 | DisableFlagParsing: true,
28 | RunE: client.ValidateCmd,
29 | }
30 |
31 | cmd.AddCommand(TransferCmd())
32 |
33 | return cmd
34 | }
35 |
36 | func TransferCmd() *cobra.Command {
37 | cmd := &cobra.Command{
38 | Use: "transfer [from_address] [to_address] [amount]",
39 | Short: "Transfer TIA tokens between Celestia and LazyChain (both ways)",
40 | Args: cobra.ExactArgs(3),
41 | RunE: func(cmd *cobra.Command, args []string) error {
42 | from := args[0]
43 | to := args[1]
44 | amountStr := args[2]
45 |
46 | node, _ := cmd.Flags().GetString(sdkflags.FlagNode)
47 | chainID, _ := cmd.Flags().GetString(sdkflags.FlagChainID)
48 | // TODO: Fix celestia wait for tx (json: cannot unmarshal string into Go value of type uint8)
49 | // waitForTx, _ := cmd.Flags().GetBool(lazycommandutils.FlagWaitForTx)
50 | waitForTx := false
51 | denom, _ := cmd.Flags().GetString(lazycommandutils.FlagICS20Denom)
52 | ics20Channel, _ := cmd.Flags().GetString(lazycommandutils.FlagICS20Channel)
53 |
54 | mainnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagMainnet)
55 | testnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagTestnet)
56 |
57 | isCelestia := strings.HasPrefix(from, "celestia")
58 | if isCelestia && !strings.HasPrefix(to, "lazy") {
59 | return fmt.Errorf("invalid addresses. Must transfer between Celestia and LazyChain")
60 | }
61 | if !isCelestia && (!strings.HasPrefix(to, "celestia") || !strings.HasPrefix(from, "lazy")) {
62 | return fmt.Errorf("invalid addresses. Must transfer between Celestia and LazyChain")
63 | }
64 |
65 | if !mainnet && !testnet &&
66 | (node == "" || chainID == "" || denom == "") {
67 | return fmt.Errorf("missing required flags. Either set --mainnet or --testnet or provide the manual flags (--%s --%s --%s --%s)",
68 | sdkflags.FlagNode, sdkflags.FlagChainID, lazycommandutils.FlagICS20Denom, lazycommandutils.FlagICS20Channel)
69 | }
70 |
71 | if mainnet || testnet {
72 | // TODO: Remove once mainnet
73 | if mainnet {
74 | return fmt.Errorf("mainnet not supported yet")
75 | }
76 |
77 | var networks lazycommandutils.ICS20Networks
78 | if mainnet {
79 | networks = lazycommandutils.ICS20Mainnets
80 | } else {
81 | networks = lazycommandutils.ICS20Testnets
82 | }
83 |
84 | var networkInfo lazycommandutils.StaticICS20NetworkInfo
85 | if isCelestia {
86 | networkInfo = networks.Celestia
87 | } else {
88 | networkInfo = networks.LazyChain
89 | }
90 |
91 | denom = networkInfo.ICS20Denom
92 | ics20Channel = networkInfo.ICS20Channel
93 | node = networkInfo.Node
94 | // Needed because this flag is picked up later by the clientCtx
95 | if err := cmd.Flags().Set(sdkflags.FlagNode, node); err != nil {
96 | return err
97 | }
98 |
99 | chainID = networkInfo.ChainID
100 | if err := cmd.Flags().Set(sdkflags.FlagChainID, chainID); err != nil {
101 | return err
102 | }
103 |
104 | if err := cmd.Flags().Set(sdkflags.FlagGas, "auto"); err != nil {
105 | return err
106 | }
107 | if err := cmd.Flags().Set(sdkflags.FlagGasAdjustment, "1.5"); err != nil {
108 | return err
109 | }
110 | if err := cmd.Flags().Set(sdkflags.FlagGasPrices, networkInfo.GasPrices); err != nil {
111 | return err
112 | }
113 | }
114 |
115 | amount, err := strconv.ParseInt(amountStr, 10, 64)
116 | if err != nil {
117 | // Try to parse as coin
118 | coin, err := sdk.ParseCoinNormalized(amountStr)
119 | if err != nil {
120 | return err
121 | }
122 |
123 | amount = coin.Amount.Int64()
124 | denom = coin.Denom
125 | }
126 |
127 | now := time.Now()
128 | fiveMinutesLater := now.Add(10 * time.Minute) // TODO: Maybe more...
129 | msg := transfertypes.NewMsgTransfer("transfer", ics20Channel, sdk.NewCoin(denom, sdkmath.NewInt(amount)), from, to, clienttypes.Height{}, uint64(fiveMinutesLater.UnixNano()), "")
130 |
131 | if err := cmd.Flags().Set(sdkflags.FlagFrom, from); err != nil {
132 | return err
133 | }
134 | clientCtx, err := client.GetClientTxContext(cmd)
135 | if err != nil {
136 | return err
137 | }
138 |
139 | if waitForTx {
140 | if err := lazycommandutils.SendAndWaitForTx(clientCtx, cmd.Flags(), msg); err != nil {
141 | return err
142 | }
143 |
144 | fmt.Printf("🦥 lazy... transfer... of... %d%s... to... %s... done...\n", amount, denom, to)
145 | fmt.Printf("🦥 tx... finally... done... time... too... 💤!\n")
146 |
147 | return nil
148 | }
149 |
150 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
151 | },
152 | }
153 |
154 | cmd.Flags().Bool(lazycommandutils.FlagWaitForTx, true, "Wait for transaction to be included in a block")
155 | cmd.Flags().Bool(lazycommandutils.FlagMainnet, false, "Use mainnet values")
156 | cmd.Flags().Bool(lazycommandutils.FlagTestnet, false, "Use testnet values")
157 | cmd.Flags().String(lazycommandutils.FlagICS20Denom, "", "Denom of ICS20 token on sender chain (optional if using --testnet or --mainnet)")
158 |
159 | sdkflags.AddTxFlagsToCmd(cmd)
160 | nodeFlag := cmd.Flags().Lookup(sdkflags.FlagNode)
161 | nodeFlag.Usage = "RPC endpoint of sending chain (Celestia or LazyChain)"
162 | nodeFlag.DefValue = ""
163 |
164 | cmd.Flags().Lookup(sdkflags.FlagChainID).Usage = "Chain ID of sending chain (Stargaze or LazyChain)"
165 |
166 | return cmd
167 | }
168 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 |
3 | BINDIR ?= $(GOPATH)/bin
4 | BINARY_NAME := "lazychaind"
5 | CHAIN_NAME := "lazychain"
6 | VERSION := $(shell echo $(shell git describe --tags) | sed 's/^v//')
7 | COMMIT := $(shell git log -1 --format='%H')
8 | LEDGER_ENABLED ?= true
9 | SDK_PACK := $(shell go list -m github.com/cosmos/cosmos-sdk | sed 's/ /\@/g')
10 | DOCKER := $(shell which docker)
11 | BUILD_DIR ?= $(CURDIR)/build
12 | COSMOS_SDK_VERSION := $(shell go list -m -f '{{ .Version }}' github.com/cosmos/cosmos-sdk)
13 |
14 | export GO111MODULE = on
15 |
16 | # process build tags
17 |
18 | build_tags = netgo
19 | ifeq ($(LEDGER_ENABLED),true)
20 | ifeq ($(OS),Windows_NT)
21 | GCCEXE = $(shell where gcc.exe 2> NUL)
22 | ifeq ($(GCCEXE),)
23 | $(error gcc.exe not installed for ledger support, please install or set LEDGER_ENABLED=false)
24 | else
25 | build_tags += ledger
26 | endif
27 | else
28 | UNAME_S = $(shell uname -s)
29 | ifeq ($(UNAME_S),OpenBSD)
30 | $(warning OpenBSD detected, disabling ledger support (https://github.com/cosmos/cosmos-sdk/issues/1988))
31 | else
32 | GCC = $(shell command -v gcc 2> /dev/null)
33 | ifeq ($(GCC),)
34 | $(error gcc not installed for ledger support, please install or set LEDGER_ENABLED=false)
35 | else
36 | build_tags += ledger
37 | endif
38 | endif
39 | endif
40 | endif
41 |
42 | ifeq (cleveldb,$(findstring cleveldb,$(EMPOWER_BUILD_OPTIONS)))
43 | build_tags += gcc
44 | else ifeq (rocksdb,$(findstring rocksdb,$(EMPOWER_BUILD_OPTIONS)))
45 | build_tags += gcc
46 | endif
47 | build_tags += $(BUILD_TAGS)
48 | build_tags := $(strip $(build_tags))
49 |
50 | whitespace :=
51 | whitespace := $(whitespace) $(whitespace)
52 | comma := ,
53 | build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags))
54 |
55 | # process linker flags
56 |
57 | ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=$(CHAIN_NAME) \
58 | -X github.com/cosmos/cosmos-sdk/version.AppName=$(BINARY_NAME) \
59 | -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \
60 | -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \
61 | -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)"
62 |
63 | ifeq (cleveldb,$(findstring cleveldb,$(EMPOWER_BUILD_OPTIONS)))
64 | ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=cleveldb
65 | else ifeq (rocksdb,$(findstring rocksdb,$(EMPOWER_BUILD_OPTIONS)))
66 | ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=rocksdb
67 | endif
68 | ifeq (,$(findstring nostrip,$(EMPOWER_BUILD_OPTIONS)))
69 | ldflags += -w -s
70 | endif
71 | ifeq ($(LINK_STATICALLY),true)
72 | ldflags += -linkmode=external -extldflags "-Wl,-z,muldefs -static"
73 | endif
74 | ldflags += $(LDFLAGS)
75 | ldflags := $(strip $(ldflags))
76 |
77 | BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
78 | # check for nostrip option
79 | ifeq (,$(findstring nostrip,$(EMPOWER_BUILD_OPTIONS)))
80 | BUILD_FLAGS += -trimpath
81 | endif
82 |
83 | ###############################################################################
84 | ### Build ###
85 | ###############################################################################
86 |
87 | ver:
88 | @echo $(VERSION)
89 |
90 | all: install lint test
91 |
92 | BUILD_TARGETS := build install
93 |
94 | build: BUILD_ARGS=-o $(BUILD_DIR)/
95 |
96 | $(BUILD_TARGETS): go.sum $(BUILD_DIR)/
97 | go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...
98 |
99 | $(BUILD_DIR)/:
100 | mkdir -p $(BUILD_DIR)/
101 |
102 | build-linux-amd64: go.sum
103 | LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build
104 |
105 | build-linux-arm64: go.sum
106 | LEDGER_ENABLED=false GOOS=linux GOARCH=arm64 $(MAKE) build
107 |
108 | build-darwin-amd64: go.sum
109 | LEDGER_ENABLED=false GOOS=darwin GOARCH=amd64 $(MAKE) build
110 |
111 | build-darwin-arm64: go.sum
112 | LEDGER_ENABLED=false GOOS=darwin GOARCH=arm64 $(MAKE) build
113 |
114 | build-windows-amd64: go.sum
115 | LEDGER_ENABLED=false GOOS=windows GOARCH=amd64 $(MAKE) build
116 |
117 | go-mod-cache: go.sum
118 | @echo "--> Download go modules to local cache 💤"
119 | @go mod download
120 |
121 | go.sum: go.mod
122 | @echo "--> Ensure dependencies have not been modified 💤"
123 | @go mod verify
124 |
125 | clean:
126 | rm -rf $(BUILD_DIR)
127 | rm -f $(shell which $(BINARY_NAME))
128 |
129 | ###############################################################################
130 | ### Docker ###
131 | ###############################################################################
132 |
133 | local-docker:
134 | @echo "Building lazychain:local 💤"
135 | @docker build -t lazychain:local .
136 |
137 | ###############################################################################
138 | ### Run locally ###
139 | ###############################################################################
140 |
141 | local-interchaintest:
142 | @echo "Spinning up local interchain environment 💤"
143 | @cd interchaintest && go run ./local-interchain
144 |
145 | ###############################################################################
146 | ### Testing ###
147 | ###############################################################################
148 |
149 | interchaintest:
150 | @echo "Running interchaintest 💤"
151 | @cd interchaintest && go test -race -count=1 -v -run TestICS20TestSuite/TestIBCTokenTransfers ./...
152 | @cd interchaintest && go test -race -count=1 -v -run TestICS20TestSuite/TestTIAGasToken ./...
153 | @cd interchaintest && go test -race -count=1 -v -run TestICS721TestSuite/TestICS721 ./...
154 |
155 | ###############################################################################
156 | ### Linting ###
157 | ###############################################################################
158 |
159 | lint:
160 | @echo "--> Running linter 💤"
161 | @go run github.com/golangci/golangci-lint/cmd/golangci-lint run --timeout=10m
162 |
163 | format:
164 | @go run github.com/golangci/golangci-lint/cmd/golangci-lint run --fix
165 |
166 | .PHONY: *
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "os"
5 | "strings"
6 |
7 | "github.com/spf13/cobra"
8 | "github.com/spf13/pflag"
9 |
10 | "cosmossdk.io/client/v2/autocli"
11 | clientv2keyring "cosmossdk.io/client/v2/autocli/keyring"
12 | "cosmossdk.io/core/address"
13 | "cosmossdk.io/depinject"
14 | "cosmossdk.io/log"
15 |
16 | "github.com/cosmos/cosmos-sdk/client"
17 | "github.com/cosmos/cosmos-sdk/client/config"
18 | "github.com/cosmos/cosmos-sdk/client/flags"
19 | "github.com/cosmos/cosmos-sdk/codec"
20 | codectypes "github.com/cosmos/cosmos-sdk/codec/types"
21 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
22 | "github.com/cosmos/cosmos-sdk/server"
23 | "github.com/cosmos/cosmos-sdk/types/module"
24 | "github.com/cosmos/cosmos-sdk/types/tx/signing"
25 | "github.com/cosmos/cosmos-sdk/x/auth/tx"
26 | txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
27 | "github.com/cosmos/cosmos-sdk/x/auth/types"
28 |
29 | "github.com/Lazychain/lazychain/app"
30 | )
31 |
32 | // NewRootCmd creates a new root command for lazychaind. It is called once in the main function.
33 | func NewRootCmd() *cobra.Command {
34 | initSDKConfig()
35 |
36 | var (
37 | txConfigOpts tx.ConfigOptions
38 | autoCliOpts autocli.AppOptions
39 | moduleBasicManager module.BasicManager
40 | clientCtx client.Context
41 | )
42 |
43 | if err := depinject.Inject(
44 | depinject.Configs(app.Config(),
45 | depinject.Supply(
46 | log.NewNopLogger(),
47 | ),
48 | depinject.Provide(
49 | ProvideClientContext,
50 | ProvideKeyring,
51 | ),
52 | ),
53 | &txConfigOpts,
54 | &autoCliOpts,
55 | &moduleBasicManager,
56 | &clientCtx,
57 | ); err != nil {
58 | panic(err)
59 | }
60 |
61 | rootCmd := &cobra.Command{
62 | Use: app.Name + "d",
63 | Short: "Start lazychain node",
64 | SilenceErrors: true,
65 | PersistentPreRunE: func(cmd *cobra.Command, _ []string) error {
66 | // set the default command outputs
67 | cmd.SetOut(cmd.OutOrStdout())
68 | cmd.SetErr(cmd.ErrOrStderr())
69 |
70 | clientCtx = clientCtx.WithCmdContext(cmd.Context())
71 | clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
72 | if err != nil {
73 | return err
74 | }
75 |
76 | clientCtx, err = config.ReadFromClientConfig(clientCtx)
77 | if err != nil {
78 | return err
79 | }
80 |
81 | // This needs to go after ReadFromClientConfig, as that function
82 | // sets the RPC client needed for SIGN_MODE_TEXTUAL.
83 | txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
84 | txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx)
85 | txConfigWithTextual, err := tx.NewTxConfigWithOptions(
86 | codec.NewProtoCodec(clientCtx.InterfaceRegistry),
87 | txConfigOpts,
88 | )
89 | if err != nil {
90 | return err
91 | }
92 |
93 | clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
94 | if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
95 | return err
96 | }
97 |
98 | customAppTemplate, customAppConfig := initAppConfig()
99 | customCMTConfig := initCometBFTConfig()
100 |
101 | if err := server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customCMTConfig); err != nil {
102 | return err
103 | }
104 |
105 | serverCtx := server.GetServerContextFromCmd(cmd)
106 | serverCtx.Logger, err = CreateLazyLogger(serverCtx, os.Stderr)
107 | if err != nil {
108 | return err
109 | }
110 |
111 | if cmd.Name() == "start" {
112 | serverCtx.Logger.Info("LM 🦥")
113 | serverCtx.Logger.Info("💤 Starting chain... ")
114 | }
115 |
116 | return nil
117 | },
118 | }
119 |
120 | // Since the IBC modules and tokenfactory don't support dependency injection,
121 | // we need to manually register the modules on the client side.
122 | // This needs to be removed after IBC supports App Wiring.
123 | ibcModules := app.RegisterIBC(clientCtx.InterfaceRegistry)
124 | for name, mod := range ibcModules {
125 | moduleBasicManager[name] = module.CoreAppModuleBasicAdaptor(name, mod)
126 | autoCliOpts.Modules[name] = mod
127 | }
128 |
129 | tokenFactoryName, tokenFactoryModule := app.RegisterTokenFactory(clientCtx.InterfaceRegistry)
130 | moduleBasicManager[tokenFactoryName] = module.CoreAppModuleAdaptor(tokenFactoryName, tokenFactoryModule)
131 | autoCliOpts.Modules[tokenFactoryName] = tokenFactoryModule
132 |
133 | initRootCmd(rootCmd, clientCtx.TxConfig, moduleBasicManager)
134 |
135 | overwriteFlagDefaults(rootCmd, map[string]string{
136 | flags.FlagChainID: strings.ReplaceAll(app.Name, "-", ""),
137 | flags.FlagKeyringBackend: "test",
138 | })
139 |
140 | if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
141 | panic(err)
142 | }
143 |
144 | return rootCmd
145 | }
146 |
147 | func overwriteFlagDefaults(c *cobra.Command, defaults map[string]string) {
148 | set := func(s *pflag.FlagSet, key, val string) {
149 | if f := s.Lookup(key); f != nil {
150 | f.DefValue = val
151 | _ = f.Value.Set(val)
152 | }
153 | }
154 | for key, val := range defaults {
155 | set(c.Flags(), key, val)
156 | set(c.PersistentFlags(), key, val)
157 | }
158 | for _, c := range c.Commands() {
159 | overwriteFlagDefaults(c, defaults)
160 | }
161 | }
162 |
163 | func ProvideClientContext(
164 | appCodec codec.Codec,
165 | interfaceRegistry codectypes.InterfaceRegistry,
166 | txConfig client.TxConfig,
167 | legacyAmino *codec.LegacyAmino,
168 | ) client.Context {
169 | clientCtx := client.Context{}.
170 | WithCodec(appCodec).
171 | WithInterfaceRegistry(interfaceRegistry).
172 | WithTxConfig(txConfig).
173 | WithLegacyAmino(legacyAmino).
174 | WithInput(os.Stdin).
175 | WithAccountRetriever(types.AccountRetriever{}).
176 | WithHomeDir(app.DefaultNodeHome).
177 | WithViper(app.Name) // env variable prefix
178 |
179 | // Read the config again to overwrite the default values with the values from the config file
180 | clientCtx, _ = config.ReadFromClientConfig(clientCtx)
181 |
182 | return clientCtx
183 | }
184 |
185 | func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) {
186 | kb, err := client.NewKeyringFromBackend(clientCtx, clientCtx.Keyring.Backend())
187 | if err != nil {
188 | return nil, err
189 | }
190 |
191 | return keyring.NewAutoCLIKeyring(kb)
192 | }
193 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/sloths/tx.go:
--------------------------------------------------------------------------------
1 | package sloths
2 |
3 | import (
4 | "encoding/base64"
5 | "fmt"
6 | "strings"
7 | "time"
8 |
9 | wasmdtypes "github.com/CosmWasm/wasmd/x/wasm/types"
10 | "github.com/spf13/cobra"
11 |
12 | "github.com/cosmos/cosmos-sdk/client"
13 | sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
14 | "github.com/cosmos/cosmos-sdk/client/tx"
15 |
16 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/lazycommandutils"
17 | )
18 |
19 | func GetTxCmd() *cobra.Command {
20 | cmd := &cobra.Command{
21 | Use: "sloths",
22 | Short: "Transaction commands for sloths",
23 | DisableFlagParsing: true,
24 | RunE: client.ValidateCmd,
25 | }
26 |
27 | cmd.AddCommand(TransferSlothCmd())
28 |
29 | return cmd
30 | }
31 |
32 | func TransferSlothCmd() *cobra.Command {
33 | cmd := &cobra.Command{
34 | Use: "transfer [from_address] [to_address] [nft-id]",
35 | Short: "Transfer sloth nfts between Stargaze and LazyChain using ICS721",
36 | Args: cobra.ExactArgs(3),
37 | RunE: func(cmd *cobra.Command, args []string) error {
38 | from := args[0]
39 | to := args[1]
40 | nftID := args[2]
41 |
42 | node, _ := cmd.Flags().GetString(sdkflags.FlagNode)
43 | chainID, _ := cmd.Flags().GetString(sdkflags.FlagChainID)
44 | nftContract, _ := cmd.Flags().GetString(lazycommandutils.FlagNFTContract)
45 | ics721Contract, _ := cmd.Flags().GetString(lazycommandutils.FlagICS721Contract)
46 | ics721Channel, _ := cmd.Flags().GetString(lazycommandutils.FlagICS721Channel)
47 | waitForTx, _ := cmd.Flags().GetBool(lazycommandutils.FlagWaitForTx)
48 |
49 | mainnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagMainnet)
50 | testnet, _ := cmd.Flags().GetBool(lazycommandutils.FlagTestnet)
51 |
52 | // Figure out if we are transferring from Stargaze to LazyChain or vice versa
53 | isStargaze := strings.HasPrefix(from, "stars")
54 | if isStargaze && !strings.HasPrefix(to, "lazy") {
55 | return fmt.Errorf("invalid addresses. Must transfer between Stargaze and LazyChain")
56 | }
57 | if !isStargaze && (!strings.HasPrefix(to, "stars") || !strings.HasPrefix(from, "lazy")) {
58 | return fmt.Errorf("invalid addresses. Must transfer between Stargaze and LazyChain")
59 | }
60 |
61 | if !mainnet && !testnet &&
62 | (node == "" || chainID == "" || nftContract == "" || ics721Contract == "" || ics721Channel == "") {
63 | return fmt.Errorf("missing required flags. Either set --mainnet or --testnet or provide the manual flags (--%s --%s --%s --%s --%s)",
64 | sdkflags.FlagNode, sdkflags.FlagChainID, lazycommandutils.FlagNFTContract, lazycommandutils.FlagICS721Contract, lazycommandutils.FlagICS721Channel)
65 | }
66 |
67 | if mainnet || testnet {
68 | // TODO: Remove once mainnet
69 | if mainnet {
70 | return fmt.Errorf("mainnet not supported yet")
71 | }
72 |
73 | var networks lazycommandutils.ICS721Networks
74 | if mainnet {
75 | networks = lazycommandutils.ICS721Mainnets
76 | } else {
77 | networks = lazycommandutils.ICS721Testnets
78 | }
79 |
80 | var networkInfo lazycommandutils.StaticICS721NetworkInfo
81 | if isStargaze {
82 | networkInfo = networks.Stargaze
83 | } else {
84 | networkInfo = networks.LazyChain
85 | }
86 |
87 | chainID = networkInfo.ChainID
88 | if err := cmd.Flags().Set(sdkflags.FlagChainID, chainID); err != nil {
89 | return err
90 | }
91 | node = networkInfo.Node
92 | if err := cmd.Flags().Set(sdkflags.FlagNode, node); err != nil {
93 | return err
94 | }
95 | nftContract = networkInfo.NFTContract
96 | ics721Contract = networkInfo.ICS721Contract
97 | ics721Channel = networkInfo.ICS721Channel
98 |
99 | if err := cmd.Flags().Set(sdkflags.FlagGas, "auto"); err != nil {
100 | return err
101 | }
102 | if err := cmd.Flags().Set(sdkflags.FlagGasAdjustment, "1.5"); err != nil {
103 | return err
104 | }
105 | if err := cmd.Flags().Set(sdkflags.FlagGasPrices, networkInfo.GasPrices); err != nil {
106 | return err
107 | }
108 | }
109 |
110 | msg := createTransferMsg(from, to, nftID, nftContract, ics721Contract, ics721Channel)
111 |
112 | if err := cmd.Flags().Set(sdkflags.FlagFrom, from); err != nil {
113 | return err
114 | }
115 | clientCtx, err := client.GetClientTxContext(cmd)
116 | if err != nil {
117 | return err
118 | }
119 |
120 | if waitForTx {
121 | if err := lazycommandutils.SendAndWaitForTx(clientCtx, cmd.Flags(), &msg); err != nil {
122 | return err
123 | }
124 |
125 | fmt.Printf("🦥 lazy... transfer... of... sloth #%s... to... %s... done...\n", nftID, to)
126 | fmt.Printf("🦥 tx... finally... done... time... too... 💤!\n")
127 |
128 | return nil
129 | }
130 |
131 | return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
132 | },
133 | }
134 |
135 | cmd.Flags().Bool(lazycommandutils.FlagWaitForTx, true, "Wait for transaction to be included in a block")
136 | cmd.Flags().String(lazycommandutils.FlagICS721Contract, "", "ICS721 contract address")
137 | cmd.Flags().String(lazycommandutils.FlagICS721Channel, "", "ICS721 channel")
138 | cmd.Flags().String(lazycommandutils.FlagNFTContract, "", "NFT contract address")
139 | cmd.Flags().Bool(lazycommandutils.FlagMainnet, false, "Use mainnet (overrides transfer flags)")
140 | cmd.Flags().Bool(lazycommandutils.FlagTestnet, false, "Use testnet (overrides transfer flags)")
141 |
142 | sdkflags.AddTxFlagsToCmd(cmd)
143 | nodeFlag := cmd.Flags().Lookup(sdkflags.FlagNode)
144 | nodeFlag.Usage = "RPC endpoint of sending chain (Stargaze or LazyChain)"
145 | nodeFlag.DefValue = ""
146 |
147 | cmd.Flags().Lookup(sdkflags.FlagChainID).Usage = "Chain ID of sending chain (Stargaze or LazyChain)"
148 |
149 | return cmd
150 | }
151 |
152 | func createTransferMsg(from string, to string, nftID string, nftContract string, ics721Contract string, ics721channel string) wasmdtypes.MsgExecuteContract {
153 | now := time.Now()
154 | fiveMinutesLater := now.Add(5 * time.Minute) // TODO: Maybe more...
155 | sendExecMsg := fmt.Sprintf("{\"receiver\": \"%s\",\n\"channel_id\": \"%s\",\n\"timeout\": { \"timestamp\": \"%d\"}}",
156 | to,
157 | ics721channel,
158 | fiveMinutesLater.UnixNano(),
159 | )
160 | sendExecMsgBase64 := base64.StdEncoding.EncodeToString([]byte(sendExecMsg))
161 |
162 | execMsg := fmt.Sprintf(`{
163 | "send_nft": {
164 | "contract": "%s",
165 | "token_id": "%s",
166 | "msg": "%s"}
167 | }`, ics721Contract, nftID, sendExecMsgBase64)
168 | return wasmdtypes.MsgExecuteContract{
169 | Sender: from,
170 | Contract: nftContract,
171 | Msg: []byte(execMsg),
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/cmd/lazychaind/cmd/commands.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "errors"
5 | "io"
6 |
7 | "github.com/CosmWasm/wasmd/x/wasm"
8 | wasmcli "github.com/CosmWasm/wasmd/x/wasm/client/cli"
9 | dbm "github.com/cosmos/cosmos-db"
10 | rollserv "github.com/rollkit/cosmos-sdk-starter/server"
11 | rollconf "github.com/rollkit/rollkit/config"
12 | "github.com/spf13/cobra"
13 | "github.com/spf13/viper"
14 |
15 | "cosmossdk.io/log"
16 | confixcmd "cosmossdk.io/tools/confix/cmd"
17 |
18 | "github.com/cosmos/cosmos-sdk/client"
19 | "github.com/cosmos/cosmos-sdk/client/debug"
20 | "github.com/cosmos/cosmos-sdk/client/flags"
21 | "github.com/cosmos/cosmos-sdk/client/keys"
22 | "github.com/cosmos/cosmos-sdk/client/pruning"
23 | "github.com/cosmos/cosmos-sdk/client/rpc"
24 | "github.com/cosmos/cosmos-sdk/client/snapshot"
25 | "github.com/cosmos/cosmos-sdk/server"
26 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
27 | "github.com/cosmos/cosmos-sdk/types/module"
28 | authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
29 | "github.com/cosmos/cosmos-sdk/x/crisis"
30 | genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
31 |
32 | "github.com/Lazychain/lazychain/app"
33 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/sloths"
34 | "github.com/Lazychain/lazychain/cmd/lazychaind/cmd/tia"
35 | )
36 |
37 | func initRootCmd(
38 | rootCmd *cobra.Command,
39 | txConfig client.TxConfig,
40 | basicManager module.BasicManager,
41 | ) {
42 | rootCmd.AddCommand(
43 | genutilcli.InitCmd(basicManager, app.DefaultNodeHome),
44 | debug.Cmd(),
45 | confixcmd.ConfigCommand(),
46 | pruning.Cmd(newApp, app.DefaultNodeHome),
47 | snapshot.Cmd(newApp),
48 | )
49 |
50 | server.AddCommandsWithStartCmdOptions(
51 | rootCmd,
52 | app.DefaultNodeHome,
53 | newApp, appExport,
54 | server.StartCmdOptions{
55 | AddFlags: func(cmd *cobra.Command) {
56 | rollconf.AddFlags(cmd)
57 | addModuleInitFlags(cmd)
58 | },
59 | StartCommandHandler: rollserv.StartHandler[servertypes.Application],
60 | })
61 |
62 | // add keybase, auxiliary RPC, query, genesis, and tx child commands
63 | rootCmd.AddCommand(
64 | server.StatusCommand(),
65 | genesisCommand(txConfig, basicManager),
66 | queryCommand(),
67 | txCommand(),
68 | keys.Commands(),
69 | )
70 | wasmcli.ExtendUnsafeResetAllCmd(
71 | rootCmd,
72 | )
73 | }
74 |
75 | func addModuleInitFlags(startCmd *cobra.Command) {
76 | crisis.AddModuleInitFlags(startCmd)
77 | wasm.AddModuleInitFlags(startCmd)
78 | }
79 |
80 | // genesisCommand builds genesis-related `lazychaind genesis` command. Users may provide application specific commands as a parameter
81 | func genesisCommand(txConfig client.TxConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command {
82 | cmd := genutilcli.Commands(txConfig, basicManager, app.DefaultNodeHome)
83 |
84 | for _, subCmd := range cmds {
85 | cmd.AddCommand(subCmd)
86 | }
87 | return cmd
88 | }
89 |
90 | func queryCommand() *cobra.Command {
91 | cmd := &cobra.Command{
92 | Use: "query",
93 | Aliases: []string{"q"},
94 | Short: "Querying subcommands",
95 | DisableFlagParsing: false,
96 | SuggestionsMinimumDistance: 2,
97 | RunE: client.ValidateCmd,
98 | }
99 |
100 | cmd.AddCommand(
101 | rpc.QueryEventForTxCmd(),
102 | rpc.ValidatorCommand(),
103 | server.QueryBlockCmd(),
104 | authcmd.QueryTxsByEventsCmd(),
105 | server.QueryBlocksCmd(),
106 | authcmd.QueryTxCmd(),
107 | server.QueryBlockResultsCmd(),
108 | // Custom query commands
109 | sloths.GetQueryCmd(),
110 | tia.GetQueryCmd(),
111 | )
112 | cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
113 |
114 | return cmd
115 | }
116 |
117 | func txCommand() *cobra.Command {
118 | cmd := &cobra.Command{
119 | Use: "tx",
120 | Short: "Transactions subcommands",
121 | DisableFlagParsing: false,
122 | SuggestionsMinimumDistance: 2,
123 | RunE: client.ValidateCmd,
124 | }
125 |
126 | cmd.AddCommand(
127 | authcmd.GetSignCommand(),
128 | authcmd.GetSignBatchCommand(),
129 | authcmd.GetMultiSignCommand(),
130 | authcmd.GetMultiSignBatchCmd(),
131 | authcmd.GetValidateSignaturesCommand(),
132 | flags.LineBreak,
133 | authcmd.GetBroadcastCommand(),
134 | authcmd.GetEncodeCommand(),
135 | authcmd.GetDecodeCommand(),
136 | authcmd.GetSimulateCmd(),
137 | )
138 | cmd.PersistentFlags().String(flags.FlagChainID, "", "The network chain ID")
139 |
140 | // Custom tx commands (setting this after, because we need the chain ID flag a bit)
141 | cmd.AddCommand(sloths.GetTxCmd())
142 | cmd.AddCommand(tia.GetTxCmd())
143 |
144 | return cmd
145 | }
146 |
147 | // newApp creates the application
148 | func newApp(
149 | logger log.Logger,
150 | db dbm.DB,
151 | traceStore io.Writer,
152 | appOpts servertypes.AppOptions,
153 | ) servertypes.Application {
154 | baseappOptions := server.DefaultBaseappOptions(appOpts)
155 |
156 | lazyApp, err := app.New(
157 | logger, db, traceStore, true,
158 | appOpts,
159 | baseappOptions...,
160 | )
161 | if err != nil {
162 | panic(err)
163 | }
164 | return lazyApp
165 | }
166 |
167 | // appExport creates a new app (optionally at a given height) and exports state.
168 | func appExport(
169 | logger log.Logger,
170 | db dbm.DB,
171 | traceStore io.Writer,
172 | height int64,
173 | forZeroHeight bool,
174 | jailAllowedAddrs []string,
175 | appOpts servertypes.AppOptions,
176 | modulesToExport []string,
177 | ) (servertypes.ExportedApp, error) {
178 | var (
179 | bApp *app.LazyApp
180 | err error
181 | )
182 |
183 | // this check is necessary as we use the flag in x/upgrade.
184 | // we can exit more gracefully by checking the flag here.
185 | homePath, ok := appOpts.Get(flags.FlagHome).(string)
186 | if !ok || homePath == "" {
187 | return servertypes.ExportedApp{}, errors.New("application home not set")
188 | }
189 |
190 | viperAppOpts, ok := appOpts.(*viper.Viper)
191 | if !ok {
192 | return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper")
193 | }
194 |
195 | // overwrite the FlagInvCheckPeriod
196 | viperAppOpts.Set(server.FlagInvCheckPeriod, 1)
197 | appOpts = viperAppOpts
198 |
199 | if height != -1 {
200 | bApp, err = app.New(logger, db, traceStore, false, appOpts)
201 | if err != nil {
202 | return servertypes.ExportedApp{}, err
203 | }
204 |
205 | if err := bApp.LoadHeight(height); err != nil {
206 | return servertypes.ExportedApp{}, err
207 | }
208 | } else {
209 | bApp, err = app.New(logger, db, traceStore, true, appOpts)
210 | if err != nil {
211 | return servertypes.ExportedApp{}, err
212 | }
213 | }
214 |
215 | return bApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)
216 | }
217 |
--------------------------------------------------------------------------------
/app/ibc.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "github.com/CosmWasm/wasmd/x/wasm"
5 | wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
6 | "github.com/cosmos/ibc-go/modules/capability"
7 | capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper"
8 | capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
9 | ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee"
10 | ibcfeekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper"
11 | ibcfeetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"
12 | ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer"
13 | ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper"
14 | ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
15 | ibc "github.com/cosmos/ibc-go/v8/modules/core"
16 | ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
17 | ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"
18 | porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types"
19 | ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported"
20 | ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper"
21 | solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine"
22 | ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
23 |
24 | "cosmossdk.io/core/appmodule"
25 | storetypes "cosmossdk.io/store/types"
26 |
27 | cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
28 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
29 | "github.com/cosmos/cosmos-sdk/types/module"
30 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
31 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
32 | govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
33 | paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
34 | )
35 |
36 | // registerIBCModules register IBC keepers and non dependency inject modules.
37 | func (app *LazyApp) registerIBCModules(appOpts servertypes.AppOptions) error {
38 | // set up non depinject support modules store keys
39 | if err := app.RegisterStores(
40 | storetypes.NewKVStoreKey(capabilitytypes.StoreKey),
41 | storetypes.NewKVStoreKey(ibcexported.StoreKey),
42 | storetypes.NewKVStoreKey(ibctransfertypes.StoreKey),
43 | storetypes.NewKVStoreKey(ibcfeetypes.StoreKey),
44 | storetypes.NewMemoryStoreKey(capabilitytypes.MemStoreKey),
45 | storetypes.NewTransientStoreKey(paramstypes.TStoreKey),
46 | ); err != nil {
47 | return err
48 | }
49 |
50 | // register the key tables for legacy param subspaces
51 | keyTable := ibcclienttypes.ParamKeyTable()
52 | keyTable.RegisterParamSet(&ibcconnectiontypes.Params{})
53 | app.ParamsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable)
54 | app.ParamsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable())
55 |
56 | // add capability keeper and ScopeToModule for ibc module
57 | app.CapabilityKeeper = capabilitykeeper.NewKeeper(
58 | app.AppCodec(),
59 | app.GetKey(capabilitytypes.StoreKey),
60 | app.GetMemKey(capabilitytypes.MemStoreKey),
61 | )
62 |
63 | // add capability keeper and ScopeToModule for ibc module
64 | scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName)
65 | scopedIBCTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
66 |
67 | // Create IBC keeper
68 | app.IBCKeeper = ibckeeper.NewKeeper(
69 | app.appCodec,
70 | app.GetKey(ibcexported.StoreKey),
71 | app.GetSubspace(ibcexported.ModuleName),
72 | app.StakingKeeper,
73 | app.UpgradeKeeper,
74 | scopedIBCKeeper,
75 | authtypes.NewModuleAddress(govtypes.ModuleName).String(),
76 | )
77 |
78 | // Register the proposal types
79 | // Deprecated: Avoid adding new handlers, instead use the new proposal flow
80 | // by granting the governance module the right to execute the message.
81 | // See: https://docs.cosmos.network/main/modules/gov#proposal-messages
82 | govRouter := govv1beta1.NewRouter()
83 | govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler)
84 |
85 | app.IBCFeeKeeper = ibcfeekeeper.NewKeeper(
86 | app.appCodec, app.GetKey(ibcfeetypes.StoreKey),
87 | app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware
88 | app.IBCKeeper.ChannelKeeper,
89 | app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper,
90 | )
91 |
92 | // Create IBC transfer keeper
93 | app.TransferKeeper = ibctransferkeeper.NewKeeper(
94 | app.appCodec,
95 | app.GetKey(ibctransfertypes.StoreKey),
96 | app.GetSubspace(ibctransfertypes.ModuleName),
97 | app.IBCFeeKeeper,
98 | app.IBCKeeper.ChannelKeeper,
99 | app.IBCKeeper.PortKeeper,
100 | app.AccountKeeper,
101 | app.BankKeeper,
102 | scopedIBCTransferKeeper,
103 | authtypes.NewModuleAddress(govtypes.ModuleName).String(),
104 | )
105 |
106 | // Create IBC modules with ibcfee middleware
107 | transferIBCModule := ibcfee.NewIBCMiddleware(ibctransfer.NewIBCModule(app.TransferKeeper), app.IBCFeeKeeper)
108 |
109 | // Create static IBC router, add transfer route, then set and seal it
110 | ibcRouter := porttypes.NewRouter().
111 | AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
112 |
113 | wasmStack, err := app.registerWasmModules(appOpts)
114 | if err != nil {
115 | return err
116 | }
117 | ibcRouter.AddRoute(wasmtypes.ModuleName, wasmStack)
118 |
119 | // this line is used by starport scaffolding # ibc/app/module
120 |
121 | app.IBCKeeper.SetRouter(ibcRouter)
122 |
123 | app.ScopedIBCKeeper = scopedIBCKeeper
124 | app.ScopedIBCTransferKeeper = scopedIBCTransferKeeper
125 |
126 | // register IBC modules
127 | if err := app.RegisterModules(
128 | ibc.NewAppModule(app.IBCKeeper),
129 | ibctransfer.NewAppModule(app.TransferKeeper),
130 | ibcfee.NewAppModule(app.IBCFeeKeeper),
131 | capability.NewAppModule(app.appCodec, *app.CapabilityKeeper, false),
132 | ibctm.NewAppModule(),
133 | solomachine.NewAppModule(),
134 | ); err != nil {
135 | return err
136 | }
137 |
138 | return nil
139 | }
140 |
141 | // RegisterIBC Since the IBC modules don't support dependency injection,
142 | // we need to manually register the modules on the client side.
143 | // This needs to be removed after IBC supports App Wiring.
144 | func RegisterIBC(registry cdctypes.InterfaceRegistry) map[string]appmodule.AppModule {
145 | modules := map[string]appmodule.AppModule{
146 | ibcexported.ModuleName: ibc.AppModule{},
147 | ibctransfertypes.ModuleName: ibctransfer.AppModule{},
148 | ibcfeetypes.ModuleName: ibcfee.AppModule{},
149 | capabilitytypes.ModuleName: capability.AppModule{},
150 | ibctm.ModuleName: ibctm.AppModule{},
151 | solomachine.ModuleName: solomachine.AppModule{},
152 | wasmtypes.ModuleName: wasm.AppModule{},
153 | }
154 |
155 | for name, m := range modules {
156 | module.CoreAppModuleBasicAdaptor(name, m).RegisterInterfaces(registry)
157 | }
158 |
159 | return modules
160 | }
161 |
--------------------------------------------------------------------------------
/app/export.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "log"
7 |
8 | storetypes "cosmossdk.io/store/types"
9 |
10 | servertypes "github.com/cosmos/cosmos-sdk/server/types"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | "github.com/cosmos/cosmos-sdk/x/staking"
13 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
14 |
15 | cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
16 | )
17 |
18 | // ExportAppStateAndValidators exports the state of the application for a genesis
19 | // file.
20 | func (app *LazyApp) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) {
21 | // as if they could withdraw from the start of the next block
22 | ctx := app.NewContextLegacy(true, cmtproto.Header{Height: app.LastBlockHeight()})
23 |
24 | // We export at last height + 1, because that's the height at which
25 | // CometBFT will start InitChain.
26 | height := app.LastBlockHeight() + 1
27 | if forZeroHeight {
28 | height = 0
29 | app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
30 | }
31 |
32 | genState, err := app.ModuleManager.ExportGenesisForModules(ctx, app.appCodec, modulesToExport)
33 | if err != nil {
34 | return servertypes.ExportedApp{}, err
35 | }
36 |
37 | appState, err := json.MarshalIndent(genState, "", " ")
38 | if err != nil {
39 | return servertypes.ExportedApp{}, err
40 | }
41 |
42 | validators, err := staking.WriteValidators(ctx, &app.StakingKeeper.Keeper)
43 | return servertypes.ExportedApp{
44 | AppState: appState,
45 | Validators: validators,
46 | Height: height,
47 | ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
48 | }, err
49 | }
50 |
51 | // prepare for fresh start at zero height
52 | // NOTE zero height genesis is a temporary feature which will be deprecated
53 | //
54 | // in favor of export at a block height
55 | func (app *LazyApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs []string) {
56 | applyAllowedAddrs := false
57 |
58 | // check if there is a allowed address list
59 | if len(jailAllowedAddrs) > 0 {
60 | applyAllowedAddrs = true
61 | }
62 |
63 | allowedAddrsMap := make(map[string]bool)
64 |
65 | for _, addr := range jailAllowedAddrs {
66 | _, err := sdk.ValAddressFromBech32(addr)
67 | if err != nil {
68 | log.Fatal(err)
69 | }
70 | allowedAddrsMap[addr] = true
71 | }
72 |
73 | /* Just to be safe, assert the invariants on current state. */
74 | app.CrisisKeeper.AssertInvariants(ctx)
75 |
76 | /* Handle fee distribution state. */
77 |
78 | // withdraw all validator commission
79 | err := app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
80 | valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
81 | if err != nil {
82 | panic(err)
83 | }
84 | _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, valBz)
85 | return false
86 | })
87 | if err != nil {
88 | panic(err)
89 | }
90 |
91 | // withdraw all delegator rewards
92 | dels, err := app.StakingKeeper.GetAllDelegations(ctx)
93 | if err != nil {
94 | panic(err)
95 | }
96 |
97 | for _, delegation := range dels {
98 | valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress)
99 | if err != nil {
100 | panic(err)
101 | }
102 |
103 | delAddr := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress)
104 |
105 | _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr)
106 | }
107 |
108 | // clear validator slash events
109 | app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
110 |
111 | // clear validator historical rewards
112 | app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
113 |
114 | // set context height to zero
115 | height := ctx.BlockHeight()
116 | ctx = ctx.WithBlockHeight(0)
117 |
118 | // reinitialize all validators
119 | err = app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) {
120 | valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator())
121 | if err != nil {
122 | panic(err)
123 | }
124 | // donate any unwithdrawn outstanding reward fraction tokens to the community pool
125 | scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, valBz)
126 | if err != nil {
127 | panic(err)
128 | }
129 | feePool, err := app.DistrKeeper.FeePool.Get(ctx)
130 | if err != nil {
131 | panic(err)
132 | }
133 | feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
134 | if err := app.DistrKeeper.FeePool.Set(ctx, feePool); err != nil {
135 | panic(err)
136 | }
137 |
138 | if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, valBz); err != nil {
139 | panic(err)
140 | }
141 | return false
142 | })
143 |
144 | // reinitialize all delegations
145 | for _, del := range dels {
146 | valAddr, err := sdk.ValAddressFromBech32(del.ValidatorAddress)
147 | if err != nil {
148 | panic(err)
149 | }
150 | delAddr := sdk.MustAccAddressFromBech32(del.DelegatorAddress)
151 |
152 | if err := app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, delAddr, valAddr); err != nil {
153 | // never called as BeforeDelegationCreated always returns nil
154 | panic(fmt.Errorf("error while incrementing period: %w", err))
155 | }
156 |
157 | if err := app.DistrKeeper.Hooks().AfterDelegationModified(ctx, delAddr, valAddr); err != nil {
158 | // never called as AfterDelegationModified always returns nil
159 | panic(fmt.Errorf("error while creating a new delegation period record: %w", err))
160 | }
161 | }
162 |
163 | // reset context height
164 | ctx = ctx.WithBlockHeight(height)
165 |
166 | /* Handle staking state. */
167 |
168 | // iterate through redelegations, reset creation height
169 | err = app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) {
170 | for i := range red.Entries {
171 | red.Entries[i].CreationHeight = 0
172 | }
173 | err = app.StakingKeeper.SetRedelegation(ctx, red)
174 | if err != nil {
175 | panic(err)
176 | }
177 | return false
178 | })
179 | if err != nil {
180 | panic(err)
181 | }
182 |
183 | // iterate through unbonding delegations, reset creation height
184 | err = app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) {
185 | for i := range ubd.Entries {
186 | ubd.Entries[i].CreationHeight = 0
187 | }
188 | err = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
189 | if err != nil {
190 | panic(err)
191 | }
192 | return false
193 | })
194 | if err != nil {
195 | panic(err)
196 | }
197 |
198 | // Iterate through validators by power descending, reset bond heights, and
199 | // update bond intra-tx counters.
200 | store := ctx.KVStore(app.GetKey(stakingtypes.StoreKey))
201 | iter := storetypes.KVStoreReversePrefixIterator(store, stakingtypes.ValidatorsKey)
202 | counter := int16(0)
203 |
204 | for ; iter.Valid(); iter.Next() {
205 | addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key()))
206 | validator, err := app.StakingKeeper.GetValidator(ctx, addr)
207 | if err != nil {
208 | panic("expected validator, not found")
209 | }
210 |
211 | validator.UnbondingHeight = 0
212 | if applyAllowedAddrs && !allowedAddrsMap[addr.String()] {
213 | validator.Jailed = true
214 | }
215 |
216 | if err := app.StakingKeeper.SetValidator(ctx, validator); err != nil {
217 | panic(err)
218 | }
219 | counter++
220 | }
221 |
222 | if err := iter.Close(); err != nil {
223 | app.Logger().Error("error while closing the key-value store reverse prefix iterator: ", err)
224 | return
225 | }
226 |
227 | _, err = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
228 | if err != nil {
229 | log.Fatal(err)
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/interchaintest/ics20/ics20_test.go:
--------------------------------------------------------------------------------
1 | package ics20
2 |
3 | import (
4 | "fmt"
5 | "github.com/Lazychain/lazychain/interchaintest/utils"
6 | "go.uber.org/zap/zaptest"
7 | "testing"
8 |
9 | "cosmossdk.io/math"
10 | transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
11 | "github.com/strangelove-ventures/interchaintest/v8"
12 | "github.com/strangelove-ventures/interchaintest/v8/ibc"
13 | "github.com/strangelove-ventures/interchaintest/v8/testutil"
14 | testifysuite "github.com/stretchr/testify/suite"
15 | )
16 |
17 | type ICS20TestSuite struct {
18 | utils.E2ETestSuite
19 | }
20 |
21 | func TestICS20TestSuite(t *testing.T) {
22 | testifysuite.Run(t, new(ICS20TestSuite))
23 | }
24 |
25 | func (s *ICS20TestSuite) TestIBCTokenTransfers() {
26 | s.NotNil(s.Interchain)
27 |
28 | slothUser, err := s.LazyChain.BuildWallet(s.Ctx, "slothUser", "")
29 | s.NoError(err)
30 | stargazeUser := interchaintest.GetAndFundTestUsers(s.T(), s.Ctx, s.T().Name(), math.NewInt(10_000_000_000), s.Stargaze)[0]
31 | celestiaUser := interchaintest.GetAndFundTestUsers(s.T(), s.Ctx, s.T().Name(), math.NewInt(10_000_000_000), s.Celestia)[0]
32 |
33 | s.NoError(s.Relayer.StartRelayer(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath, s.CelestiaSlothPath))
34 | s.T().Cleanup(
35 | func() {
36 | err := s.Relayer.StopRelayer(s.Ctx, s.RelayerExecRep)
37 | if err != nil {
38 | s.T().Logf("an error occurred while stopping the relayer: %s", err)
39 | }
40 | },
41 | )
42 |
43 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.LazyChain, s.Stargaze, s.Celestia))
44 |
45 | sgToSlothChannel, err := ibc.GetTransferChannel(s.Ctx, s.Relayer, s.RelayerExecRep, s.Stargaze.Config().ChainID, s.LazyChain.Config().ChainID)
46 | s.NoError(err)
47 |
48 | celestiaToSlothChannel, err := ibc.GetTransferChannel(s.Ctx, s.Relayer, s.RelayerExecRep, s.Celestia.Config().ChainID, s.LazyChain.Config().ChainID)
49 | s.NoError(err)
50 |
51 | sgUserAddr := stargazeUser.FormattedAddress()
52 | celestiaUserAddr := celestiaUser.FormattedAddress()
53 | slothUserAddr := slothUser.FormattedAddress()
54 |
55 | sgBalanceBefore, err := s.Stargaze.GetBalance(s.Ctx, sgUserAddr, s.Stargaze.Config().Denom)
56 | s.NoError(err)
57 |
58 | celestiaBalanceBefore, err := s.Celestia.GetBalance(s.Ctx, celestiaUserAddr, s.Celestia.Config().Denom)
59 | s.NoError(err)
60 |
61 | var transferAmount = math.NewInt(1_000)
62 | sgTransfer := ibc.WalletAmount{
63 | Address: slothUserAddr,
64 | Denom: s.Stargaze.Config().Denom,
65 | Amount: transferAmount,
66 | }
67 | _, err = s.Stargaze.SendIBCTransfer(s.Ctx, sgToSlothChannel.ChannelID, sgUserAddr, sgTransfer, ibc.TransferOptions{})
68 | s.NoError(err)
69 |
70 | celestiaTransfer := ibc.WalletAmount{
71 | Address: slothUserAddr,
72 | Denom: s.Celestia.Config().Denom,
73 | Amount: transferAmount,
74 | }
75 | s.CelestiaIBCTransfer(celestiaToSlothChannel.ChannelID, celestiaUser.KeyName(), celestiaTransfer)
76 |
77 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.LazyChain, s.Stargaze, s.Celestia))
78 |
79 | starsSrcDenom := transfertypes.GetPrefixedDenom("transfer", sgToSlothChannel.Counterparty.ChannelID, s.Stargaze.Config().Denom)
80 | starsSrcIBCDenom := transfertypes.ParseDenomTrace(starsSrcDenom).IBCDenom()
81 | tiaSrcDenom := transfertypes.GetPrefixedDenom("transfer", celestiaToSlothChannel.Counterparty.ChannelID, s.Celestia.Config().Denom)
82 | tiaSrcIBCDenom := transfertypes.ParseDenomTrace(tiaSrcDenom).IBCDenom()
83 |
84 | sgBalanceAfter, err := s.Stargaze.GetBalance(s.Ctx, sgUserAddr, s.Stargaze.Config().Denom)
85 | s.NoError(err)
86 | s.Equal(sgBalanceBefore.Sub(transferAmount), sgBalanceAfter)
87 |
88 | celestiaBalanceAfter, err := s.Celestia.GetBalance(s.Ctx, celestiaUserAddr, s.Celestia.Config().Denom)
89 | s.NoError(err)
90 | s.Equal(celestiaBalanceBefore.Sub(transferAmount), celestiaBalanceAfter)
91 |
92 | slothStarsBalanceAfter, err := s.LazyChain.GetBalance(s.Ctx, slothUserAddr, starsSrcIBCDenom)
93 | s.NoError(err)
94 | s.Equal(transferAmount, slothStarsBalanceAfter)
95 |
96 | slothTiaBalanceAfter, err := s.LazyChain.GetBalance(s.Ctx, slothUserAddr, tiaSrcIBCDenom)
97 | s.NoError(err)
98 | s.Equal(transferAmount, slothTiaBalanceAfter)
99 |
100 | // Transfer back
101 | sgTransfer = ibc.WalletAmount{
102 | Address: sgUserAddr,
103 | Denom: starsSrcIBCDenom,
104 | Amount: transferAmount,
105 | }
106 | _, err = s.LazyChain.SendIBCTransfer(s.Ctx, sgToSlothChannel.Counterparty.ChannelID, slothUserAddr, sgTransfer, ibc.TransferOptions{})
107 | s.NoError(err)
108 |
109 | celestiaTransfer = ibc.WalletAmount{
110 | Address: celestiaUserAddr,
111 | Denom: tiaSrcIBCDenom,
112 | Amount: transferAmount,
113 | }
114 | _, err = s.LazyChain.SendIBCTransfer(s.Ctx, celestiaToSlothChannel.Counterparty.ChannelID, slothUserAddr, celestiaTransfer, ibc.TransferOptions{})
115 | s.NoError(err)
116 |
117 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.LazyChain, s.Stargaze, s.Celestia))
118 |
119 | sgBalanceFinal, err := s.Stargaze.GetBalance(s.Ctx, sgUserAddr, s.Stargaze.Config().Denom)
120 | s.NoError(err)
121 | s.Equal(sgBalanceBefore, sgBalanceFinal)
122 |
123 | celestiaBalanceFinal, err := s.Celestia.GetBalance(s.Ctx, celestiaUserAddr, s.Celestia.Config().Denom)
124 | s.NoError(err)
125 | s.Equal(celestiaBalanceBefore, celestiaBalanceFinal)
126 |
127 | slothStarsBalanceFinal, err := s.LazyChain.GetBalance(s.Ctx, slothUserAddr, starsSrcIBCDenom)
128 | s.NoError(err)
129 | s.Equal(math.NewInt(0), slothStarsBalanceFinal)
130 |
131 | slothTiaBalanceFinal, err := s.LazyChain.GetBalance(s.Ctx, slothUserAddr, tiaSrcIBCDenom)
132 | s.NoError(err)
133 | s.Equal(math.NewInt(0), slothTiaBalanceFinal)
134 | }
135 |
136 | func (s *ICS20TestSuite) TestTIAGasToken() {
137 | s.NotNil(s.Interchain)
138 |
139 | celestiaUser := interchaintest.GetAndFundTestUsers(s.T(), s.Ctx, s.T().Name(), math.NewInt(10_000_000_000), s.Celestia)[0]
140 | slothUser, err := s.LazyChain.BuildWallet(s.Ctx, "slothUser", "")
141 | s.NoError(err)
142 |
143 | // Transfer TIA to relayer wallet + our user
144 | relayerWallet, found := s.Relayer.GetWallet(s.LazyChain.Config().ChainID)
145 | s.Require().True(found)
146 |
147 | s.NoError(s.Relayer.StartRelayer(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath, s.CelestiaSlothPath))
148 | s.T().Cleanup(
149 | func() {
150 | err := s.Relayer.StopRelayer(s.Ctx, s.RelayerExecRep)
151 | if err != nil {
152 | s.T().Logf("an error occurred while stopping the relayer: %s", err)
153 | }
154 | },
155 | )
156 |
157 | celestiaToSlothChannel, err := ibc.GetTransferChannel(s.Ctx, s.Relayer, s.RelayerExecRep, s.Celestia.Config().ChainID, s.LazyChain.Config().ChainID)
158 | s.NoError(err)
159 |
160 | var transferAmount = math.NewInt(1_000_000_00)
161 | celestiaTransfer := ibc.WalletAmount{
162 | Address: relayerWallet.FormattedAddress(),
163 | Denom: s.Celestia.Config().Denom,
164 | Amount: transferAmount,
165 | }
166 | s.CelestiaIBCTransfer(celestiaToSlothChannel.ChannelID, celestiaUser.KeyName(), celestiaTransfer)
167 |
168 | celestiaTransfer = ibc.WalletAmount{
169 | Address: slothUser.FormattedAddress(),
170 | Denom: s.Celestia.Config().Denom,
171 | Amount: transferAmount,
172 | }
173 | s.CelestiaIBCTransfer(celestiaToSlothChannel.ChannelID, celestiaUser.KeyName(), celestiaTransfer)
174 |
175 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.LazyChain, s.Stargaze, s.Celestia))
176 |
177 | // Change minimum gas price
178 | s.NoError(s.LazyChain.StopAllNodes(s.Ctx))
179 | for _, n := range s.LazyChain.Nodes() {
180 | s.NoError(testutil.ModifyTomlConfigFile(
181 | s.Ctx,
182 | zaptest.NewLogger(s.T()),
183 | n.DockerClient,
184 | s.T().Name(),
185 | n.VolumeName,
186 | "config/app.toml",
187 | testutil.Toml{
188 | "minimum-gas-prices": "0.025ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA",
189 | },
190 | ))
191 | }
192 | s.NoError(s.LazyChain.StartAllNodes(s.Ctx))
193 |
194 | s.NoError(testutil.WaitForBlocks(s.Ctx, 5, s.LazyChain, s.Stargaze, s.Celestia))
195 |
196 | newWallet, err := s.LazyChain.BuildWallet(s.Ctx, "newWallet", "")
197 | s.NoError(err)
198 | _, err = s.LazyChain.GetNode().ExecTx(s.Ctx,
199 | slothUser.KeyName(), "bank", "send", slothUser.KeyName(), newWallet.FormattedAddress(),
200 | "42000000ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA",
201 | "--gas-prices", "0.025ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA",
202 | )
203 | s.NoError(err)
204 |
205 | slothUserBal, err := s.LazyChain.GetBalance(s.Ctx, slothUser.FormattedAddress(), "ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA")
206 | s.NoError(err)
207 | newWalletBal, err := s.LazyChain.GetBalance(s.Ctx, newWallet.FormattedAddress(), "ibc/C3E53D20BC7A4CC993B17C7971F8ECD06A433C10B6A96F4C4C3714F0624C56DA")
208 | s.NoError(err)
209 |
210 | fmt.Println(slothUserBal.String())
211 |
212 | s.Equal(math.NewInt(42000000), newWalletBal)
213 | // Because gas
214 | s.Less(slothUserBal.Int64(), int64(58_000_000))
215 | s.Greater(slothUserBal.Int64(), int64(57_000_000))
216 | }
217 |
--------------------------------------------------------------------------------
/app/app_config.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
5 | capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types"
6 | ibcfeetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"
7 | ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
8 | ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported"
9 | sequencerv1 "github.com/decentrio/rollkit-sdk/api/rollkitsdk/sequencer/module"
10 | sequencertypes "github.com/decentrio/rollkit-sdk/x/sequencer/types"
11 |
12 | runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1"
13 | appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
14 | authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1"
15 | authzmodulev1 "cosmossdk.io/api/cosmos/authz/module/v1"
16 | bankmodulev1 "cosmossdk.io/api/cosmos/bank/module/v1"
17 | circuitmodulev1 "cosmossdk.io/api/cosmos/circuit/module/v1"
18 | consensusmodulev1 "cosmossdk.io/api/cosmos/consensus/module/v1"
19 | crisismodulev1 "cosmossdk.io/api/cosmos/crisis/module/v1"
20 | distrmodulev1 "cosmossdk.io/api/cosmos/distribution/module/v1"
21 | feegrantmodulev1 "cosmossdk.io/api/cosmos/feegrant/module/v1"
22 | genutilmodulev1 "cosmossdk.io/api/cosmos/genutil/module/v1"
23 | govmodulev1 "cosmossdk.io/api/cosmos/gov/module/v1"
24 | paramsmodulev1 "cosmossdk.io/api/cosmos/params/module/v1"
25 | stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1"
26 | txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1"
27 | upgrademodulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1"
28 | vestingmodulev1 "cosmossdk.io/api/cosmos/vesting/module/v1"
29 | "cosmossdk.io/core/appconfig"
30 | "cosmossdk.io/depinject"
31 | circuittypes "cosmossdk.io/x/circuit/types"
32 | "cosmossdk.io/x/feegrant"
33 | upgradetypes "cosmossdk.io/x/upgrade/types"
34 |
35 | "github.com/cosmos/cosmos-sdk/runtime"
36 | authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
37 | vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
38 | "github.com/cosmos/cosmos-sdk/x/authz"
39 | banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
40 | consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types"
41 | crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types"
42 | distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
43 | genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
44 | govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
45 | paramstypes "github.com/cosmos/cosmos-sdk/x/params/types"
46 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
47 |
48 | tokenfactorytypes "github.com/Stride-Labs/tokenfactory/tokenfactory/types"
49 | )
50 |
51 | var (
52 | // NOTE: The genutils module must occur after staking so that pools are
53 | // properly initialized with tokens from genesis accounts.
54 | // NOTE: The genutils module must also occur after auth so that it can access the params from auth.
55 | // NOTE: Capability module must occur first so that it can initialize any capabilities
56 | // so that other modules that want to create or claim capabilities afterwards in InitChain
57 | // can do so safely.
58 | genesisModuleOrder = []string{
59 | // cosmos-sdk/ibc modules
60 | capabilitytypes.ModuleName,
61 | authtypes.ModuleName,
62 | banktypes.ModuleName,
63 | distrtypes.ModuleName,
64 | sequencertypes.ModuleName,
65 | stakingtypes.ModuleName,
66 | govtypes.ModuleName,
67 | crisistypes.ModuleName,
68 | ibcexported.ModuleName,
69 | genutiltypes.ModuleName,
70 | authz.ModuleName,
71 | ibctransfertypes.ModuleName,
72 | ibcfeetypes.ModuleName,
73 | feegrant.ModuleName,
74 | paramstypes.ModuleName,
75 | upgradetypes.ModuleName,
76 | vestingtypes.ModuleName,
77 | consensustypes.ModuleName,
78 | circuittypes.ModuleName,
79 | // chain modules
80 | wasmtypes.ModuleName,
81 | tokenfactorytypes.ModuleName,
82 | // this line is used by starport scaffolding # stargate/app/initGenesis
83 | }
84 |
85 | // NOTE: staking module is required if HistoricalEntries param > 0
86 | // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC)
87 | beginBlockers = []string{
88 | // cosmos sdk modules
89 | distrtypes.ModuleName,
90 | stakingtypes.ModuleName,
91 | authz.ModuleName,
92 | genutiltypes.ModuleName,
93 | // ibc modules
94 | capabilitytypes.ModuleName,
95 | ibcexported.ModuleName,
96 | ibctransfertypes.ModuleName,
97 | ibcfeetypes.ModuleName,
98 | // chain modules
99 | wasmtypes.ModuleName,
100 | tokenfactorytypes.ModuleName,
101 | // this line is used by starport scaffolding # stargate/app/beginBlockers
102 | }
103 |
104 | endBlockers = []string{
105 | // cosmos sdk modules
106 | crisistypes.ModuleName,
107 | govtypes.ModuleName,
108 | sequencertypes.ModuleName,
109 | stakingtypes.ModuleName,
110 | feegrant.ModuleName,
111 | genutiltypes.ModuleName,
112 | // ibc modules
113 | ibcexported.ModuleName,
114 | ibctransfertypes.ModuleName,
115 | capabilitytypes.ModuleName,
116 | ibcfeetypes.ModuleName,
117 | // chain modules
118 | wasmtypes.ModuleName,
119 | tokenfactorytypes.ModuleName,
120 | // this line is used by starport scaffolding # stargate/app/endBlockers
121 | }
122 |
123 | preBlockers = []string{
124 | upgradetypes.ModuleName,
125 | // this line is used by starport scaffolding # stargate/app/preBlockers
126 | }
127 |
128 | // module account permissions
129 | moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
130 | {Account: authtypes.FeeCollectorName},
131 | {Account: distrtypes.ModuleName},
132 | {Account: stakingtypes.BondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}},
133 | {Account: stakingtypes.NotBondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}},
134 | {Account: govtypes.ModuleName, Permissions: []string{authtypes.Burner}},
135 | {Account: ibctransfertypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner}},
136 | {Account: ibcfeetypes.ModuleName},
137 | {Account: wasmtypes.ModuleName, Permissions: []string{authtypes.Burner}},
138 | {Account: tokenfactorytypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner}},
139 | // this line is used by starport scaffolding # stargate/app/maccPerms
140 | }
141 |
142 | // blocked account addresses
143 | blockAccAddrs = []string{
144 | authtypes.FeeCollectorName,
145 | distrtypes.ModuleName,
146 | stakingtypes.BondedPoolName,
147 | stakingtypes.NotBondedPoolName,
148 | }
149 |
150 | // appConfig application configuration (used by depinject)
151 | )
152 |
153 | func appConfig() depinject.Config {
154 | return appconfig.Compose(&appv1alpha1.Config{
155 | Modules: []*appv1alpha1.ModuleConfig{
156 | {
157 | Name: runtime.ModuleName,
158 | Config: appconfig.WrapAny(&runtimev1alpha1.Module{
159 | AppName: Name,
160 | PreBlockers: preBlockers,
161 | BeginBlockers: beginBlockers,
162 | EndBlockers: endBlockers,
163 | InitGenesis: genesisModuleOrder,
164 | OverrideStoreKeys: []*runtimev1alpha1.StoreKeyConfig{
165 | {
166 | ModuleName: authtypes.ModuleName,
167 | KvStoreKey: "acc",
168 | },
169 | },
170 | // When ExportGenesis is not specified, the export genesis module order
171 | // is equal to the init genesis order
172 | // ExportGenesis: genesisModuleOrder,
173 | // Uncomment if you want to set a custom migration order here.
174 | // OrderMigrations: nil,
175 | }),
176 | },
177 | {
178 | Name: authtypes.ModuleName,
179 | Config: appconfig.WrapAny(&authmodulev1.Module{
180 | Bech32Prefix: AccountAddressPrefix,
181 | ModuleAccountPermissions: moduleAccPerms,
182 | // By default modules authority is the governance module. This is configurable with the following:
183 | // Authority: "group", // A custom module authority can be set using a module name
184 | // Authority: "cosmos1cwwv22j5ca08ggdv9c2uky355k908694z577tv", // or a specific address
185 | }),
186 | },
187 | {
188 | Name: vestingtypes.ModuleName,
189 | Config: appconfig.WrapAny(&vestingmodulev1.Module{}),
190 | },
191 | {
192 | Name: banktypes.ModuleName,
193 | Config: appconfig.WrapAny(&bankmodulev1.Module{
194 | BlockedModuleAccountsOverride: blockAccAddrs,
195 | }),
196 | },
197 | {
198 | Name: stakingtypes.ModuleName,
199 | Config: appconfig.WrapAny(&stakingmodulev1.Module{
200 | // NOTE: specifying a prefix is only necessary when using bech32 addresses
201 | // If not specfied, the auth Bech32Prefix appended with "valoper" and "valcons" is used by default
202 | Bech32PrefixValidator: AccountAddressPrefix + "valoper",
203 | Bech32PrefixConsensus: AccountAddressPrefix + "valcons",
204 | }),
205 | },
206 | {
207 | Name: paramstypes.ModuleName,
208 | Config: appconfig.WrapAny(¶msmodulev1.Module{}),
209 | },
210 | {
211 | Name: "tx",
212 | Config: appconfig.WrapAny(&txconfigv1.Config{}),
213 | },
214 | {
215 | Name: genutiltypes.ModuleName,
216 | Config: appconfig.WrapAny(&genutilmodulev1.Module{}),
217 | },
218 | {
219 | Name: authz.ModuleName,
220 | Config: appconfig.WrapAny(&authzmodulev1.Module{}),
221 | },
222 | {
223 | Name: upgradetypes.ModuleName,
224 | Config: appconfig.WrapAny(&upgrademodulev1.Module{}),
225 | },
226 | {
227 | Name: distrtypes.ModuleName,
228 | Config: appconfig.WrapAny(&distrmodulev1.Module{}),
229 | },
230 | {
231 | Name: feegrant.ModuleName,
232 | Config: appconfig.WrapAny(&feegrantmodulev1.Module{}),
233 | },
234 | {
235 | Name: govtypes.ModuleName,
236 | Config: appconfig.WrapAny(&govmodulev1.Module{}),
237 | },
238 | {
239 | Name: crisistypes.ModuleName,
240 | Config: appconfig.WrapAny(&crisismodulev1.Module{}),
241 | },
242 | {
243 | Name: consensustypes.ModuleName,
244 | Config: appconfig.WrapAny(&consensusmodulev1.Module{}),
245 | },
246 | {
247 | Name: circuittypes.ModuleName,
248 | Config: appconfig.WrapAny(&circuitmodulev1.Module{}),
249 | },
250 | {
251 | Name: sequencertypes.ModuleName,
252 | Config: appconfig.WrapAny(&sequencerv1.Module{}),
253 | },
254 | // this line is used by starport scaffolding # stargate/app/moduleConfig
255 | },
256 | })
257 | }
258 |
--------------------------------------------------------------------------------
/interchaintest/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/Lazychain/lazychain/interchaintest
2 |
3 | go 1.22.2
4 |
5 | replace (
6 | // TODO: using version v1.0.0 causes a build failure. This is the previous version which compiles successfully.
7 | github.com/ChainSafe/go-schnorrkel => github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d
8 | github.com/ChainSafe/go-schnorrkel/1 => github.com/ChainSafe/go-schnorrkel v1.0.0
9 |
10 | github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
11 | // Necessary until better support for Rollkit is added to interchaintest
12 | github.com/strangelove-ventures/interchaintest/v8 => github.com/gjermundgaraba/interchaintest/v8 v8.0.0-20240508174758-4f9dee360813
13 | github.com/vedhavyas/go-subkey => github.com/strangelove-ventures/go-subkey v1.0.7
14 | )
15 |
16 | require (
17 | cosmossdk.io/math v1.3.0
18 | github.com/CosmWasm/wasmd v0.51.0
19 | github.com/cosmos/cosmos-sdk v0.50.6
20 | github.com/cosmos/ibc-go/v8 v8.2.0
21 | github.com/strangelove-ventures/interchaintest/v8 v8.2.0
22 | github.com/stretchr/testify v1.9.0
23 | go.uber.org/zap v1.27.0
24 | )
25 |
26 | require (
27 | cloud.google.com/go v0.112.0 // indirect
28 | cloud.google.com/go/compute v1.24.0 // indirect
29 | cloud.google.com/go/compute/metadata v0.2.3 // indirect
30 | cloud.google.com/go/iam v1.1.6 // indirect
31 | cloud.google.com/go/storage v1.37.0 // indirect
32 | cosmossdk.io/api v0.7.4 // indirect
33 | cosmossdk.io/collections v0.4.0 // indirect
34 | cosmossdk.io/core v0.11.0 // indirect
35 | cosmossdk.io/depinject v1.0.0-alpha.4 // indirect
36 | cosmossdk.io/errors v1.0.1 // indirect
37 | cosmossdk.io/log v1.3.1 // indirect
38 | cosmossdk.io/store v1.1.0 // indirect
39 | cosmossdk.io/x/evidence v0.1.0 // indirect
40 | cosmossdk.io/x/feegrant v0.1.0 // indirect
41 | cosmossdk.io/x/tx v0.13.3 // indirect
42 | cosmossdk.io/x/upgrade v0.1.1 // indirect
43 | filippo.io/edwards25519 v1.0.0 // indirect
44 | github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
45 | github.com/99designs/keyring v1.2.2 // indirect
46 | github.com/BurntSushi/toml v1.3.2 // indirect
47 | github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
48 | github.com/ChainSafe/go-schnorrkel/1 v0.0.0-00010101000000-000000000000 // indirect
49 | github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 // indirect
50 | github.com/CosmWasm/wasmvm/v2 v2.0.0 // indirect
51 | github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
52 | github.com/DataDog/zstd v1.5.5 // indirect
53 | github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect
54 | github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect
55 | github.com/Microsoft/go-winio v0.6.1 // indirect
56 | github.com/StirlingMarketingGroup/go-namecase v1.0.0 // indirect
57 | github.com/avast/retry-go/v4 v4.5.1 // indirect
58 | github.com/aws/aws-sdk-go v1.44.224 // indirect
59 | github.com/beorn7/perks v1.0.1 // indirect
60 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
61 | github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect
62 | github.com/bits-and-blooms/bitset v1.10.0 // indirect
63 | github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
64 | github.com/cenkalti/backoff/v4 v4.1.3 // indirect
65 | github.com/cespare/xxhash v1.1.0 // indirect
66 | github.com/cespare/xxhash/v2 v2.3.0 // indirect
67 | github.com/chzyer/readline v1.5.1 // indirect
68 | github.com/cockroachdb/errors v1.11.1 // indirect
69 | github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
70 | github.com/cockroachdb/pebble v1.1.0 // indirect
71 | github.com/cockroachdb/redact v1.1.5 // indirect
72 | github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
73 | github.com/cometbft/cometbft v0.38.6 // indirect
74 | github.com/cometbft/cometbft-db v0.10.0 // indirect
75 | github.com/cosmos/btcutil v1.0.5 // indirect
76 | github.com/cosmos/cosmos-db v1.0.2 // indirect
77 | github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
78 | github.com/cosmos/go-bip39 v1.0.0 // indirect
79 | github.com/cosmos/gogogateway v1.2.0 // indirect
80 | github.com/cosmos/gogoproto v1.4.12 // indirect
81 | github.com/cosmos/iavl v1.1.2 // indirect
82 | github.com/cosmos/ibc-go/modules/capability v1.0.0 // indirect
83 | github.com/cosmos/ics23/go v0.10.0 // indirect
84 | github.com/cosmos/interchain-security/v5 v5.0.0-alpha1.0.20240424193412-7cd900ad2a74 // indirect
85 | github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect
86 | github.com/danieljoos/wincred v1.1.2 // indirect
87 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
88 | github.com/deckarep/golang-set v1.8.0 // indirect
89 | github.com/decred/base58 v1.0.4 // indirect
90 | github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect
91 | github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1 // indirect
92 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
93 | github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
94 | github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
95 | github.com/dgraph-io/ristretto v0.1.1 // indirect
96 | github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
97 | github.com/distribution/reference v0.5.0 // indirect
98 | github.com/docker/distribution v2.8.2+incompatible // indirect
99 | github.com/docker/docker v24.0.9+incompatible // indirect
100 | github.com/docker/go-connections v0.5.0 // indirect
101 | github.com/docker/go-units v0.5.0 // indirect
102 | github.com/dustin/go-humanize v1.0.1 // indirect
103 | github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
104 | github.com/emicklei/dot v1.6.1 // indirect
105 | github.com/ethereum/go-ethereum v1.13.15 // indirect
106 | github.com/fatih/color v1.15.0 // indirect
107 | github.com/felixge/httpsnoop v1.0.4 // indirect
108 | github.com/fsnotify/fsnotify v1.7.0 // indirect
109 | github.com/getsentry/sentry-go v0.27.0 // indirect
110 | github.com/go-kit/kit v0.12.0 // indirect
111 | github.com/go-kit/log v0.2.1 // indirect
112 | github.com/go-logfmt/logfmt v0.6.0 // indirect
113 | github.com/go-logr/logr v1.4.1 // indirect
114 | github.com/go-logr/stdr v1.2.2 // indirect
115 | github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
116 | github.com/gogo/googleapis v1.4.1 // indirect
117 | github.com/gogo/protobuf v1.3.3 // indirect
118 | github.com/golang/glog v1.2.0 // indirect
119 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
120 | github.com/golang/mock v1.6.0 // indirect
121 | github.com/golang/protobuf v1.5.4 // indirect
122 | github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
123 | github.com/google/btree v1.1.2 // indirect
124 | github.com/google/go-cmp v0.6.0 // indirect
125 | github.com/google/gofuzz v1.2.0 // indirect
126 | github.com/google/orderedcode v0.0.1 // indirect
127 | github.com/google/s2a-go v0.1.7 // indirect
128 | github.com/google/uuid v1.6.0 // indirect
129 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
130 | github.com/googleapis/gax-go/v2 v2.12.0 // indirect
131 | github.com/gorilla/handlers v1.5.2 // indirect
132 | github.com/gorilla/mux v1.8.1 // indirect
133 | github.com/gorilla/websocket v1.5.0 // indirect
134 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
135 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
136 | github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
137 | github.com/gtank/merlin v0.1.1 // indirect
138 | github.com/gtank/ristretto255 v0.1.2 // indirect
139 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
140 | github.com/hashicorp/go-getter v1.7.3 // indirect
141 | github.com/hashicorp/go-hclog v1.5.0 // indirect
142 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
143 | github.com/hashicorp/go-metrics v0.5.3 // indirect
144 | github.com/hashicorp/go-plugin v1.5.2 // indirect
145 | github.com/hashicorp/go-safetemp v1.0.0 // indirect
146 | github.com/hashicorp/go-version v1.6.0 // indirect
147 | github.com/hashicorp/golang-lru v1.0.2 // indirect
148 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
149 | github.com/hashicorp/hcl v1.0.0 // indirect
150 | github.com/hashicorp/yamux v0.1.1 // indirect
151 | github.com/hdevalence/ed25519consensus v0.1.0 // indirect
152 | github.com/holiman/uint256 v1.2.4 // indirect
153 | github.com/huandu/skiplist v1.2.0 // indirect
154 | github.com/iancoleman/strcase v0.3.0 // indirect
155 | github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 // indirect
156 | github.com/improbable-eng/grpc-web v0.15.0 // indirect
157 | github.com/inconshreveable/mousetrap v1.1.0 // indirect
158 | github.com/ipfs/go-cid v0.4.1 // indirect
159 | github.com/jmespath/go-jmespath v0.4.0 // indirect
160 | github.com/jmhodges/levigo v1.0.0 // indirect
161 | github.com/klauspost/compress v1.17.7 // indirect
162 | github.com/klauspost/cpuid/v2 v2.2.5 // indirect
163 | github.com/kr/pretty v0.3.1 // indirect
164 | github.com/kr/text v0.2.0 // indirect
165 | github.com/lib/pq v1.10.7 // indirect
166 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect
167 | github.com/libp2p/go-libp2p v0.31.0 // indirect
168 | github.com/linxGnu/grocksdb v1.8.14 // indirect
169 | github.com/magiconair/properties v1.8.7 // indirect
170 | github.com/manifoldco/promptui v0.9.0 // indirect
171 | github.com/mattn/go-colorable v0.1.13 // indirect
172 | github.com/mattn/go-isatty v0.0.20 // indirect
173 | github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect
174 | github.com/minio/highwayhash v1.0.2 // indirect
175 | github.com/minio/sha256-simd v1.0.1 // indirect
176 | github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2 // indirect
177 | github.com/mitchellh/go-homedir v1.1.0 // indirect
178 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect
179 | github.com/mitchellh/mapstructure v1.5.0 // indirect
180 | github.com/mr-tron/base58 v1.2.0 // indirect
181 | github.com/mtibben/percent v0.2.1 // indirect
182 | github.com/multiformats/go-base32 v0.1.0 // indirect
183 | github.com/multiformats/go-base36 v0.2.0 // indirect
184 | github.com/multiformats/go-multiaddr v0.11.0 // indirect
185 | github.com/multiformats/go-multibase v0.2.0 // indirect
186 | github.com/multiformats/go-multicodec v0.9.0 // indirect
187 | github.com/multiformats/go-multihash v0.2.3 // indirect
188 | github.com/multiformats/go-varint v0.0.7 // indirect
189 | github.com/ncruces/go-strftime v0.1.9 // indirect
190 | github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
191 | github.com/oklog/run v1.1.0 // indirect
192 | github.com/opencontainers/go-digest v1.0.0 // indirect
193 | github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
194 | github.com/pelletier/go-toml v1.9.5 // indirect
195 | github.com/pelletier/go-toml/v2 v2.2.0 // indirect
196 | github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect
197 | github.com/pierrec/xxHash v0.1.5 // indirect
198 | github.com/pkg/errors v0.9.1 // indirect
199 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
200 | github.com/prometheus/client_golang v1.19.0 // indirect
201 | github.com/prometheus/client_model v0.6.1 // indirect
202 | github.com/prometheus/common v0.52.2 // indirect
203 | github.com/prometheus/procfs v0.13.0 // indirect
204 | github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
205 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
206 | github.com/rogpeppe/go-internal v1.12.0 // indirect
207 | github.com/rs/cors v1.8.3 // indirect
208 | github.com/rs/zerolog v1.32.0 // indirect
209 | github.com/sagikazarmark/locafero v0.4.0 // indirect
210 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect
211 | github.com/sasha-s/go-deadlock v0.3.1 // indirect
212 | github.com/sourcegraph/conc v0.3.0 // indirect
213 | github.com/spaolacci/murmur3 v1.1.0 // indirect
214 | github.com/spf13/afero v1.11.0 // indirect
215 | github.com/spf13/cast v1.6.0 // indirect
216 | github.com/spf13/cobra v1.8.0 // indirect
217 | github.com/spf13/pflag v1.0.5 // indirect
218 | github.com/spf13/viper v1.18.2 // indirect
219 | github.com/subosito/gotenv v1.6.0 // indirect
220 | github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
221 | github.com/tendermint/go-amino v0.16.0 // indirect
222 | github.com/tidwall/btree v1.7.0 // indirect
223 | github.com/tyler-smith/go-bip32 v1.0.0 // indirect
224 | github.com/tyler-smith/go-bip39 v1.1.0 // indirect
225 | github.com/ulikunitz/xz v0.5.11 // indirect
226 | github.com/zondax/hid v0.9.2 // indirect
227 | github.com/zondax/ledger-go v0.14.3 // indirect
228 | go.etcd.io/bbolt v1.3.8 // indirect
229 | go.opencensus.io v0.24.0 // indirect
230 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect
231 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
232 | go.opentelemetry.io/otel v1.22.0 // indirect
233 | go.opentelemetry.io/otel/metric v1.22.0 // indirect
234 | go.opentelemetry.io/otel/trace v1.22.0 // indirect
235 | go.uber.org/multierr v1.11.0 // indirect
236 | golang.org/x/crypto v0.22.0 // indirect
237 | golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
238 | golang.org/x/mod v0.17.0 // indirect
239 | golang.org/x/net v0.24.0 // indirect
240 | golang.org/x/oauth2 v0.18.0 // indirect
241 | golang.org/x/sync v0.7.0 // indirect
242 | golang.org/x/sys v0.19.0 // indirect
243 | golang.org/x/term v0.19.0 // indirect
244 | golang.org/x/text v0.14.0 // indirect
245 | golang.org/x/time v0.5.0 // indirect
246 | golang.org/x/tools v0.20.0 // indirect
247 | google.golang.org/api v0.162.0 // indirect
248 | google.golang.org/appengine v1.6.8 // indirect
249 | google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
250 | google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
251 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
252 | google.golang.org/grpc v1.63.2 // indirect
253 | google.golang.org/protobuf v1.33.0 // indirect
254 | gopkg.in/ini.v1 v1.67.0 // indirect
255 | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
256 | gopkg.in/yaml.v2 v2.4.0 // indirect
257 | gopkg.in/yaml.v3 v3.0.1 // indirect
258 | gotest.tools/v3 v3.5.1 // indirect
259 | lukechampine.com/blake3 v1.2.1 // indirect
260 | modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
261 | modernc.org/libc v1.41.0 // indirect
262 | modernc.org/mathutil v1.6.0 // indirect
263 | modernc.org/memory v1.7.2 // indirect
264 | modernc.org/sqlite v1.29.5 // indirect
265 | modernc.org/strutil v1.2.0 // indirect
266 | modernc.org/token v1.1.0 // indirect
267 | nhooyr.io/websocket v1.8.7 // indirect
268 | pgregory.net/rapid v1.1.0 // indirect
269 | sigs.k8s.io/yaml v1.4.0 // indirect
270 | )
271 |
--------------------------------------------------------------------------------
/interchaintest/utils/interchainvalues.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/CosmWasm/wasmd/x/wasm"
7 | sdk "github.com/cosmos/cosmos-sdk/types"
8 | sdktestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
9 | "github.com/pelletier/go-toml/v2"
10 | "github.com/strangelove-ventures/interchaintest/v8"
11 | "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
12 | "github.com/strangelove-ventures/interchaintest/v8/ibc"
13 | interchaintestrelayer "github.com/strangelove-ventures/interchaintest/v8/relayer"
14 | "github.com/strangelove-ventures/interchaintest/v8/relayer/hermes"
15 | "github.com/strangelove-ventures/interchaintest/v8/testreporter"
16 | "github.com/strangelove-ventures/interchaintest/v8/testutil"
17 | testifysuite "github.com/stretchr/testify/suite"
18 | "go.uber.org/zap/zaptest"
19 | "os"
20 | "strings"
21 | )
22 |
23 | type InterchainValues struct {
24 | // We hold a reference to this, so we can implement the s.NoError and get access to the T() method
25 | testifySuiteRef *testifysuite.Suite
26 | fakeT *FakeT
27 |
28 | Ctx context.Context
29 | Interchain *interchaintest.Interchain
30 | Network string
31 | Relayer ibc.Relayer
32 | RelayerExecRep *testreporter.RelayerExecReporter
33 | CelestiaSlothPath string
34 | StargazeSlothPath string
35 |
36 | LazyChain *cosmos.CosmosChain
37 | Celestia *cosmos.CosmosChain
38 | Stargaze *cosmos.CosmosChain
39 | }
40 |
41 | func (s *InterchainValues) SetupFakeT(name string) {
42 | if name == "" {
43 | name = "fake_test_name"
44 | }
45 |
46 | s.fakeT = &FakeT{
47 | FakeName: name,
48 | }
49 | }
50 |
51 | func (s *InterchainValues) GetFakeT() *FakeT {
52 | return s.fakeT
53 | }
54 |
55 | func (s *InterchainValues) TT() CustomT {
56 | if s.testifySuiteRef != nil {
57 | return s.testifySuiteRef.T()
58 | }
59 |
60 | return s.fakeT
61 | }
62 |
63 | func (s *InterchainValues) NoError(err error) {
64 | if s.testifySuiteRef != nil {
65 | s.testifySuiteRef.NoError(err)
66 | return
67 | }
68 |
69 | if err != nil {
70 | panic(err)
71 | }
72 | }
73 |
74 | func (s *InterchainValues) ErrorContains(err error, contains string) {
75 | if s.testifySuiteRef != nil {
76 | s.testifySuiteRef.ErrorContains(err, contains)
77 | return
78 | }
79 |
80 | if err == nil {
81 | panic("error is nil")
82 | }
83 |
84 | if !strings.Contains(err.Error(), contains) {
85 | panic(fmt.Sprintf("error does not contain %s", contains))
86 | }
87 | }
88 |
89 | func (s *InterchainValues) NotEmpty(value interface{}) {
90 | if s.testifySuiteRef != nil {
91 | s.testifySuiteRef.NotEmpty(value)
92 | return
93 | }
94 |
95 | if value == nil {
96 | panic("value is empty")
97 | }
98 | }
99 |
100 | func (s *InterchainValues) Len(value interface{}, length int) {
101 | if s.testifySuiteRef != nil {
102 | s.testifySuiteRef.Len(value, length)
103 | return
104 | }
105 |
106 | // TODO: Check better plz
107 | if value == nil {
108 | panic("value is empty")
109 | }
110 | }
111 |
112 | func (s *InterchainValues) Equal(expected, actual interface{}, msgAndArgs ...interface{}) {
113 | if s.testifySuiteRef != nil {
114 | s.testifySuiteRef.Equal(expected, actual, msgAndArgs)
115 | return
116 | }
117 |
118 | if expected != actual {
119 | panic(fmt.Sprintf("expected: %v, actual: %v", expected, actual))
120 | }
121 | }
122 |
123 | func (s *InterchainValues) True(value bool) {
124 | if s.testifySuiteRef != nil {
125 | s.testifySuiteRef.True(value)
126 | return
127 | }
128 |
129 | if !value {
130 | panic("value is not true")
131 | }
132 | }
133 |
134 | func (s *InterchainValues) NotNil(value interface{}) {
135 | if s.testifySuiteRef != nil {
136 | s.testifySuiteRef.NotNil(value)
137 | return
138 | }
139 |
140 | if value == nil {
141 | panic("value is nil")
142 | }
143 | }
144 |
145 | func (s *InterchainValues) SetupInterchainValues() {
146 | s.Ctx = context.Background()
147 |
148 | // Create a new Interchain object which describes the chains, relayers, and IBC connections we want to use
149 | ic := interchaintest.NewInterchain()
150 | s.Interchain = ic
151 | cf := s.getChainFactory()
152 | chains, err := cf.Chains(s.TT().Name())
153 | lazyChain, celestia, stargaze := chains[0].(*cosmos.CosmosChain), chains[1].(*cosmos.CosmosChain), chains[2].(*cosmos.CosmosChain)
154 | s.NoError(err)
155 | s.LazyChain = lazyChain
156 | s.Celestia = celestia
157 | s.Stargaze = stargaze
158 |
159 | for _, chain := range chains {
160 | ic.AddChain(chain)
161 | }
162 |
163 | client, network := interchaintest.DockerSetup(s.TT())
164 |
165 | rf := interchaintest.NewBuiltinRelayerFactory(
166 | //ibc.Hermes,
167 | ibc.CosmosRly,
168 | zaptest.NewLogger(s.TT()),
169 | //interchaintestrelayer.CustomDockerImage("ghcr.io/informalsystems/hermes", "1.10.0", "2000:2000"),
170 | interchaintestrelayer.CustomDockerImage("ghcr.io/cosmos/relayer", "latest", "100:1000"),
171 | interchaintestrelayer.StartupFlags("--processor", "events", "--block-history", "100"),
172 | )
173 | r := rf.Build(s.TT(), client, network)
174 | s.Relayer = r
175 |
176 | ic.AddRelayer(r, "relayer")
177 | s.StargazeSlothPath = "sg-sloth-path"
178 | ic.AddLink(interchaintest.InterchainLink{
179 | Chain1: stargaze,
180 | Chain2: lazyChain,
181 | Relayer: r,
182 | Path: s.StargazeSlothPath,
183 | })
184 | s.CelestiaSlothPath = "celestia-sloth-path"
185 | ic.AddLink(interchaintest.InterchainLink{
186 | Chain1: celestia,
187 | Chain2: lazyChain,
188 | Relayer: r,
189 | Path: s.CelestiaSlothPath,
190 | })
191 |
192 | rep := testreporter.NewNopReporter()
193 | eRep := rep.RelayerExecReporter(s.TT())
194 | s.RelayerExecRep = eRep
195 |
196 | err = ic.Build(s.Ctx, eRep, interchaintest.InterchainBuildOptions{
197 | TestName: s.TT().Name(),
198 | Client: client,
199 | NetworkID: network,
200 | SkipPathCreation: true,
201 | })
202 | s.NoError(err)
203 |
204 | //s.modifyHermesConfig(r.(*hermes.Relayer))
205 | //res := s.Relayer.Exec(s.Ctx, eRep, []string{"cat", "/home/hermes/.hermes/config.toml"}, nil)
206 | //s.TT().Log(string(res.Stdout))
207 |
208 | // For some reason automated path creation in Build didn't work when doing two paths 🤷
209 | s.NoError(s.Relayer.GeneratePath(s.Ctx, s.RelayerExecRep, s.Celestia.Config().ChainID, s.LazyChain.Config().ChainID, s.CelestiaSlothPath))
210 | s.NoError(s.Relayer.LinkPath(s.Ctx, s.RelayerExecRep, s.CelestiaSlothPath, ibc.DefaultChannelOpts(), ibc.DefaultClientOpts()))
211 |
212 | s.NoError(s.Relayer.GeneratePath(s.Ctx, s.RelayerExecRep, s.Stargaze.Config().ChainID, s.LazyChain.Config().ChainID, s.StargazeSlothPath))
213 | s.NoError(s.Relayer.LinkPath(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath, ibc.DefaultChannelOpts(), ibc.DefaultClientOpts()))
214 |
215 | s.TT().Cleanup(func() {
216 | _ = ic.Close()
217 | })
218 | }
219 |
220 | func (s *InterchainValues) getChainFactory() *interchaintest.BuiltinChainFactory {
221 | lazyChainImageRepository := "lazychain"
222 | lazyChainImageVersion := "local"
223 | envImageVersion, found := os.LookupEnv("LAZYCHAIN_IMAGE_VERSION")
224 | if found {
225 | s.TT().Log("LAZYCHAIN_IMAGE_VERSION from environment found", envImageVersion)
226 | lazyChainImageVersion = envImageVersion
227 | }
228 | envImageRepository, found := os.LookupEnv("LAZYCHAIN_IMAGE_REPOSITORY")
229 | if found {
230 | s.TT().Log("LAZYCHAIN_IMAGE_REPOSITORY from environment found", envImageRepository)
231 | lazyChainImageRepository = envImageRepository
232 | }
233 |
234 | s.TT().Log("LAZYCHAIN_IMAGE_VERSION", lazyChainImageVersion)
235 | s.TT().Log("LAZYCHAIN_IMAGE_REPOSITORY", lazyChainImageRepository)
236 |
237 | return interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(s.TT()), []*interchaintest.ChainSpec{
238 | {
239 | Name: "lazychain",
240 | ChainName: "lazychain",
241 | Version: lazyChainImageVersion,
242 | ChainConfig: ibc.ChainConfig{
243 | Type: "cosmos",
244 | Name: "lazychain",
245 | ChainID: lazyChainId,
246 | Images: []ibc.DockerImage{
247 | {
248 | Repository: lazyChainImageRepository,
249 | Version: lazyChainImageVersion,
250 | UidGid: "1025:1025",
251 | },
252 | },
253 | Bin: "lazychaind",
254 | Bech32Prefix: "lazy",
255 | Denom: "useq",
256 | CoinType: "118",
257 | GasPrices: "0.00useq",
258 | GasAdjustment: 2.0,
259 | TrustingPeriod: "112h",
260 | NoHostMount: false,
261 | ConfigFileOverrides: nil,
262 | EncodingConfig: getEncodingConfig(),
263 | ModifyGenesisAmounts: func(_ int) (sdk.Coin, sdk.Coin) {
264 | return sdk.NewInt64Coin("useq", 10_000_000_000_000), sdk.NewInt64Coin("useq", 1_000_000_000)
265 | },
266 | ModifyGenesis: func(config ibc.ChainConfig, bytes []byte) ([]byte, error) {
267 | addressBz, _, err := s.LazyChain.Validators[0].Exec(s.Ctx, []string{"jq", "-r", ".address", "/var/cosmos-chain/lazychain/config/priv_validator_key.json"}, []string{})
268 | if err != nil {
269 | return nil, err
270 | }
271 | address := strings.TrimSuffix(string(addressBz), "\n")
272 |
273 | pubKeyBz, _, err := s.LazyChain.Validators[0].Exec(s.Ctx, []string{"jq", "-r", ".pub_key.value", "/var/cosmos-chain/lazychain/config/priv_validator_key.json"}, []string{})
274 | if err != nil {
275 | return nil, err
276 | }
277 | pubKey := strings.TrimSuffix(string(pubKeyBz), "\n")
278 |
279 | pubKeyValueBz, _, err := s.LazyChain.Validators[0].Exec(s.Ctx, []string{"jq", "-r", ".pub_key .value", "/var/cosmos-chain/lazychain/config/priv_validator_key.json"}, []string{})
280 | if err != nil {
281 | return nil, err
282 | }
283 | pubKeyValue := strings.TrimSuffix(string(pubKeyValueBz), "\n")
284 |
285 | newGenesis := []cosmos.GenesisKV{
286 | {
287 | Key: "consensus.validators",
288 | Value: []map[string]interface{}{
289 | {
290 | "address": address,
291 | "pub_key": map[string]interface{}{
292 | "type": "tendermint/PubKeyEd25519",
293 | "value": pubKey,
294 | },
295 | "power": "1",
296 | "name": "Rollkit Sequencer",
297 | },
298 | },
299 | },
300 | {
301 | Key: "app_state.sequencer.sequencers",
302 | Value: []map[string]interface{}{
303 | {
304 | "name": "test-1",
305 | "consensus_pubkey": map[string]interface{}{
306 | "@type": "/cosmos.crypto.ed25519.PubKey",
307 | "key": pubKeyValue,
308 | },
309 | },
310 | },
311 | },
312 | }
313 |
314 | name := s.LazyChain.Sidecars[0].HostName()
315 | _, _, err = s.LazyChain.Validators[0].Exec(s.Ctx, []string{"sh", "-c", fmt.Sprintf(`echo "[rollkit]
316 | da_address = \"http://%s:%s\"" >> /var/cosmos-chain/lazychain/config/config.toml`, name, "7980")}, []string{})
317 | if err != nil {
318 | return nil, err
319 | }
320 |
321 | return cosmos.ModifyGenesis(newGenesis)(config, bytes)
322 | },
323 | AdditionalStartArgs: []string{"--rollkit.aggregator", "true", "--api.enable", "--api.enabled-unsafe-cors", "--rpc.laddr", "tcp://0.0.0.0:26657"},
324 | SidecarConfigs: []ibc.SidecarConfig{
325 | {
326 | ProcessName: "mock-da",
327 | Image: ibc.DockerImage{
328 | Repository: "ghcr.io/gjermundgaraba/mock-da",
329 | Version: "pessimist",
330 | UidGid: "1025:1025",
331 | },
332 | HomeDir: "",
333 | Ports: []string{"7980/tcp"},
334 | StartCmd: []string{"/usr/bin/mock-da", "-listen-all"},
335 | Env: nil,
336 | PreStart: true,
337 | ValidatorProcess: false,
338 | },
339 | },
340 | },
341 | NumValidators: &lazyVals,
342 | NumFullNodes: &lazyFullNodes,
343 | },
344 | {
345 | Name: "celestia",
346 | ChainName: "celestia",
347 | Version: "v1.9.0",
348 | ChainConfig: ibc.ChainConfig{
349 | Type: "cosmos",
350 | Name: "celestia",
351 | ChainID: celestiaChainID,
352 | Images: []ibc.DockerImage{
353 | {
354 | Repository: "ghcr.io/strangelove-ventures/heighliner/celestia",
355 | Version: "v1.9.0",
356 | UidGid: "1025:1025",
357 | },
358 | },
359 | Bin: "celestia-appd",
360 | Bech32Prefix: "celestia",
361 | Denom: "utia",
362 | CoinType: "118",
363 | GasPrices: "0.00utia",
364 | GasAdjustment: 2.0,
365 | TrustingPeriod: "112h",
366 | NoHostMount: false,
367 | ConfigFileOverrides: map[string]any{
368 | "config/config.toml": testutil.Toml{
369 | "storage": testutil.Toml{
370 | "discard_abci_responses": false,
371 | },
372 | "tx_index": testutil.Toml{
373 | "indexer": "kv",
374 | },
375 | },
376 | "config/app.toml": testutil.Toml{
377 | "grpc": testutil.Toml{
378 | "enable": true,
379 | },
380 | },
381 | },
382 | EncodingConfig: getEncodingConfig(),
383 | },
384 | NumValidators: &celestialVals,
385 | NumFullNodes: &celestialFullNodes,
386 | },
387 | {
388 | Name: "stargaze",
389 | ChainName: "stargaze",
390 | Version: "v13.0.0",
391 | ChainConfig: ibc.ChainConfig{
392 | Type: "cosmos",
393 | Name: "stargaze",
394 | ChainID: sgChainID,
395 | CoinType: "118",
396 | GasPrices: "0.00ustars",
397 | GasAdjustment: 2.0,
398 | EncodingConfig: getEncodingConfig(),
399 | },
400 | NumValidators: &stargazeVals,
401 | NumFullNodes: &stargazeFullNodes,
402 | },
403 | })
404 | }
405 |
406 | func getEncodingConfig() *sdktestutil.TestEncodingConfig {
407 | cfg := cosmos.DefaultEncoding()
408 |
409 | // register custom types
410 | // whatever.RegisterInterfaces(cfg.InterfaceRegistry)
411 | wasm.RegisterInterfaces(cfg.InterfaceRegistry)
412 |
413 | return &cfg
414 | }
415 |
416 | func (s *InterchainValues) modifyHermesConfig(h *hermes.Relayer) {
417 | bz, err := h.ReadFileFromHomeDir(s.Ctx, ".hermes/config.toml")
418 | s.NoError(err)
419 |
420 | var config map[string]interface{}
421 | err = toml.Unmarshal(bz, &config)
422 | s.NoError(err)
423 |
424 | chains, ok := config["chains"].([]interface{})
425 | s.True(ok)
426 | var celestia, lazychain map[string]interface{}
427 | for _, ci := range chains {
428 | c, ok := ci.(map[string]interface{})
429 | s.True(ok)
430 | if c["id"] == celestiaChainID {
431 | celestia = c
432 | } else if c["id"] == lazyChainId {
433 | lazychain = c
434 | }
435 | }
436 | s.NotNil(celestia)
437 |
438 | celestia["compat_mode"] = "0.34"
439 |
440 | lazychain["event_source"] = map[string]interface{}{
441 | "mode": "pull",
442 | "interval": "1s",
443 | "max_retries": 20,
444 | }
445 | //lazychain["compat_mode"] = "0.37"
446 |
447 | bz, err = toml.Marshal(config)
448 | s.NoError(err)
449 |
450 | err = h.WriteFileToHomeDir(s.Ctx, ".hermes/config.toml", bz)
451 | s.NoError(err)
452 | }
453 |
--------------------------------------------------------------------------------
/app/sim_test.go:
--------------------------------------------------------------------------------
1 | package app_test
2 |
3 | import (
4 | "encoding/json"
5 | "flag"
6 | "fmt"
7 | "math/rand"
8 | "os"
9 | "runtime/debug"
10 | "strings"
11 | "testing"
12 | "time"
13 |
14 | dbm "github.com/cosmos/cosmos-db"
15 | "github.com/spf13/viper"
16 | "github.com/stretchr/testify/require"
17 |
18 | "cosmossdk.io/log"
19 | "cosmossdk.io/store"
20 | storetypes "cosmossdk.io/store/types"
21 | "cosmossdk.io/x/feegrant"
22 |
23 | "github.com/cosmos/cosmos-sdk/baseapp"
24 | "github.com/cosmos/cosmos-sdk/client/flags"
25 | "github.com/cosmos/cosmos-sdk/server"
26 | simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
27 | simulationtypes "github.com/cosmos/cosmos-sdk/types/simulation"
28 | authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
29 | "github.com/cosmos/cosmos-sdk/x/simulation"
30 | simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
31 | slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
32 | stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
33 |
34 | abci "github.com/cometbft/cometbft/abci/types"
35 | cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
36 |
37 | "github.com/Lazychain/lazychain/app"
38 | )
39 |
40 | const (
41 | SimAppChainID = "lazychain-simapp"
42 | )
43 |
44 | var FlagEnableStreamingValue bool
45 |
46 | // Get flags every time the simulator is run
47 | func init() {
48 | simcli.GetSimulatorFlags()
49 | flag.BoolVar(&FlagEnableStreamingValue, "EnableStreaming", false, "Enable streaming service")
50 | }
51 |
52 | // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
53 | // an IAVLStore for faster simulation speed.
54 | func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
55 | bapp.SetFauxMerkleMode()
56 | }
57 |
58 | // interBlockCacheOpt returns a BaseApp option function that sets the persistent
59 | // inter-block write-through cache.
60 | func interBlockCacheOpt() func(*baseapp.BaseApp) {
61 | return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
62 | }
63 |
64 | // BenchmarkSimulation run the chain simulation
65 | // Running using starport command:
66 | // `ignite chain simulate -v --numBlocks 200 --blockSize 50`
67 | // Running as go benchmark test:
68 | // `go test -benchmem -run=^$ -bench ^BenchmarkSimulation ./app -NumBlocks=200 -BlockSize 50 -Commit=true -Verbose=true -Enabled=true`
69 | func BenchmarkSimulation(b *testing.B) {
70 | simcli.FlagSeedValue = time.Now().Unix()
71 | simcli.FlagVerboseValue = true
72 | simcli.FlagCommitValue = true
73 | simcli.FlagEnabledValue = true
74 |
75 | config := simcli.NewConfigFromFlags()
76 | config.ChainID = SimAppChainID
77 |
78 | db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim", "Simulation", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
79 | if skip {
80 | b.Skip("skipping application simulation")
81 | }
82 | require.NoError(b, err, "simulation setup failed")
83 |
84 | defer func() {
85 | require.NoError(b, db.Close())
86 | require.NoError(b, os.RemoveAll(dir))
87 | }()
88 |
89 | appOptions := make(simtestutil.AppOptionsMap, 0)
90 | appOptions[flags.FlagHome] = app.DefaultNodeHome
91 | appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue
92 |
93 | bApp, err := app.New(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID))
94 | require.NoError(b, err)
95 | require.Equal(b, app.Name, bApp.Name())
96 |
97 | // run randomized simulation
98 | _, simParams, simErr := simulation.SimulateFromSeed(
99 | b,
100 | os.Stdout,
101 | bApp.BaseApp,
102 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
103 | simulationtypes.RandomAccounts,
104 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
105 | app.BlockedAddresses(),
106 | config,
107 | bApp.AppCodec(),
108 | )
109 |
110 | // export state and simParams before the simulation error is checked
111 | err = simtestutil.CheckExportSimulation(bApp, config, simParams)
112 | require.NoError(b, err)
113 | require.NoError(b, simErr)
114 |
115 | if config.Commit {
116 | simtestutil.PrintStats(db)
117 | }
118 | }
119 |
120 | func TestAppImportExport(t *testing.T) {
121 | config := simcli.NewConfigFromFlags()
122 | config.ChainID = SimAppChainID
123 |
124 | db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim", "Simulation", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
125 | if skip {
126 | t.Skip("skipping application import/export simulation")
127 | }
128 | require.NoError(t, err, "simulation setup failed")
129 |
130 | defer func() {
131 | require.NoError(t, db.Close())
132 | require.NoError(t, os.RemoveAll(dir))
133 | }()
134 |
135 | appOptions := make(simtestutil.AppOptionsMap, 0)
136 | appOptions[flags.FlagHome] = app.DefaultNodeHome
137 | appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue
138 |
139 | bApp, err := app.New(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID))
140 | require.NoError(t, err)
141 | require.Equal(t, app.Name, bApp.Name())
142 |
143 | // Run randomized simulation
144 | _, simParams, simErr := simulation.SimulateFromSeed(
145 | t,
146 | os.Stdout,
147 | bApp.BaseApp,
148 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
149 | simulationtypes.RandomAccounts,
150 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
151 | app.BlockedAddresses(),
152 | config,
153 | bApp.AppCodec(),
154 | )
155 |
156 | // export state and simParams before the simulation error is checked
157 | err = simtestutil.CheckExportSimulation(bApp, config, simParams)
158 | require.NoError(t, err)
159 | require.NoError(t, simErr)
160 |
161 | if config.Commit {
162 | simtestutil.PrintStats(db)
163 | }
164 |
165 | fmt.Printf("exporting genesis...\n")
166 |
167 | exported, err := bApp.ExportAppStateAndValidators(false, []string{}, []string{})
168 | require.NoError(t, err)
169 |
170 | fmt.Printf("importing genesis...\n")
171 |
172 | newDB, newDir, _, _, err := simtestutil.SetupSimulation(config, "leveldb-app-sim-2", "Simulation-2", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
173 | require.NoError(t, err, "simulation setup failed")
174 |
175 | defer func() {
176 | require.NoError(t, newDB.Close())
177 | require.NoError(t, os.RemoveAll(newDir))
178 | }()
179 |
180 | newApp, err := app.New(log.NewNopLogger(), newDB, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID))
181 | require.NoError(t, err)
182 | require.Equal(t, app.Name, newApp.Name())
183 |
184 | var genesisState app.GenesisState
185 | err = json.Unmarshal(exported.AppState, &genesisState)
186 | require.NoError(t, err)
187 |
188 | ctxA := bApp.NewContextLegacy(true, cmtproto.Header{Height: bApp.LastBlockHeight()})
189 | ctxB := newApp.NewContextLegacy(true, cmtproto.Header{Height: bApp.LastBlockHeight()})
190 | _, err = newApp.ModuleManager.InitGenesis(ctxB, bApp.AppCodec(), genesisState)
191 |
192 | if err != nil {
193 | if strings.Contains(err.Error(), "validator set is empty after InitGenesis") {
194 | logger.Info("Skipping simulation as all validators have been unbonded")
195 | logger.Info("err", err, "stacktrace", string(debug.Stack()))
196 | return
197 | }
198 | }
199 | require.NoError(t, err)
200 | err = newApp.StoreConsensusParams(ctxB, exported.ConsensusParams)
201 | require.NoError(t, err)
202 | fmt.Printf("comparing stores...\n")
203 |
204 | // skip certain prefixes
205 | skipPrefixes := map[string][][]byte{
206 | stakingtypes.StoreKey: {
207 | stakingtypes.UnbondingQueueKey, stakingtypes.RedelegationQueueKey, stakingtypes.ValidatorQueueKey,
208 | stakingtypes.HistoricalInfoKey, stakingtypes.UnbondingIDKey, stakingtypes.UnbondingIndexKey,
209 | stakingtypes.UnbondingTypeKey, stakingtypes.ValidatorUpdatesKey,
210 | },
211 | authzkeeper.StoreKey: {authzkeeper.GrantQueuePrefix},
212 | feegrant.StoreKey: {feegrant.FeeAllowanceQueueKeyPrefix},
213 | slashingtypes.StoreKey: {slashingtypes.ValidatorMissedBlockBitmapKeyPrefix},
214 | }
215 |
216 | storeKeys := bApp.GetStoreKeys()
217 | require.NotEmpty(t, storeKeys)
218 |
219 | for _, appKeyA := range storeKeys {
220 | // only compare kvstores
221 | if _, ok := appKeyA.(*storetypes.KVStoreKey); !ok {
222 | continue
223 | }
224 |
225 | keyName := appKeyA.Name()
226 | appKeyB := newApp.GetKey(keyName)
227 |
228 | storeA := ctxA.KVStore(appKeyA)
229 | storeB := ctxB.KVStore(appKeyB)
230 |
231 | failedKVAs, failedKVBs := simtestutil.DiffKVStores(storeA, storeB, skipPrefixes[keyName])
232 | require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare %s", keyName)
233 |
234 | fmt.Printf("compared %d different key/value pairs between %s and %s\n", len(failedKVAs), appKeyA, appKeyB)
235 |
236 | require.Equal(t, 0, len(failedKVAs), simtestutil.GetSimulationLog(keyName, bApp.SimulationManager().StoreDecoders, failedKVAs, failedKVBs))
237 | }
238 | }
239 |
240 | func TestAppSimulationAfterImport(t *testing.T) {
241 | config := simcli.NewConfigFromFlags()
242 | config.ChainID = SimAppChainID
243 |
244 | db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim", "Simulation", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
245 | if skip {
246 | t.Skip("skipping application simulation after import")
247 | }
248 | require.NoError(t, err, "simulation setup failed")
249 |
250 | defer func() {
251 | require.NoError(t, db.Close())
252 | require.NoError(t, os.RemoveAll(dir))
253 | }()
254 |
255 | appOptions := make(simtestutil.AppOptionsMap, 0)
256 | appOptions[flags.FlagHome] = app.DefaultNodeHome
257 | appOptions[server.FlagInvCheckPeriod] = simcli.FlagPeriodValue
258 |
259 | bApp, err := app.New(logger, db, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID))
260 | require.NoError(t, err)
261 | require.Equal(t, app.Name, bApp.Name())
262 |
263 | // Run randomized simulation
264 | stopEarly, simParams, simErr := simulation.SimulateFromSeed(
265 | t,
266 | os.Stdout,
267 | bApp.BaseApp,
268 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
269 | simulationtypes.RandomAccounts,
270 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
271 | app.BlockedAddresses(),
272 | config,
273 | bApp.AppCodec(),
274 | )
275 |
276 | // export state and simParams before the simulation error is checked
277 | err = simtestutil.CheckExportSimulation(bApp, config, simParams)
278 | require.NoError(t, err)
279 | require.NoError(t, simErr)
280 |
281 | if config.Commit {
282 | simtestutil.PrintStats(db)
283 | }
284 |
285 | if stopEarly {
286 | fmt.Println("can't export or import a zero-validator genesis, exiting test...")
287 | return
288 | }
289 |
290 | fmt.Printf("exporting genesis...\n")
291 |
292 | exported, err := bApp.ExportAppStateAndValidators(true, []string{}, []string{})
293 | require.NoError(t, err)
294 |
295 | fmt.Printf("importing genesis...\n")
296 |
297 | newDB, newDir, _, _, err := simtestutil.SetupSimulation(config, "leveldb-app-sim-2", "Simulation-2", simcli.FlagVerboseValue, simcli.FlagEnabledValue)
298 | require.NoError(t, err, "simulation setup failed")
299 |
300 | defer func() {
301 | require.NoError(t, newDB.Close())
302 | require.NoError(t, os.RemoveAll(newDir))
303 | }()
304 |
305 | newApp, err := app.New(log.NewNopLogger(), newDB, nil, true, appOptions, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID))
306 | require.NoError(t, err)
307 | require.Equal(t, app.Name, newApp.Name())
308 |
309 | _, err = newApp.InitChain(&abci.RequestInitChain{
310 | AppStateBytes: exported.AppState,
311 | ChainId: SimAppChainID,
312 | })
313 | require.NoError(t, err)
314 |
315 | _, _, err = simulation.SimulateFromSeed(
316 | t,
317 | os.Stdout,
318 | newApp.BaseApp,
319 | simtestutil.AppStateFn(bApp.AppCodec(), bApp.SimulationManager(), bApp.DefaultGenesis()),
320 | simulationtypes.RandomAccounts,
321 | simtestutil.SimulationOperations(newApp, newApp.AppCodec(), config),
322 | app.BlockedAddresses(),
323 | config,
324 | bApp.AppCodec(),
325 | )
326 | require.NoError(t, err)
327 | }
328 |
329 | func TestAppStateDeterminism(t *testing.T) {
330 | if !simcli.FlagEnabledValue {
331 | t.Skip("skipping application simulation")
332 | }
333 |
334 | config := simcli.NewConfigFromFlags()
335 | config.InitialBlockHeight = 1
336 | config.ExportParamsPath = ""
337 | config.OnOperation = true
338 | config.AllInvariants = true
339 |
340 | numSeeds := 3
341 | numTimesToRunPerSeed := 3 // This used to be set to 5, but we've temporarily reduced it to 3 for the sake of faster CI.
342 | appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
343 |
344 | // We will be overriding the random seed and just run a single simulation on the provided seed value
345 | if config.Seed != simcli.DefaultSeedValue {
346 | numSeeds = 1
347 | }
348 |
349 | appOptions := viper.New()
350 | if FlagEnableStreamingValue {
351 | m := make(map[string]interface{})
352 | m["streaming.abci.keys"] = []string{"*"}
353 | m["streaming.abci.plugin"] = "abci_v1"
354 | m["streaming.abci.stop-node-on-err"] = true
355 | for key, value := range m {
356 | appOptions.SetDefault(key, value)
357 | }
358 | }
359 | appOptions.SetDefault(flags.FlagHome, app.DefaultNodeHome)
360 | appOptions.SetDefault(server.FlagInvCheckPeriod, simcli.FlagPeriodValue)
361 | if simcli.FlagVerboseValue {
362 | appOptions.SetDefault(flags.FlagLogLevel, "debug")
363 | }
364 |
365 | for i := 0; i < numSeeds; i++ {
366 | if config.Seed == simcli.DefaultSeedValue {
367 | config.Seed = rand.Int63()
368 | }
369 | fmt.Println("config.Seed: ", config.Seed)
370 |
371 | for j := 0; j < numTimesToRunPerSeed; j++ {
372 | var logger log.Logger
373 | if simcli.FlagVerboseValue {
374 | logger = log.NewTestLogger(t)
375 | } else {
376 | logger = log.NewNopLogger()
377 | }
378 | chainID := fmt.Sprintf("chain-id-%d-%d", i, j)
379 | config.ChainID = chainID
380 |
381 | db := dbm.NewMemDB()
382 | bApp, err := app.New(
383 | logger,
384 | db,
385 | nil,
386 | true,
387 | appOptions,
388 | interBlockCacheOpt(),
389 | baseapp.SetChainID(chainID),
390 | )
391 | require.NoError(t, err)
392 |
393 | fmt.Printf(
394 | "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n",
395 | config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
396 | )
397 |
398 | _, _, err = simulation.SimulateFromSeed(
399 | t,
400 | os.Stdout,
401 | bApp.BaseApp,
402 | simtestutil.AppStateFn(
403 | bApp.AppCodec(),
404 | bApp.SimulationManager(),
405 | bApp.DefaultGenesis(),
406 | ),
407 | simulationtypes.RandomAccounts,
408 | simtestutil.SimulationOperations(bApp, bApp.AppCodec(), config),
409 | app.BlockedAddresses(),
410 | config,
411 | bApp.AppCodec(),
412 | )
413 | require.NoError(t, err)
414 |
415 | if config.Commit {
416 | simtestutil.PrintStats(db)
417 | }
418 |
419 | appHash := bApp.LastCommitID().Hash
420 | appHashList[j] = appHash
421 |
422 | if j != 0 {
423 | require.Equal(
424 | t, string(appHashList[0]), string(appHashList[j]),
425 | "non-determinism in seed %d: %d/%d, attempt: %d/%d\n", config.Seed, i+1, numSeeds, j+1, numTimesToRunPerSeed,
426 | )
427 | }
428 | }
429 | }
430 | }
431 |
--------------------------------------------------------------------------------
/interchaintest/utils/helpers.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "context"
5 | "encoding/base64"
6 | "encoding/hex"
7 | "fmt"
8 | abci "github.com/cometbft/cometbft/abci/types"
9 | "github.com/cosmos/cosmos-sdk/client/flags"
10 | "github.com/cosmos/cosmos-sdk/crypto/keyring"
11 | sdk "github.com/cosmos/cosmos-sdk/types"
12 | "github.com/cosmos/gogoproto/proto"
13 | channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
14 | "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
15 | "github.com/strangelove-ventures/interchaintest/v8/ibc"
16 | "github.com/strangelove-ventures/interchaintest/v8/testutil"
17 | "google.golang.org/grpc"
18 | "google.golang.org/grpc/credentials/insecure"
19 | "path"
20 | "strconv"
21 | "strings"
22 | "time"
23 | )
24 |
25 | type NFTSetup struct {
26 | SGICS721Contract string
27 | LazyChainICS721Contract string
28 | LazyChainICS721IncomingProxyContract string
29 | CelestineSlothsContract string
30 | SGPort string
31 | SGChannel string
32 | LazyChainPort string
33 | LazyChainChannel string
34 | }
35 |
36 | func (s *InterchainValues) DeployNFTSetup(sgUser ibc.Wallet, slothUser ibc.Wallet, artifactsPath string) NFTSetup {
37 | sgCW721CodeID := s.StoreCW721(s.Stargaze, sgUser.KeyName(), artifactsPath)
38 | slothCW721CodeID := s.StoreCW721(s.LazyChain, slothUser.KeyName(), artifactsPath)
39 |
40 | slothContract := s.DeploySloths(slothCW721CodeID, sgUser)
41 | s.MintNFTs(slothContract, sgUser.KeyName(), sgUser.FormattedAddress(), []string{"1", "2", "3"})
42 |
43 | // Deploy incoming proxy contract on LazyChain
44 | lazyChainICS721Contract := s.DeployICS721(s.LazyChain, slothUser, artifactsPath, slothCW721CodeID)
45 |
46 | sgICS721Contract := s.DeployICS721(s.Stargaze, sgUser, artifactsPath, sgCW721CodeID)
47 |
48 | sgPortName := fmt.Sprintf("wasm.%s", sgICS721Contract)
49 | slothPortName := fmt.Sprintf("wasm.%s", lazyChainICS721Contract)
50 | channelOpts := ibc.CreateChannelOptions{
51 | SourcePortName: sgPortName,
52 | DestPortName: slothPortName,
53 | Order: ibc.Unordered,
54 | Version: "ics721-1",
55 | }
56 | clientOpts := ibc.CreateClientOptions{}
57 | s.NoError(s.Relayer.LinkPath(s.Ctx, s.RelayerExecRep, s.StargazeSlothPath, channelOpts, clientOpts))
58 |
59 | channels, err := s.Relayer.GetChannels(s.Ctx, s.RelayerExecRep, s.Stargaze.Config().ChainID)
60 | s.NoError(err)
61 | var sgChannel string
62 | var lazyChainChannel string
63 | for _, channel := range channels {
64 | if channel.PortID == sgPortName {
65 | sgChannel = channel.ChannelID
66 | lazyChainChannel = channel.Counterparty.ChannelID
67 | }
68 | }
69 | s.NotEmpty(sgChannel)
70 | s.NotEmpty(lazyChainChannel)
71 |
72 | ics721IncomingProxyContract := s.DeployICS721IncomingProxy(s.LazyChain, slothUser, artifactsPath, lazyChainICS721Contract, slothContract, lazyChainChannel)
73 | s.MigrateICS721(s.LazyChain, slothUser.KeyName(), artifactsPath, lazyChainICS721Contract, ics721IncomingProxyContract, slothCW721CodeID)
74 |
75 | return NFTSetup{
76 | SGICS721Contract: sgICS721Contract,
77 | LazyChainICS721Contract: lazyChainICS721Contract,
78 | LazyChainICS721IncomingProxyContract: ics721IncomingProxyContract,
79 | CelestineSlothsContract: slothContract,
80 | SGChannel: sgChannel,
81 | SGPort: sgPortName,
82 | LazyChainChannel: lazyChainChannel,
83 | LazyChainPort: slothPortName,
84 | }
85 | }
86 |
87 | func (s *InterchainValues) StoreCW721(chain *cosmos.CosmosChain, userKeyName string, artifactsFolderPath string) string {
88 | contractPath := path.Join(artifactsFolderPath, "cw721_base.wasm")
89 | codeID, err := chain.StoreContract(s.Ctx, userKeyName, contractPath, "--gas", "auto", "--gas-adjustment", "2")
90 | s.NoError(err)
91 |
92 | return codeID
93 | }
94 |
95 | func (s *InterchainValues) DeployICS721(
96 | chain *cosmos.CosmosChain,
97 | user ibc.Wallet,
98 | artifactsFolderPath string,
99 | cw721CodeID string,
100 | ) string {
101 | contractPath := path.Join(artifactsFolderPath, "ics721_base.wasm")
102 | sgICS721CodeID, err := chain.StoreContract(s.Ctx, user.KeyName(), contractPath, "--gas", "auto", "--gas-adjustment", "2")
103 | s.NoError(err)
104 |
105 | ics721InstantiateMsg := fmt.Sprintf("{\"cw721_base_code_id\": %s}", cw721CodeID)
106 |
107 | ics721Contract, err := chain.InstantiateContract(s.Ctx, user.KeyName(), sgICS721CodeID, ics721InstantiateMsg, false, "--admin", user.FormattedAddress(), "--gas", "auto", "--gas-adjustment", "2")
108 | s.NoError(err)
109 |
110 | return ics721Contract
111 | }
112 |
113 | func (s *InterchainValues) DeployICS721IncomingProxy(
114 | chain *cosmos.CosmosChain,
115 | user ibc.Wallet,
116 | artifactsFolderPath string,
117 | ics721Contract string,
118 | classID string,
119 | ics721Channel string,
120 | ) string {
121 | contractPath := path.Join(artifactsFolderPath, "cw_ics721_incoming_proxy_base.wasm")
122 | codeID, err := chain.StoreContract(s.Ctx, user.KeyName(), contractPath, "--gas", "auto", "--gas-adjustment", "2")
123 | s.NoError(err)
124 |
125 | incomingProxyInstantiateMsg := fmt.Sprintf("{\"origin\": \"%s\", \"class_ids\": [\"%s\"], \"channels\": [\"%s\"]}", ics721Contract, classID, ics721Channel)
126 | incomingProxyContract, err := chain.InstantiateContract(s.Ctx, user.KeyName(), codeID, incomingProxyInstantiateMsg, false, "--admin", user.FormattedAddress(), "--gas", "auto", "--gas-adjustment", "2")
127 | s.NoError(err)
128 |
129 | return incomingProxyContract
130 | }
131 |
132 | func (s *InterchainValues) MigrateICS721IncomingProxy(
133 | chain *cosmos.CosmosChain,
134 | userKeyName string,
135 | artifactsFolderPath string,
136 | ics721IncomingProxyContract string,
137 | classID string,
138 | ics721Contract string,
139 | ics721Channel string,
140 | ) {
141 | contractPath := path.Join(artifactsFolderPath, "cw_ics721_incoming_proxy_base.wasm")
142 | codeID, err := chain.StoreContract(s.Ctx, userKeyName, contractPath, "--gas", "auto", "--gas-adjustment", "2")
143 | s.NoError(err)
144 |
145 | migrateMsg := fmt.Sprintf("{\"with_update\": {\"origin\": \"%s\", \"class_ids\": [\"%s\"], \"channels\": [\"%s\"]}}", ics721Contract, classID, ics721Channel)
146 |
147 | txHash, err := chain.GetNode().ExecTx(
148 | s.Ctx,
149 | userKeyName,
150 | "wasm",
151 | "migrate", ics721IncomingProxyContract, codeID, migrateMsg,
152 | "--node", chain.GetRPCAddress(),
153 | "--home", chain.HomeDir(),
154 | "--chain-id", chain.Config().ChainID,
155 | "--from", userKeyName,
156 | "--gas", "500000",
157 | "--keyring-dir", chain.HomeDir(),
158 | "--keyring-backend", keyring.BackendTest,
159 | "-y",
160 | )
161 | s.NoError(err)
162 |
163 | txResp, err := chain.GetTransaction(txHash)
164 | s.NoError(err)
165 | s.Equal(uint32(0), txResp.Code, txResp.RawLog)
166 | }
167 |
168 | func (s *InterchainValues) MigrateICS721(
169 | chain *cosmos.CosmosChain,
170 | userKeyName string,
171 | artifactsFolderPath string,
172 | ics721Contract string,
173 | ics721IncomingProxy string,
174 | cw721CodeID string,
175 | ) {
176 | contractPath := path.Join(artifactsFolderPath, "ics721_base.wasm")
177 | codeID, err := chain.StoreContract(s.Ctx, userKeyName, contractPath, "--gas", "auto", "--gas-adjustment", "2")
178 | s.NoError(err)
179 |
180 | migrateMsg := fmt.Sprintf("{\"with_update\": {\"incoming_proxy\": \"%s\", \"cw721_base_code_id\": %s}}", ics721IncomingProxy, cw721CodeID)
181 |
182 | txHash, err := chain.GetNode().ExecTx(
183 | s.Ctx,
184 | userKeyName,
185 | "wasm",
186 | "migrate", ics721Contract, codeID, migrateMsg,
187 | "--node", chain.GetRPCAddress(),
188 | "--home", chain.HomeDir(),
189 | "--chain-id", chain.Config().ChainID,
190 | "--from", userKeyName,
191 | "--gas", "500000",
192 | "--keyring-dir", chain.HomeDir(),
193 | "--keyring-backend", keyring.BackendTest,
194 | "-y",
195 | )
196 | s.NoError(err)
197 |
198 | txResp, err := chain.GetTransaction(txHash)
199 | s.NoError(err)
200 | s.Equal(uint32(0), txResp.Code, txResp.RawLog)
201 | }
202 |
203 | func (s *InterchainValues) DeploySloths(slothCodeID string, sgUser ibc.Wallet) string {
204 | return s.InstantiateCW721(slothCodeID, sgUser.KeyName(), "Celestine Sloth Society", "CSS", sgUser.FormattedAddress())
205 | }
206 |
207 | func (s *InterchainValues) InstantiateCW721(contractAddress string, userKeyName string, name string, symbol string, minter string) string {
208 | instantiateMsg := fmt.Sprintf("{\"name\": \"%s\", \"symbol\": \"%s\", \"minter\": \"%s\"}", name, symbol, minter)
209 | contract, err := s.Stargaze.InstantiateContract(s.Ctx, userKeyName, contractAddress, instantiateMsg, true, "--gas", "auto", "--gas-adjustment", "2")
210 | s.NoError(err)
211 |
212 | return contract
213 | }
214 |
215 | func (s *InterchainValues) MintNFTs(cw721Contract string, sgUserKeyName string, mintTo string, tokenIds []string) {
216 | for _, tokenId := range tokenIds {
217 | slothCW721MintMsg := fmt.Sprintf("{\"mint\": {\"token_id\": \"%s\", \"owner\": \"%s\"}}", tokenId, mintTo)
218 | _, err := s.Stargaze.ExecuteContract(s.Ctx, sgUserKeyName, cw721Contract, slothCW721MintMsg)
219 | s.NoError(err)
220 | }
221 | }
222 |
223 | func (s *InterchainValues) TransferSlothToLazyChain(nftSetup NFTSetup, from ibc.Wallet, to ibc.Wallet, tokenId string) (classID string, contractAddress string) {
224 | s.NoError(s.TransferNFT(s.Stargaze, from, to, tokenId, nftSetup.CelestineSlothsContract, nftSetup.SGICS721Contract, nftSetup.SGChannel))
225 |
226 | s.NoError(testutil.WaitForBlocks(s.Ctx, 10, s.Stargaze, s.LazyChain, s.Celestia))
227 |
228 | type Response struct {
229 | Data [][]string `json:"data"`
230 | }
231 | var resp Response
232 | s.NoError(s.LazyChain.QueryContract(s.Ctx, nftSetup.LazyChainICS721Contract, "{\"nft_contracts\": {}}", &resp))
233 |
234 | s.Len(resp.Data, 1)
235 |
236 | return resp.Data[0][0], resp.Data[0][1]
237 | }
238 |
239 | func (s *InterchainValues) TransferSlothToStargaze(nftSetup NFTSetup, from ibc.Wallet, to ibc.Wallet, tokenId string, slothsContractOnLazyChain string) {
240 | s.NoError(s.TransferNFT(s.LazyChain, from, to, tokenId, slothsContractOnLazyChain, nftSetup.LazyChainICS721Contract, nftSetup.LazyChainChannel))
241 | }
242 |
243 | func (s *InterchainValues) TransferNFT(chain *cosmos.CosmosChain, from ibc.Wallet, to ibc.Wallet, tokenID string, nftContract string, ics721Contract string, channel string) error {
244 | now := time.Now()
245 | fiveMinutesLater := now.Add(5 * time.Minute)
246 | sendExecMsg := fmt.Sprintf("{\"receiver\": \"%s\",\n\"channel_id\": \"%s\",\n\"timeout\": { \"timestamp\": \"%d\"}}",
247 | to.FormattedAddress(),
248 | channel,
249 | fiveMinutesLater.UnixNano(),
250 | )
251 | sendExecMsgBase64 := base64.StdEncoding.EncodeToString([]byte(sendExecMsg))
252 |
253 | transferMsg := fmt.Sprintf("{\"send_nft\": {\"contract\": \"%s\", \"token_id\": \"%s\", \"msg\": \"%s\"}}",
254 | ics721Contract,
255 | tokenID,
256 | sendExecMsgBase64,
257 | )
258 |
259 | _, err := chain.ExecuteContract(s.Ctx, from.KeyName(), nftContract, transferMsg, "--gas", "auto", "--gas-adjustment", "2")
260 | return err
261 | }
262 |
263 | func (s *E2ETestSuite) AllNFTs(chain *cosmos.CosmosChain, contractAddress string) []string {
264 | type Response struct {
265 | Data struct {
266 | Tokens []string `json:"tokens"`
267 | } `json:"data"`
268 | }
269 | var resp Response
270 | s.NoError(chain.QueryContract(s.Ctx, contractAddress, "{\"all_tokens\": {}}", &resp))
271 |
272 | return resp.Data.Tokens
273 | }
274 |
275 | // Different versions makes the normal helper methods fail, so the celestia transfer is done more manually:
276 | func (s *InterchainValues) CelestiaIBCTransfer(channelID string, celestiaUserKeyName string, celestiaTransfer ibc.WalletAmount) {
277 | // Different versions makes the helper methods fail, so the celestia transfer is done more manually:
278 | txHash, err := s.Celestia.GetNode().SendIBCTransfer(s.Ctx, channelID, celestiaUserKeyName, celestiaTransfer, ibc.TransferOptions{})
279 | s.NoError(err)
280 | rpcNode, err := s.Celestia.GetNode().CliContext().GetNode()
281 | s.NoError(err)
282 | hash, err := hex.DecodeString(txHash)
283 | s.NoError(err)
284 | resTx, err := rpcNode.Tx(s.Ctx, hash, false)
285 | s.NoError(err)
286 | s.Equal(uint32(0), resTx.TxResult.Code)
287 | }
288 |
289 | // AssertPacketRelayed asserts that the packet commitment does not exist on the sending chain.
290 | // The packet commitment will be deleted upon a packet acknowledgement or timeout.
291 | func (s *InterchainValues) AssertPacketRelayed(chain *cosmos.CosmosChain, portID, channelID string, sequence uint64) {
292 | _, err := GRPCQuery[channeltypes.QueryPacketCommitmentResponse](s.Ctx, chain, &channeltypes.QueryPacketCommitmentRequest{
293 | PortId: portID,
294 | ChannelId: channelID,
295 | Sequence: sequence,
296 | })
297 | s.ErrorContains(err, "packet commitment hash not found")
298 | }
299 |
300 | // GRPCQuery queries the chain with a query request and deserializes the response to T
301 | func GRPCQuery[T any](ctx context.Context, chain ibc.Chain, req proto.Message, opts ...grpc.CallOption) (*T, error) {
302 | path, err := getProtoPath(req)
303 | if err != nil {
304 | return nil, err
305 | }
306 |
307 | // Create a connection to the gRPC server.
308 | grpcConn, err := grpc.Dial(
309 | chain.GetHostGRPCAddress(),
310 | grpc.WithTransportCredentials(insecure.NewCredentials()),
311 | )
312 | if err != nil {
313 | return nil, err
314 | }
315 |
316 | defer grpcConn.Close()
317 |
318 | resp := new(T)
319 | err = grpcConn.Invoke(ctx, path, req, resp, opts...)
320 | if err != nil {
321 | return nil, err
322 | }
323 |
324 | return resp, nil
325 | }
326 |
327 | func getProtoPath(req proto.Message) (string, error) {
328 | typeURL := "/" + proto.MessageName(req)
329 |
330 | switch {
331 | case strings.Contains(typeURL, "Query"):
332 | return getQueryProtoPath(typeURL)
333 | case strings.Contains(typeURL, "cosmos.base.tendermint"):
334 | return getCmtProtoPath(typeURL)
335 | default:
336 | return "", fmt.Errorf("unsupported typeURL: %s", typeURL)
337 | }
338 | }
339 |
340 | func getQueryProtoPath(queryTypeURL string) (string, error) {
341 | queryIndex := strings.Index(queryTypeURL, "Query")
342 | if queryIndex == -1 {
343 | return "", fmt.Errorf("invalid typeURL: %s", queryTypeURL)
344 | }
345 |
346 | // Add to the index to account for the length of "Query"
347 | queryIndex += len("Query")
348 |
349 | // Add a slash before the query
350 | urlWithSlash := queryTypeURL[:queryIndex] + "/" + queryTypeURL[queryIndex:]
351 | if !strings.HasSuffix(urlWithSlash, "Request") {
352 | return "", fmt.Errorf("invalid typeURL: %s", queryTypeURL)
353 | }
354 |
355 | return strings.TrimSuffix(urlWithSlash, "Request"), nil
356 | }
357 |
358 | func getCmtProtoPath(cmtTypeURL string) (string, error) {
359 | cmtIndex := strings.Index(cmtTypeURL, "Get")
360 | if cmtIndex == -1 {
361 | return "", fmt.Errorf("invalid typeURL: %s", cmtTypeURL)
362 | }
363 |
364 | // Add a slash before the commitment
365 | urlWithSlash := cmtTypeURL[:cmtIndex] + "Service/" + cmtTypeURL[cmtIndex:]
366 | if !strings.HasSuffix(urlWithSlash, "Request") {
367 | return "", fmt.Errorf("invalid typeURL: %s", cmtTypeURL)
368 | }
369 |
370 | return strings.TrimSuffix(urlWithSlash, "Request"), nil
371 | }
372 |
373 | // QueryTxsByEvents runs the QueryTxsByEvents command on the given chain.
374 | // https://github.com/cosmos/cosmos-sdk/blob/65ab2530cc654fd9e252b124ed24cbaa18023b2b/x/auth/client/cli/query.go#L33
375 | func (s *InterchainValues) QueryTxsByEvents(
376 | chain ibc.Chain,
377 | page, limit int, queryReq, orderBy string,
378 | ) (*sdk.SearchTxsResult, error) {
379 | cosmosChain, ok := chain.(*cosmos.CosmosChain)
380 | if !ok {
381 | return nil, fmt.Errorf("QueryTxsByEvents must be passed a cosmos.CosmosChain")
382 | }
383 |
384 | cmd := []string{"txs"}
385 |
386 | cmd = append(cmd, "--query", queryReq)
387 | // cmd = append(cmd, "--events", queryReq) ??
388 |
389 | if orderBy != "" {
390 | cmd = append(cmd, "--order_by", orderBy)
391 | }
392 | if page != 0 {
393 | cmd = append(cmd, "--"+flags.FlagPage, strconv.Itoa(page))
394 | }
395 | if limit != 0 {
396 | cmd = append(cmd, "--"+flags.FlagLimit, strconv.Itoa(limit))
397 | }
398 |
399 | stdout, _, err := cosmosChain.GetNode().ExecQuery(s.Ctx, cmd...)
400 | if err != nil {
401 | return nil, err
402 | }
403 |
404 | result := &sdk.SearchTxsResult{}
405 | err = getEncodingConfig().Codec.UnmarshalJSON(stdout, result)
406 | if err != nil {
407 | return nil, err
408 | }
409 |
410 | return result, nil
411 | }
412 |
413 | // ExtractValueFromEvents extracts the value of an attribute from a list of events.
414 | // If the attribute is not found, the function returns an empty string and false.
415 | // If the attribute is found, the function returns the value and true.
416 | func (*E2ETestSuite) ExtractValueFromEvents(events []abci.Event, eventType, attrKey string) (string, bool) {
417 | for _, event := range events {
418 | if event.Type != eventType {
419 | continue
420 | }
421 |
422 | for _, attr := range event.Attributes {
423 | if attr.Key != attrKey {
424 | continue
425 | }
426 |
427 | return attr.Value, true
428 | }
429 | }
430 |
431 | return "", false
432 | }
433 |
--------------------------------------------------------------------------------