├── 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 | --------------------------------------------------------------------------------