{"id":13742323,"url":"https://github.com/crypto-com/chain-indexing","last_synced_at":"2026-01-14T11:59:33.635Z","repository":{"id":38384546,"uuid":"293032164","full_name":"crypto-com/chain-indexing","owner":"crypto-com","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-15T04:24:11.000Z","size":67634,"stargazers_count":34,"open_issues_count":99,"forks_count":31,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-15T11:11:29.030Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crypto-com.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-09-05T08:10:04.000Z","updated_at":"2025-10-15T04:22:49.000Z","dependencies_parsed_at":"2024-01-23T03:28:03.513Z","dependency_job_id":"cbd39630-c922-4ba1-af10-69528869272a","html_url":"https://github.com/crypto-com/chain-indexing","commit_stats":null,"previous_names":[],"tags_count":152,"template":false,"template_full_name":null,"purl":"pkg:github/crypto-com/chain-indexing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-com%2Fchain-indexing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-com%2Fchain-indexing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-com%2Fchain-indexing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-com%2Fchain-indexing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crypto-com","download_url":"https://codeload.github.com/crypto-com/chain-indexing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crypto-com%2Fchain-indexing/sbom","scorecard":{"id":310149,"data":{"date":"2025-08-11","repo":{"name":"github.com/crypto-com/chain-indexing","commit":"419de8fafc5ee86cc63a81d955237b71e31e3fbd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.8,"checks":[{"name":"Code-Review","score":9,"reason":"Found 11/12 approved changesets -- score normalized to 9","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":10,"reason":"12 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Info: topLevel 'contents' permission set to 'read': .github/workflows/golangci-lint.yml:5","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/crypto-com/chain-indexing/golangci-lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/crypto-com/chain-indexing/golangci-lint.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/golangci-lint.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/crypto-com/chain-indexing/golangci-lint.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/crypto-com/chain-indexing/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/crypto-com/chain-indexing/test.yml/master?enable=pin","Warn: containerImage not pinned by hash: docker/ginkgo/Dockerfile:1: pin your Docker image by updating golang:1.23 to golang:1.23@sha256:48701ce865534290020481ccb9a78f3b3e46352ba6f1270d987da9cccc591ce8","Warn: containerImage not pinned by hash: docker/postgres/Dockerfile:1: pin your Docker image by updating postgres:12.2 to postgres:12.2@sha256:d96835c9032988c8a899cb8a3c54467dae81daaa99485de70e8c9bddd5432d92","Warn: goCommand not pinned by hash: test.sh:165","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned","Info:   1 out of   2 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"61 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-1098 / GHSA-2chg-86hq-7w38","Warn: Project is vulnerable to: GO-2024-2818 / GHSA-3jgf-r68h-xfqm","Warn: Project is vulnerable to: GO-2024-3189 / GHSA-27vh-h6mc-q6g8","Warn: Project is vulnerable to: GHSA-23px-mw2p-46qm","Warn: Project is vulnerable to: GO-2023-1861 / GHSA-j2cr-jc39-wpx5","Warn: Project is vulnerable to: GO-2024-2571 / GHSA-2557-x9mg-76w8","Warn: Project is vulnerable to: GO-2024-2572 / GHSA-4j93-fm92-rp4m","Warn: Project is vulnerable to: GO-2024-2584 / GHSA-86h5-xcpx-cfqc","Warn: Project is vulnerable to: GO-2024-3339 / GHSA-8wcc-m6j2-qxvm","Warn: Project is vulnerable to: GO-2025-3476 / GHSA-x5vx-95h7-rv4p","Warn: Project is vulnerable to: GO-2025-3516 / GHSA-47ww-ff84-4jrg","Warn: Project is vulnerable to: GO-2025-3803 / GHSA-p22h-3m2v-cmgh","Warn: Project is vulnerable to: GO-2023-1821 / GHSA-qfc5-6r3j-jj22","Warn: Project is vulnerable to: GO-2023-1881 / GHSA-w5w5-2882-47pc","Warn: Project is vulnerable to: GO-2024-2874 / GHSA-qjcv-rx3v-7mvj","Warn: Project is vulnerable to: GO-2024-2694 / GHSA-j496-crgh-34mx","Warn: Project is vulnerable to: GO-2025-3494 / GHSA-jg6f-48ff-5xrw","Warn: Project is vulnerable to: GO-2025-3517 / GHSA-4wf3-5qj9-368v","Warn: Project is vulnerable to: GHSA-f854-hpxv-cw9r","Warn: Project is vulnerable to: GO-2022-0760 / GHSA-f92v-grc2-w2fg","Warn: Project is vulnerable to: GO-2022-0829 / GHSA-gwj5-wp6r-5q9f","Warn: Project is vulnerable to: GO-2023-2409 / GHSA-6294-6rgp-fr7r / GHSA-mhpq-9638-x6pw","Warn: Project is vulnerable to: GO-2022-0254 / GHSA-9856-9gg9-qcmq","Warn: Project is vulnerable to: GO-2022-0256 / GHSA-59hh-656j-3p7v","Warn: Project is vulnerable to: GO-2022-0456 / GHSA-wjxw-gh3m-7pm5","Warn: Project is vulnerable to: GO-2023-2046 / GHSA-ppjg-v974-84cm","Warn: Project is vulnerable to: GO-2024-2819 / GHSA-4xc9-8hmq-j652","Warn: Project is vulnerable to: GHSA-5m8f-chrv-7rw5","Warn: Project is vulnerable to: GHSA-pvx3-gm3c-gmpr","Warn: Project is vulnerable to: GHSA-rqmg-hrg4-fm69","Warn: Project is vulnerable to: GHSA-v9jh-j8px-98vq","Warn: Project is vulnerable to: GHSA-vmf7-hmh6-vv57","Warn: Project is vulnerable to: GHSA-vrcc-g6vj-mh5w","Warn: Project is vulnerable to: GO-2024-2606 / GHSA-7jwh-3vrq-q3m8 / GHSA-mrww-27vc-gghv","Warn: Project is vulnerable to: GO-2024-2605 / GHSA-m7wr-2xf7-cm9p","Warn: Project is vulnerable to: GO-2022-0322 / GHSA-cg3q-j54f-5p7p","Warn: Project is vulnerable to: GO-2022-0355 / GHSA-fx95-883v-4q4h","Warn: Project is vulnerable to: GO-2022-0968 / GHSA-gwc9-m7rh-j2ww","Warn: Project is vulnerable to: GO-2021-0356 / GHSA-8c26-wmh5-6g9v","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2022-0288","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GO-2023-2153 / GHSA-m425-mq94-257g / GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2022-0493 / GHSA-p782-xgp4-8hr8","Warn: Project is vulnerable to: GO-2022-1059 / GHSA-69ch-w2m2-3vjp","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37","Warn: Project is vulnerable to: GO-2022-0603 / GHSA-hp87-p4gw-j4gq","Warn: Project is vulnerable to: GO-2024-3279 / GHSA-7225-m954-23v7","Warn: Project is vulnerable to: GO-2025-3372 / GHSA-6wxm-mpqj-6jpf","Warn: Project is vulnerable to: GO-2025-3488 / GHSA-6v2p-p543-phr9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-17T23:02:32.331Z","repository_id":38384546,"created_at":"2025-08-17T23:02:32.331Z","updated_at":"2025-08-17T23:02:32.331Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28419272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T10:47:48.104Z","status":"ssl_error","status_checked_at":"2026-01-14T10:46:19.031Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T05:00:29.052Z","updated_at":"2026-01-14T11:59:33.629Z","avatar_url":"https://github.com/crypto-com.png","language":"Go","funding_links":[],"categories":["Indexings"],"sub_categories":["Desktop Wallet"],"readme":"# Crypto.com Chain Indexing Service\n\nCrypto.com Chain Indexing Service (chain-indexing) is a service to index all publicly available data on Crypto.com chain and persist structured information into storage.\n\nRight now it supports Postgres database and provides RESTful API as query interface.\n\n## 1. Usage\n\n```go\npackage main\n\nimport (\n    \"github.com/crypto-com/chain-indexing/external/ethereumtxinnermsgdecoder\"\n    \"os\"\n\n    applogger \"github.com/crypto-com/chain-indexing/external/logger\"\n    sysconfig \"github.com/crypto-com/chain-indexing/bootstrap/config\"\n    \"github.com/crypto-com/chain-indexing/bootstrap\"\n    \"github.com/crypto-com/chain-indexing/external/txdecoder\"\n    \"github.com/crypto-com/chain-indexing/infrastructure\"\n    \"github.com/crypto-com/chain-indexing/entity/projection\"\n)\n\nfunc main() {\n    // Init configurations...\n    logger := infrastructure.NewZerologLogger(os.Stdout)\n    config := sysconfig.Config{\n        // Init configurations...\n    }\n    // Init indexing app\n    app := bootstrap.NewApp(logger, \u0026config)\n    app.InitIndexService(\n        initProjections(logger, \u0026config),\n        initCronJobs(logger, \u0026config),\n        initTxdecoder(logger, \u0026config),\n        initEthereumTxInnerMsgDecoder(logger, \u0026config),\n    )\n    app.InitHTTPAPIServer(initRouteRegistry(logger, \u0026config))\n\n    // Run indexing app\n    app.Run()\n}\n\nfunc initProjections(\n    logger applogger.Logger,\n    config *sysconfig.Config,\n) []projection.Projection {\n    // append your Projections\n}\n\nfunc initCronJobs(\n    logger applogger.Logger,\n    config *sysconfig.Config,\n) []projection.CronJob {\n    // append your CronJobs\n}\n\nfunc initRouteRegistry(\n    logger applogger.Logger,\n    config *sysconfig.Config,\n) bootstrap.RouteRegistry {\n    // append your Routes\n}\n\nfunc initTxdecoder(\n    logger applogger.Logger,\n    config *sysconfig.Config,\n) txdecoder.TxDecoder {\n    // append your Routes\n}\n\nfunc initEthereumTxInnerMsgDecoder(\n    logger applogger.Logger,\n    config *sysconfig.Config,\n) ethereumtxinnermsgdecoder.EthereumTxInnerMsgDecoder {\n// append your Routes\n}\n```\n\n### Configuration\n```go\nconfig := bootstrap.Config{\n    FileConfig: bootstrap.FileConfig{\n        Blockchain: bootstrap.BlockchainConfig{\n            // Bonding denom of the blockchain\n            BondingDenom:           \"\",\n            // Account address prefix of the blockchain\n            AccountAddressPrefix:   \"\",\n            // Account public key prefix of the blockchain\n            AccountPubKeyPrefix:    \"\",\n            // Validator address prefix of the blockchain\n            ValidatorAddressPrefix: \"\",\n            // Validator public key prefix of the blockchain\n            ValidatorPubKeyPrefix:  \"\",\n        },\n        System: bootstrap.SystemConfig{\n            // \"EVENT_STORE\", \"TENDERMINT_DIRECT\", \"API_ONLY\"\n            Mode: \"\",\n        },\n        Sync: bootstrap.SyncConfig{\n            // Window size of Sunc process\n            WindowSize: 0,\n        },\n        Tendermint: bootstrap.TendermintConfig{\n            // HTTP address of Tendermint client\n            HTTPRPCUrl:           \"\",\n            // Connection type\n            Insecure:             false,\n            StrictGenesisParsing: false,\n        },\n        CosmosApp: bootstrap.CosmosAppConfig{\n            // HTTP address of Cosmos app client\n            HTTPRPCUrl: \"\",\n            // Connection type\n            Insecure:   false,\n        },\n        HTTP: bootstrap.HTTPConfig{\n            // HTTP address to be listened\n            ListeningAddress:   \"\",\n            // Prefix of all routes\n            RoutePrefix:        \"\",\n            // Allowed CORS for Origins\n            CorsAllowedOrigins: nil,\n            // Allowed CORS for Methods\n            CorsAllowedMethods: nil,\n            // Allowed CORS for Headers\n            CorsAllowedHeaders: nil,\n        },\n        Debug: bootstrap.DebugConfig{\n            // Enable pprof server\n            PprofEnable:           false,\n            // Pprof server address to be listened\n            PprofListeningAddress: \"\",\n        },\n        Database: bootstrap.DatabaseConfig{\n            // Connection type\n            SSL:      false,\n            // Database host\n            Host:     \"\",\n            // Database port\n            Port:     0,\n            // Database username\n            Username: \"\",\n            // Database password\n            Password: \"\",\n            // Database name\n            Name:     \"\",\n            // Database schema name\n            Schema:   \"\",\n        },\n        Postgres: bootstrap.PostgresConfig{\n            // Max connections of Database\n            MaxConns:            0,\n            // Min connections of Database\n            MinConns:            0,\n            // Max connections life time of Database\n            MaxConnLifeTime:     \"\",\n            // Max connections idle time of Database\n            MaxConnIdleTime:     \"\",\n            // Health check interval of Database\n            HealthCheckInterval: \"\",\n        },\n        Logger: bootstrap.LoggerConfig{\n            // LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_ERROR, LOG_LEVEL_PANIC, LOG_DISABLED\n            Level: (logger.LogLevel),\n            // Enable colered logs\n            Color: false,\n        },\n        CosmosVersionEnabledHeight: bootstrap.CosmosVersionEnabledHeightConfig{\n            // Block height from cosmos sdk version v0.42.7\n            V0_42_7: 0,\n        },\n        CronosVersionEnabledHeight: bootstrap.CronosVersionEnabledHeightConfig{\n            // Block height from cronos version v1.4.0-rc3\n            V1_4_0: 0,\n        },\n        CronosPosVersionEnabledHeight: bootstrap.CronosPosVersionEnabledHeightConfig{\n            // Block height from cronos pos version v6.0.0\n            V6_0_0: 0,\n        },\n        GithubAPI: bootstrap.GithubAPIConfig{\n            // Username of your git hub api account\n            Username:           \"username\",\n            // Token of your git hub api where at least have public repo access right\n            Token:              \"token\",\n            // Specific branch, tag or commit. Leave it empty if always using the latest master\n            MigrationRepoRef:   \"ref\",\n        },\n        Prometheus: bootstrap.PrometheusConfig{\n            Enable:     true,\n            ExportPath: \"/metrics\",\n            Port:       \"9090\",\n        },\n}\n```\n\n### Initial projections\n```go\npackage main\n\nimport (\n    \"github.com/ettle/strcase\"\n\n    \"github.com/crypto-com/chain-indexing/appinterface/cosmosapp\"\n    \"github.com/crypto-com/chain-indexing/appinterface/rdb\"\n    \"github.com/crypto-com/chain-indexing/bootstrap\"\n    sysconfig \"github.com/crypto-com/chain-indexing/bootstrap/config\"\n    projection_entity \"github.com/crypto-com/chain-indexing/entity/projection\"\n    applogger \"github.com/crypto-com/chain-indexing/external/logger\"\n    cosmosapp_infrastructure \"github.com/crypto-com/chain-indexing/infrastructure/cosmosapp\"\n    \"github.com/crypto-com/chain-indexing/infrastructure/pg\"\n    \"github.com/crypto-com/chain-indexing/infrastructure/pg/migrationhelper\"\n    github_migrationhelper \"github.com/crypto-com/chain-indexing/infrastructure/pg/migrationhelper/github\"\n    \"github.com/crypto-com/chain-indexing/projection/account\"\n    \"github.com/crypto-com/chain-indexing/projection/account_transaction\"\n)\n\nfunc initProjections(\n    logger applogger.Logger,\n    rdbConn rdb.Conn,\n    config *sysconfig.Config,\n) (projections []projection_entity.Projection) {\n    // Skip if API_ONLY is on\n    if !config.IndexService.Enable {\n        return projections\n    }\n\n    connString := rdbConn.(*pg.PgxConn).ConnString()\n    \n    githubMigrationHelperConfig := github_migrationhelper.Config{\n        GithubAPIUser:    config.IndexService.GithubAPI.Username,\n        GithubAPIToken:   config.IndexService.GithubAPI.Token,\n        MigrationRepoRef: config.IndexService.GithubAPI.MigrationRepoRef,\n        ConnString:       connString,\n    }\n\n    var cosmosAppClient cosmosapp.Client\n    if config.CosmosApp.Insecure {\n        cosmosAppClient = cosmosapp_infrastructure.NewInsecureHTTPClient(\n            config.CosmosApp.HTTPRPCUrl, config.Blockchain.BondingDenom,\n        )\n    } else {\n        cosmosAppClient = cosmosapp_infrastructure.NewHTTPClient(\n            config.CosmosApp.HTTPRPCUrl, config.Blockchain.BondingDenom,\n        )\n    }\n\n    sourceURL := github_migrationhelper.GenerateDefaultSourceURL(\"Account\", githubMigrationHelperConfig)\n    databaseURL := migrationhelper.GenerateDefaultDatabaseURL(\"Account\", connString)\n    migrationHelper := github_migrationhelper.NewGithubMigrationHelper(sourceURL, databaseURL)\n    \n    // Append `Account` projection\n    projections = append(account.NewAccount(logger, rdbConn, cosmosAppClient, migrationHelper). projections)\n\n    sourceURL = github_migrationhelper.GenerateDefaultSourceURL(\"AccountTransaction\", githubMigrationHelperConfig)\n    databaseURL = migrationhelper.GenerateDefaultDatabaseURL(\"AccountTransaction\", connString)\n    migrationHelper = github_migrationhelper.NewGithubMigrationHelper(sourceURL, databaseURL)\n\n    projections = append(account_transaction.NewAccountTransaction(logger, rdbConn, config.Blockchain.AccountAddressPrefix, migrationHelper), projections)\n\n    for _, projection := range projections {\n        if onInitErr := projection.OnInit(); onInitErr != nil {\n            logger.Errorf(\n                \"error initializing projection %s: %v\",\n                projection.Id(), onInitErr,\n            )\n        }\n    }\n\n    return projections\n}\n```\n\n#### Custom projection\n\n```go\npackage example\n\nimport (\n    \"fmt\"\n\n    applogger \"github.com/crypto-com/chain-indexing/external/logger\"\n    example_view \"your_view_packge\"\n\n    \"github.com/crypto-com/chain-indexing/appinterface/projection/rdbprojectionbase\"\n    \"github.com/crypto-com/chain-indexing/appinterface/rdb\"\n    event_entity \"github.com/crypto-com/chain-indexing/entity/event\"\n    event_usecase \"github.com/crypto-com/chain-indexing/usecase/event\"\n)\n\ntype AdditionalExampleProjection struct {\n    *rdbprojectionbase.Base\n\n    rdbConn      rdb.Conn\n    logger       applogger.Logger\n}\n\nfunc NewAdditionalProjection(\n    logger applogger.Logger,\n    rdbConn rdb.Conn,\n) *AdditionalExampleProjection {\n    return \u0026AdditionalExampleProjection{\n        rdbprojectionbase.NewRDbBase(rdbConn.ToHandle(), \"Example\"),\n        rdbConn,\n        logger,\n    }\n}\n\nvar (\n    NewExamplesView              = example_view.NewExamplesView\n    UpdateLastHandledEventHeight = (*AdditionalExampleProjection).UpdateLastHandledEventHeight\n)\n\nfunc (_ *AdditionalExampleProjection) GetEventsToListen() []string {\n    return event_usecase.MSG_EVENTS\n}\n\nfunc (projection *AdditionalExampleProjection) OnInit() error {\n    return nil\n}\n\nfunc (projection *AdditionalExampleProjection) HandleEvents(height int64, events []event_entity.Event) error {\n    rdbTx, err := projection.rdbConn.Begin()\n    if err != nil {\n        return fmt.Errorf(\"error beginning transaction: %v\", err)\n    }\n\n    committed := false\n    defer func() {\n        if !committed {\n            _ = rdbTx.Rollback()\n        }\n    }()\n\n    rdbTxHandle := rdbTx.ToHandle()\n\n    examplesView := NewExamplesView(rdbTxHandle)\n\n    for _, event := range events {\n        if typedEvent, ok := event.(*event_usecase.MsgSend); ok {\n            row := \u0026example_view.ExampleRow{\n                Address: typedEvent.ToAddress,\n                Balance: typedEvent.Amount,\n            }\n            if handleErr := projection.handleSomeEvent(examplesView, row); handleErr != nil {\n                return fmt.Errorf(\"error handling MsgSend: %v\", handleErr)\n            }\n        }\n    }\n\n    if err = UpdateLastHandledEventHeight(projection, rdbTxHandle, height); err != nil {\n        return fmt.Errorf(\"error updating last handled event height: %v\", err)\n    }\n\n    if err = rdbTx.Commit(); err != nil {\n        return fmt.Errorf(\"error committing changes: %v\", err)\n    }\n    committed = true\n\n    return nil\n}\n\nfunc (projection *AdditionalExampleProjection) handleSomeEvent(examplesView example_view.Examples, row *example_view.ExampleRow) error {\n    return examplesView.Insert(row)\n}\n```\n\n```go\npackage view\n\nimport (\n    \"fmt\"\n\n    \"github.com/crypto-com/chain-indexing/external/json\"\n\n    \"github.com/crypto-com/chain-indexing/usecase/coin\"\n\n    \"github.com/crypto-com/chain-indexing/appinterface/rdb\"\n    _ \"github.com/crypto-com/chain-indexing/test/factory\"\n)\n\ntype Examples interface {\n    Insert(*ExampleRow) error\n}\n\ntype ExamplesView struct {\n    rdb *rdb.Handle\n}\n\nfunc NewExamplesView(handle *rdb.Handle) Examples {\n    return \u0026ExamplesView{\n        handle,\n    }\n}\n\nfunc (exampleView *ExamplesView) Insert(example *ExampleRow) error {\n    sql, sqlArgs, err := exampleView.rdb.StmtBuilder.\n        Insert(\n            \"view_examples\",\n        ).\n        Columns(\n            \"address\",\n            \"balance\",\n        ).\n        Values(\n            example.Address,\n            json.MustMarshalToString(example.Balance),\n        ).\n        ToSql()\n\n    if err != nil {\n        return fmt.Errorf(\"error building examples insertion sql: %v: %w\", err, rdb.ErrBuildSQLStmt)\n    }\n\n    result, err := exampleView.rdb.Exec(sql, sqlArgs...)\n    if err != nil {\n        return fmt.Errorf(\"error inserting example into the table: %v: %w\", err, rdb.ErrWrite)\n    }\n    if result.RowsAffected() != 1 {\n        return fmt.Errorf(\"error inserting example into the table: no rows inserted: %w\", rdb.ErrWrite)\n    }\n\n    return nil\n}\n\ntype ExampleRow struct {\n    Address string     `json:\"address\"`\n    Balance coin.Coins `json:\"balance\"`\n}\n```\n\nAppend custom projection\n```go\nfunc initProjections(\n    logger applogger.Logger,\n    rdbConn rdb.Conn,\n    config *bootstrap.Config,\n    customConfig *CustomConfig,\n) (projections []projection.Projection) {\n    // ...\n\n    githubMigrationHelperConfigForCustomProjection := github_migrationhelper.Config{\n        GithubAPIUser:    config.IndexService.GithubAPI.Username,\n        GithubAPIToken:   config.IndexService.GithubAPI.Token,\n        MigrationRepoRef: customConfig.ServerGithubAPI.MigrationRepoRef,\n        ConnString:       connString,\n    }\n\n    sourceURL := generateGithubMigrationSrouceURLForCustomProjection(\"Example\", githubMigrationHelperConfigForCustomProjection)\n    databaseURL := migrationhelper.GenerateDefaultDatabaseURL(\"Example\", connString)\n    migrationHelper := github_migrationhelper.NewGithubMigrationHelper(sourceURL, databaseURL)\n\n    projections = append(example.NewAdditionalProjection(params.Logger, rdbConn, migrationHelper), projections)\n\n    return projections\n}\n```\n\n### Initial CronJobs\n```go\npackage main\n\nimport (\n    \"github.com/crypto-com/chain-indexing/appinterface/rdb\"\n    \"github.com/crypto-com/chain-indexing/bootstrap\"\n    sysconfig \"github.com/crypto-com/chain-indexing/bootstrap/config\"\n    projection_entity \"github.com/crypto-com/chain-indexing/entity/projection\"\n    applogger \"github.com/crypto-com/chain-indexing/external/logger\"\n    \"github.com/crypto-com/chain-indexing/infrastructure/pg\"\n    \"github.com/crypto-com/chain-indexing/infrastructure/pg/migrationhelper\"\n    github_migrationhelper \"github.com/crypto-com/chain-indexing/infrastructure/pg/migrationhelper/github\"\n    \"github.com/crypto-com/chain-indexing/projection/bridge_activity/bridge_activity_matcher\"\n)\n\nfunc initCronJobs(\n    logger applogger.Logger,\n    rdbConn rdb.Conn,\n    config *sysconfig.Config,\n) (crons []projection_entity.CronJob) {\n    // Skip if API_ONLY is on\n    if !config.IndexService.Enable {\n        return crons\n    }\n\n    connString := rdbConn.(*pg.PgxConn).ConnString()\n    \n    sourceURL := github_migrationhelper.GenerateSourceURL(\n        github_migrationhelper.MIGRATION_GITHUB_URL_FORMAT,\n        config.IndexService.GithubAPI.Username,\n        config.IndexService.GithubAPI.Token,\n        bridge_activity_matcher.MIGRATION_DIRECOTRY,\n        config.IndexService.GithubAPI.MigrationRepoRef,\n    )\n    databaseURL := migrationhelper.GenerateDefaultDatabaseURL(\"BridgeActivityMatcher\", connString)\n    migrationHelper := github_migrationhelper.NewGithubMigrationHelper(sourceURL, databaseURL)\n    \n    // Append `BridgeActivityMatcher` cron\n    crons = append(bridge_activity_matcher.New(\n        bridge_activity_matcher.Config{\n            // init config\n        },\n        logger,\n        rdbConn,\n        migrationHelper,\n        ). crons)\n\n    for _, cron := range crons {\n        if onInitErr := cron.OnInit(); onInitErr != nil {\n            logger.Errorf(\n                \"error initializing cronjob %s: %v\",\n                cron.Id(), onInitErr,\n            )\n        }\n    }\n    return crons\n}\n```\n\n### Initial route\n```go\npackage routes\n\nimport (\n    \"fmt\"\n\n    \"github.com/valyala/fasthttp\"\n\n    \"github.com/crypto-com/chain-indexing/infrastructure/httpapi\"\n    \"github.com/crypto-com/chain-indexing/appinterface/cosmosapp\"\n    \"github.com/crypto-com/chain-indexing/appinterface/rdb\"\n    \"github.com/crypto-com/chain-indexing/appinterface/tendermint\"\n    \"github.com/crypto-com/chain-indexing/bootstrap\"\n    sysconfig \"github.com/crypto-com/chain-indexing/bootstrap/config\"\n    applogger \"github.com/crypto-com/chain-indexing/external/logger\"\n    httpapi_handlers \"github.com/crypto-com/chain-indexing/infrastructure/httpapi/handlers\"\n)\n\ntype RouteRegistry struct {\n    routes []Route\n}\n\ntype Route struct {\n    Method  string\n    path    string\n    handler fasthttp.RequestHandler\n}\n\nfunc (registry *RouteRegistry) Register(server *httpapi.Server, routePrefix string) {\n    if routePrefix == \"/\" {\n        routePrefix = \"\"\n    }\n\n    for _, route := range registry.routes {\n        registerRoute(server, routePrefix, route)\n    }\n}\n\nfunc registerRoute(server *httpapi.Server, routePrefix string, route Route) {\n    switch route.Method {\n    case GET:\n        server.GET(fmt.Sprintf(\"%s/%s\", routePrefix, route.path), route.handler)\n    }\n}\n\nconst (\n    GET = \"GET\"\n)\n\nfunc InitRouteRegistry(\n    logger applogger.Logger,\n    rdbConn rdb.Conn,\n    config *sysconfig.Config,\n) bootstrap.RouteRegistry {\n    routes := make([]Route, 0)\n    searchHandler := httpapi_handlers.NewSearch(logger, rdbConn.ToHandle())\n    routes = append(routes,\n        Route{\n            Method:  GET,\n            path:    \"api/v1/search\",\n            handler: searchHandler.Search,\n        },\n    )\n\n    blocksHandler := httpapi_handlers.NewBlocks(logger, rdbConn.ToHandle())\n    routes = append(routes,\n        Route{\n            Method:  GET,\n            path:    \"api/v1/blocks\",\n            handler: blocksHandler.List,\n        },\n        Route{\n            Method:  GET,\n            path:    \"api/v1/blocks/{height-or-hash}\",\n            handler: blocksHandler.FindBy,\n        },\n        Route{\n            Method:  GET,\n            path:    \"api/v1/blocks/{height}/transactions\",\n            handler: blocksHandler.ListTransactionsByHeight,\n        },\n        Route{\n            Method:  GET,\n            path:    \"api/v1/blocks/{height}/events\",\n            handler: blocksHandler.ListEventsByHeight,\n        },\n        Route{\n            Method:  GET,\n            path:    \"api/v1/blocks/{height}/commitments\",\n            handler: blocksHandler.ListCommitmentsByHeight,\n        },\n    )\n\n    return \u0026RouteRegistry{routes: routes}\n}\n```\n\n## 2. Example implementation\n\n[Go here](https://github.com/crypto-com/chain-indexing/tree/master/example)\n\n## 3. Test\n\n```bash\n./test.sh [--install-dependency] [--no-db] [--watch]\n```\n\nProviding `--install-dependency` will attempt to install test runner [Ginkgo](https://github.com/onsi/ginkgo) if it is not installed before.\n\n## 4. Lint\n\n### With Local Installed golangci-lint\n\n#### Prerequisite\n\n- [golangci-lint](https://github.com/golangci/golangci-lint)\n\n```bash\n./lint.sh\n```\n\n### With Docker\n\n```bash\ndocker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.33 golangci-lint run -v\n```\n\n## 5. Contributing\n\nPlease abide by the [Code of Conduct](CODE_OF_CONDUCT.md) in all interactions,\nand the [contributing guidelines](CONTRIBUTING.md) when submitting code.\n\n## 6. License\n\n[Apache 2.0](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrypto-com%2Fchain-indexing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrypto-com%2Fchain-indexing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrypto-com%2Fchain-indexing/lists"}