├── .coderabbit.yaml ├── .dockerignore ├── .envrc ├── .github ├── actions │ ├── default │ │ └── action.yml │ └── env │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── benchmark-comparison.yml │ ├── benchmark.yml │ ├── main.yml │ └── releases.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── CODEOWNERS ├── CONTRIBUTING.md ├── Earthfile ├── Justfile ├── LICENSE ├── README.md ├── build.Dockerfile ├── cmd ├── buckets.go ├── buckets_upgrade.go ├── buckets_upgrade_test.go ├── config.go ├── docs.go ├── docs_events.go ├── docs_flags.go ├── root.go ├── serve.go ├── version.go └── worker.go ├── deployments ├── docker-compose │ ├── otel-collector-config.yaml │ └── prometheus.yaml └── pulumi │ ├── .gitignore │ ├── .golangci.yml │ ├── Pulumi.yaml │ ├── README.md │ ├── docs │ ├── schema.json │ └── schema.md │ ├── examples │ └── stack1.yaml │ ├── go.mod │ ├── go.sum │ ├── justfile │ ├── main.go │ ├── main_test.go │ ├── pkg │ ├── api │ │ ├── component.go │ │ ├── deployment.go │ │ ├── ingress.go │ │ └── service.go │ ├── common │ │ └── common.go │ ├── component.go │ ├── config │ │ └── config.go │ ├── devbox │ │ └── component.go │ ├── generator │ │ └── component.go │ ├── monitoring │ │ └── monitoring.go │ ├── provision │ │ ├── component.go │ │ └── configmap.go │ ├── storage │ │ ├── component.go │ │ ├── component_external.go │ │ ├── component_postgres.go │ │ ├── component_rds.go │ │ ├── migrate.go │ │ ├── setup_postgres.go │ │ └── setup_rds.go │ ├── utils │ │ └── convert.go │ └── worker │ │ └── component.go │ └── tools │ └── main.go ├── docker-compose.yml ├── docs ├── api │ └── README.md ├── database │ ├── _default │ │ └── diagrams │ │ │ ├── orphans │ │ │ ├── orphans.dot │ │ │ └── orphans.png │ │ │ ├── summary │ │ │ ├── relationships.real.compact.dot │ │ │ ├── relationships.real.compact.png │ │ │ ├── relationships.real.large.dot │ │ │ └── relationships.real.large.png │ │ │ └── tables │ │ │ ├── accounts.1degree.dot │ │ │ ├── accounts.1degree.png │ │ │ ├── accounts.2degrees.dot │ │ │ ├── accounts.2degrees.png │ │ │ ├── accounts_metadata.1degree.dot │ │ │ ├── accounts_metadata.1degree.png │ │ │ ├── accounts_metadata.2degrees.dot │ │ │ ├── accounts_metadata.2degrees.png │ │ │ ├── accounts_volumes.1degree.dot │ │ │ ├── accounts_volumes.1degree.png │ │ │ ├── goose_db_version.1degree.dot │ │ │ ├── goose_db_version.1degree.png │ │ │ ├── logs.1degree.dot │ │ │ ├── logs.1degree.png │ │ │ ├── moves.1degree.dot │ │ │ ├── moves.1degree.png │ │ │ ├── moves.2degrees.dot │ │ │ ├── moves.2degrees.png │ │ │ ├── transactions.1degree.dot │ │ │ ├── transactions.1degree.png │ │ │ ├── transactions.2degrees.dot │ │ │ ├── transactions.2degrees.png │ │ │ ├── transactions_metadata.1degree.dot │ │ │ ├── transactions_metadata.1degree.png │ │ │ ├── transactions_metadata.2degrees.dot │ │ │ └── transactions_metadata.2degrees.png │ └── _system │ │ └── diagrams │ │ ├── orphans │ │ ├── orphans.dot │ │ └── orphans.png │ │ └── tables │ │ ├── goose_db_version.1degree.dot │ │ ├── goose_db_version.1degree.png │ │ ├── ledgers.1degree.dot │ │ └── ledgers.1degree.png └── events │ ├── CommittedTransactions.json │ ├── DeletedMetadata.json │ ├── RevertedTransaction.json │ └── SavedMetadata.json ├── examples ├── publisher-http │ ├── Caddyfile │ └── docker-compose.yml └── publisher-kafka │ └── docker-compose.yml ├── flake.lock ├── flake.nix ├── go.mod ├── go.sum ├── internal ├── README.md ├── account.go ├── api │ ├── bulking │ │ ├── bulker.go │ │ ├── bulker_test.go │ │ ├── elements.go │ │ ├── factory.go │ │ ├── handler_json.go │ │ ├── handler_json_test.go │ │ ├── handler_stream_json.go │ │ ├── handler_stream_json_test.go │ │ ├── handler_stream_text.go │ │ ├── handler_stream_text_test.go │ │ ├── mocks.go │ │ ├── mocks_ledger_controller_test.go │ │ ├── result.go │ │ ├── text_stream.go │ │ └── text_stream_test.go │ ├── common │ │ ├── context.go │ │ ├── errors.go │ │ ├── middleware_logid.go │ │ ├── middleware_resolver.go │ │ ├── middleware_resolver_test.go │ │ ├── mocks.go │ │ ├── mocks_ledger_controller_test.go │ │ ├── mocks_system_controller_test.go │ │ └── pagination.go │ ├── module.go │ ├── router.go │ ├── v1 │ │ ├── api_utils_test.go │ │ ├── controllers_accounts.go │ │ ├── controllers_accounts_add_metadata.go │ │ ├── controllers_accounts_add_metadata_test.go │ │ ├── controllers_accounts_count.go │ │ ├── controllers_accounts_count_test.go │ │ ├── controllers_accounts_delete_metadata.go │ │ ├── controllers_accounts_delete_metadata_test.go │ │ ├── controllers_accounts_list.go │ │ ├── controllers_accounts_list_test.go │ │ ├── controllers_accounts_read.go │ │ ├── controllers_accounts_read_test.go │ │ ├── controllers_balances_aggregates.go │ │ ├── controllers_balances_aggregates_test.go │ │ ├── controllers_balances_list.go │ │ ├── controllers_config.go │ │ ├── controllers_config_test.go │ │ ├── controllers_info.go │ │ ├── controllers_info_test.go │ │ ├── controllers_logs_list.go │ │ ├── controllers_logs_list_test.go │ │ ├── controllers_stats.go │ │ ├── controllers_stats_test.go │ │ ├── controllers_transactions.go │ │ ├── controllers_transactions_add_metadata.go │ │ ├── controllers_transactions_add_metadata_test.go │ │ ├── controllers_transactions_count.go │ │ ├── controllers_transactions_count_test.go │ │ ├── controllers_transactions_create.go │ │ ├── controllers_transactions_create_test.go │ │ ├── controllers_transactions_delete_metadata.go │ │ ├── controllers_transactions_delete_metadata_test.go │ │ ├── controllers_transactions_list.go │ │ ├── controllers_transactions_list_test.go │ │ ├── controllers_transactions_read.go │ │ ├── controllers_transactions_read_test.go │ │ ├── controllers_transactions_revert.go │ │ ├── controllers_transactions_revert_test.go │ │ ├── middleware_auto_create_ledger.go │ │ ├── mocks.go │ │ ├── mocks_ledger_controller_test.go │ │ ├── mocks_system_controller_test.go │ │ ├── query.go │ │ ├── routes.go │ │ └── utils.go │ └── v2 │ │ ├── api_utils_test.go │ │ ├── common.go │ │ ├── controllers_accounts_add_metadata.go │ │ ├── controllers_accounts_add_metadata_test.go │ │ ├── controllers_accounts_count.go │ │ ├── controllers_accounts_count_test.go │ │ ├── controllers_accounts_delete_metadata.go │ │ ├── controllers_accounts_delete_metadata_test.go │ │ ├── controllers_accounts_list.go │ │ ├── controllers_accounts_list_test.go │ │ ├── controllers_accounts_read.go │ │ ├── controllers_accounts_read_test.go │ │ ├── controllers_balances.go │ │ ├── controllers_balances_test.go │ │ ├── controllers_bulk.go │ │ ├── controllers_bulk_test.go │ │ ├── controllers_ledgers_create.go │ │ ├── controllers_ledgers_create_test.go │ │ ├── controllers_ledgers_delete_metadata.go │ │ ├── controllers_ledgers_delete_metadata_test.go │ │ ├── controllers_ledgers_info.go │ │ ├── controllers_ledgers_info_test.go │ │ ├── controllers_ledgers_list.go │ │ ├── controllers_ledgers_list_test.go │ │ ├── controllers_ledgers_read.go │ │ ├── controllers_ledgers_read_test.go │ │ ├── controllers_ledgers_update_metadata.go │ │ ├── controllers_ledgers_update_metadata_test.go │ │ ├── controllers_logs_export.go │ │ ├── controllers_logs_export_test.go │ │ ├── controllers_logs_import.go │ │ ├── controllers_logs_import_test.go │ │ ├── controllers_logs_list.go │ │ ├── controllers_logs_list_test.go │ │ ├── controllers_stats.go │ │ ├── controllers_stats_test.go │ │ ├── controllers_transactions_add_metadata.go │ │ ├── controllers_transactions_add_metadata_test.go │ │ ├── controllers_transactions_count.go │ │ ├── controllers_transactions_count_test.go │ │ ├── controllers_transactions_create.go │ │ ├── controllers_transactions_create_test.go │ │ ├── controllers_transactions_delete_metadata.go │ │ ├── controllers_transactions_delete_metadata_test.go │ │ ├── controllers_transactions_list.go │ │ ├── controllers_transactions_list_test.go │ │ ├── controllers_transactions_read.go │ │ ├── controllers_transactions_read_test.go │ │ ├── controllers_transactions_revert.go │ │ ├── controllers_transactions_revert_test.go │ │ ├── controllers_volumes.go │ │ ├── controllers_volumes_test.go │ │ ├── mocks.go │ │ ├── mocks_ledger_controller_test.go │ │ ├── mocks_system_controller_test.go │ │ ├── query.go │ │ └── routes.go ├── bigint.go ├── bus │ ├── listener.go │ ├── listener_test.go │ ├── message.go │ └── module.go ├── controller │ ├── ledger │ │ ├── README.md │ │ ├── controller.go │ │ ├── controller_default.go │ │ ├── controller_default_test.go │ │ ├── controller_generated_test.go │ │ ├── controller_with_cache.go │ │ ├── controller_with_events.go │ │ ├── controller_with_too_many_client_handling.go │ │ ├── controller_with_too_many_client_handling_generated_test.go │ │ ├── controller_with_too_many_client_handling_test.go │ │ ├── controller_with_traces.go │ │ ├── errors.go │ │ ├── export.go │ │ ├── listener.go │ │ ├── listener_generated_test.go │ │ ├── log_process.go │ │ ├── log_process_test.go │ │ ├── mocks.go │ │ ├── mocks_test.go │ │ ├── numscript.go │ │ ├── numscript_parser.go │ │ ├── numscript_parser_generated_test.go │ │ ├── numscript_runtime.go │ │ ├── numscript_runtime_generated_test.go │ │ ├── parameters.go │ │ ├── state_registry.go │ │ ├── stats.go │ │ ├── stats_test.go │ │ ├── store.go │ │ └── store_generated_test.go │ └── system │ │ ├── controller.go │ │ ├── errors.go │ │ ├── module.go │ │ ├── state_tracker.go │ │ └── store.go ├── doc.go ├── errors.go ├── ledger.go ├── ledger_test.go ├── log.go ├── machine │ ├── account.go │ ├── address.go │ ├── allotment.go │ ├── allotment_test.go │ ├── asset.go │ ├── docs │ │ ├── instructions.md │ │ └── types.md │ ├── errors.go │ ├── examples │ │ └── basic.go │ ├── funding.go │ ├── funding_test.go │ ├── json.go │ ├── json_test.go │ ├── monetary.go │ ├── number.go │ ├── portion.go │ ├── portion_test.go │ ├── script │ │ ├── NumScript.g4 │ │ ├── compiler │ │ │ ├── allotment.go │ │ │ ├── compiler.go │ │ │ ├── compiler_test.go │ │ │ ├── destination.go │ │ │ ├── error.go │ │ │ ├── error_test.go │ │ │ ├── program.go │ │ │ └── source.go │ │ ├── generate.go │ │ ├── generate.sh │ │ └── parser │ │ │ ├── NumScript.interp │ │ │ ├── NumScript.tokens │ │ │ ├── NumScriptLexer.interp │ │ │ ├── NumScriptLexer.tokens │ │ │ ├── numscript_base_listener.go │ │ │ ├── numscript_lexer.go │ │ │ ├── numscript_listener.go │ │ │ └── numscript_parser.go │ ├── value.go │ └── vm │ │ ├── machine.go │ │ ├── machine_kept_test.go │ │ ├── machine_overdraft_test.go │ │ ├── machine_test.go │ │ ├── program │ │ ├── instructions.go │ │ ├── program.go │ │ ├── program_test.go │ │ ├── resource.go │ │ └── resource_test.go │ │ ├── run.go │ │ ├── run_test.go │ │ ├── stack.go │ │ └── store.go ├── metadata.go ├── moves.go ├── posting.go ├── storage │ ├── bucket │ │ ├── bucket.go │ │ ├── bucket_generated_test.go │ │ ├── default_bucket.go │ │ ├── default_bucket_test.go │ │ ├── main_test.go │ │ ├── migrations.go │ │ ├── migrations │ │ │ ├── 0-init-schema │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ └── up_tests_after.sql │ │ │ ├── 1-fix-trigger │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 10-fillfactor-on-moves │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 11-make-stateless │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 12-transaction-sequence-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 13-accounts-sequence-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 14-transaction-reference-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 15-create-ledger-indexes │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 16-create-transaction-id-index-on-moves │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 17-moves-fill-transaction-id │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ ├── up_tests_after.sql │ │ │ │ └── up_tests_before.sql │ │ │ ├── 18-transactions-fill-inserted-at │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ ├── up_tests_after.sql │ │ │ │ └── up_tests_before.sql │ │ │ ├── 19-transactions-fill-pcv │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ ├── up_tests_after.sql │ │ │ │ └── up_tests_before.sql │ │ │ ├── 2-fix-volumes-aggregation │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 20-accounts-volumes-fill-history │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 21-transactions-metadata-fill-transaction-id │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 22-accounts-metadata-fill-address │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 23-logs-fill-memento │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 24-accounts-metadata-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 25-accounts-volumes-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 26-fix-hashing-function │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 27-fix-invalid-pcv │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 28-fix-pcv-missing-asset │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 29-fix-invalid-metadata-on-reverts │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ ├── up_tests_after.sql │ │ │ │ └── up_tests_before.sql │ │ │ ├── 3-fix-trigger-inserting-backdated-transactions │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 30-transaction-updated-at-trigger │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 31-fix-transaction-updated-at │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ └── up_tests_after.sql │ │ │ ├── 32-fix-log-data-for-reverted-transactions │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ └── up_tests_after.sql │ │ │ ├── 33-fix-invalid-date-format │ │ │ │ ├── notes.yaml │ │ │ │ ├── up.sql │ │ │ │ └── up_tests_after.sql │ │ │ ├── 34-fix-memento-format │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 35-create-compute-hash-function │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 36-accounts-recreate-unique-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 37-clean-database │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 38-logs-async-hash-procedure │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 39-clean-useless-features │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 4-add-account-first-usage-column │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 40-refine-columns-types │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 5-add-idempotency-key-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 6-add-reference-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 7-add-ik-unique-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ ├── 8-ik-ledger-unique-index │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ │ └── 9-fix-incorrect-volumes-aggregation │ │ │ │ ├── notes.yaml │ │ │ │ └── up.sql │ │ └── migrations_test.go │ ├── common │ │ ├── errors.go │ │ ├── metadata.go │ │ ├── paginator.go │ │ ├── paginator_column.go │ │ ├── paginator_offset.go │ │ └── resource.go │ ├── driver │ │ ├── adapters.go │ │ ├── buckets_generated_test.go │ │ ├── driver.go │ │ ├── driver_test.go │ │ ├── errors.go │ │ ├── ledger_generated_test.go │ │ ├── main_test.go │ │ ├── mocks.go │ │ ├── module.go │ │ ├── rollbacks.go │ │ └── system_generated_test.go │ ├── ledger │ │ ├── accounts.go │ │ ├── accounts_test.go │ │ ├── adapters.go │ │ ├── balances.go │ │ ├── balances_test.go │ │ ├── debug.go │ │ ├── factory.go │ │ ├── logs.go │ │ ├── logs_test.go │ │ ├── main_test.go │ │ ├── moves.go │ │ ├── moves_test.go │ │ ├── resource_accounts.go │ │ ├── resource_aggregated_balances.go │ │ ├── resource_logs.go │ │ ├── resource_transactions.go │ │ ├── resource_volumes.go │ │ ├── store.go │ │ ├── transactions.go │ │ ├── transactions_test.go │ │ ├── utils.go │ │ ├── volumes.go │ │ └── volumes_test.go │ ├── module.go │ └── system │ │ ├── factory.go │ │ ├── main_test.go │ │ ├── migrations.go │ │ ├── migrations_test.go │ │ ├── resource_ledgers.go │ │ ├── store.go │ │ └── store_test.go ├── tracing │ └── tracing.go ├── transaction.go ├── transaction_test.go ├── volumes.go └── worker │ ├── async_block.go │ └── fx.go ├── main.go ├── openapi.yaml ├── openapi ├── overlay.yaml ├── v1.yaml └── v2.yaml ├── pkg ├── accounts │ ├── account_test.go │ └── accounts.go ├── assets │ └── asset.go ├── client │ ├── .devcontainer │ │ ├── README.md │ │ ├── devcontainer.json │ │ └── setup.sh │ ├── .gitattributes │ ├── .gitignore │ ├── .speakeasy │ │ ├── gen.lock │ │ ├── gen.yaml │ │ ├── workflow.lock │ │ └── workflow.yaml │ ├── CONTRIBUTING.md │ ├── README.md │ ├── USAGE.md │ ├── docs │ │ ├── models │ │ │ ├── components │ │ │ │ ├── account.md │ │ │ │ ├── accountresponse.md │ │ │ │ ├── accountscursorresponse.md │ │ │ │ ├── accountwithvolumesandbalances.md │ │ │ │ ├── aggregatebalancesresponse.md │ │ │ │ ├── balancescursorresponse.md │ │ │ │ ├── balancescursorresponsecursor.md │ │ │ │ ├── config.md │ │ │ │ ├── configinfo.md │ │ │ │ ├── configinforesponse.md │ │ │ │ ├── contract.md │ │ │ │ ├── cursor.md │ │ │ │ ├── data.md │ │ │ │ ├── errorresponse.md │ │ │ │ ├── errorsenum.md │ │ │ │ ├── expr.md │ │ │ │ ├── httpmetadata.md │ │ │ │ ├── ledgerinfo.md │ │ │ │ ├── ledgerinforesponse.md │ │ │ │ ├── ledgerstorage.md │ │ │ │ ├── log.md │ │ │ │ ├── logscursorresponse.md │ │ │ │ ├── logscursorresponsecursor.md │ │ │ │ ├── mapping.md │ │ │ │ ├── mappingresponse.md │ │ │ │ ├── migrationinfo.md │ │ │ │ ├── posting.md │ │ │ │ ├── posttransaction.md │ │ │ │ ├── posttransactionscript.md │ │ │ │ ├── runtime.md │ │ │ │ ├── script.md │ │ │ │ ├── scriptresponse.md │ │ │ │ ├── security.md │ │ │ │ ├── state.md │ │ │ │ ├── stats.md │ │ │ │ ├── statsresponse.md │ │ │ │ ├── storage.md │ │ │ │ ├── transaction.md │ │ │ │ ├── transactiondata.md │ │ │ │ ├── transactionresponse.md │ │ │ │ ├── transactions.md │ │ │ │ ├── transactionscursorresponse.md │ │ │ │ ├── transactionscursorresponsecursor.md │ │ │ │ ├── transactionsresponse.md │ │ │ │ ├── type.md │ │ │ │ ├── v2account.md │ │ │ │ ├── v2accountresponse.md │ │ │ │ ├── v2accountscursorresponse.md │ │ │ │ ├── v2accountscursorresponsecursor.md │ │ │ │ ├── v2aggregatebalancesresponse.md │ │ │ │ ├── v2bulkelement.md │ │ │ │ ├── v2bulkelementaddmetadata.md │ │ │ │ ├── v2bulkelementcreatetransaction.md │ │ │ │ ├── v2bulkelementdeletemetadata.md │ │ │ │ ├── v2bulkelementdeletemetadatadata.md │ │ │ │ ├── v2bulkelementresult.md │ │ │ │ ├── v2bulkelementresultaddmetadata.md │ │ │ │ ├── v2bulkelementresultcreatetransaction.md │ │ │ │ ├── v2bulkelementresultdeletemetadata.md │ │ │ │ ├── v2bulkelementresulterror.md │ │ │ │ ├── v2bulkelementresultreverttransaction.md │ │ │ │ ├── v2bulkelementreverttransaction.md │ │ │ │ ├── v2bulkelementreverttransactiondata.md │ │ │ │ ├── v2bulkresponse.md │ │ │ │ ├── v2configinforesponse.md │ │ │ │ ├── v2createledgerrequest.md │ │ │ │ ├── v2createtransactionresponse.md │ │ │ │ ├── v2errorresponse.md │ │ │ │ ├── v2errorsenum.md │ │ │ │ ├── v2getledgerresponse.md │ │ │ │ ├── v2gettransactionresponse.md │ │ │ │ ├── v2ledger.md │ │ │ │ ├── v2ledgerinfo.md │ │ │ │ ├── v2ledgerinforesponse.md │ │ │ │ ├── v2ledgerinfostorage.md │ │ │ │ ├── v2ledgerlistresponse.md │ │ │ │ ├── v2ledgerlistresponsecursor.md │ │ │ │ ├── v2log.md │ │ │ │ ├── v2logscursorresponse.md │ │ │ │ ├── v2logscursorresponsecursor.md │ │ │ │ ├── v2logtype.md │ │ │ │ ├── v2migrationinfo.md │ │ │ │ ├── v2migrationinfostate.md │ │ │ │ ├── v2posting.md │ │ │ │ ├── v2posttransaction.md │ │ │ │ ├── v2posttransactionscript.md │ │ │ │ ├── v2reverttransactionresponse.md │ │ │ │ ├── v2stats.md │ │ │ │ ├── v2statsresponse.md │ │ │ │ ├── v2targetid.md │ │ │ │ ├── v2targettype.md │ │ │ │ ├── v2transaction.md │ │ │ │ ├── v2transactionscursorresponse.md │ │ │ │ ├── v2transactionscursorresponsecursor.md │ │ │ │ ├── v2volume.md │ │ │ │ ├── v2volumeswithbalance.md │ │ │ │ ├── v2volumeswithbalancecursorresponse.md │ │ │ │ ├── v2volumeswithbalancecursorresponsecursor.md │ │ │ │ └── volume.md │ │ │ ├── operations │ │ │ │ ├── addmetadataontransactionrequest.md │ │ │ │ ├── addmetadataontransactionresponse.md │ │ │ │ ├── addmetadatatoaccountrequest.md │ │ │ │ ├── addmetadatatoaccountresponse.md │ │ │ │ ├── countaccountsrequest.md │ │ │ │ ├── countaccountsresponse.md │ │ │ │ ├── counttransactionsrequest.md │ │ │ │ ├── counttransactionsresponse.md │ │ │ │ ├── createtransactionrequest.md │ │ │ │ ├── createtransactionresponse.md │ │ │ │ ├── createtransactionsrequest.md │ │ │ │ ├── createtransactionsresponse.md │ │ │ │ ├── getaccountrequest.md │ │ │ │ ├── getaccountresponse.md │ │ │ │ ├── getbalancesaggregatedrequest.md │ │ │ │ ├── getbalancesaggregatedresponse.md │ │ │ │ ├── getbalancesrequest.md │ │ │ │ ├── getbalancesresponse.md │ │ │ │ ├── getinforesponse.md │ │ │ │ ├── getledgerinforequest.md │ │ │ │ ├── getledgerinforesponse.md │ │ │ │ ├── getmappingrequest.md │ │ │ │ ├── getmappingresponse.md │ │ │ │ ├── getmetricsresponse.md │ │ │ │ ├── gettransactionrequest.md │ │ │ │ ├── gettransactionresponse.md │ │ │ │ ├── listaccountsrequest.md │ │ │ │ ├── listaccountsresponse.md │ │ │ │ ├── listlogsrequest.md │ │ │ │ ├── listlogsresponse.md │ │ │ │ ├── listtransactionsrequest.md │ │ │ │ ├── listtransactionsresponse.md │ │ │ │ ├── metadata.md │ │ │ │ ├── option.md │ │ │ │ ├── order.md │ │ │ │ ├── readstatsrequest.md │ │ │ │ ├── readstatsresponse.md │ │ │ │ ├── reverttransactionrequest.md │ │ │ │ ├── reverttransactionresponse.md │ │ │ │ ├── runscriptrequest.md │ │ │ │ ├── runscriptresponse.md │ │ │ │ ├── updatemappingrequest.md │ │ │ │ ├── updatemappingresponse.md │ │ │ │ ├── v2addmetadataontransactionrequest.md │ │ │ │ ├── v2addmetadataontransactionresponse.md │ │ │ │ ├── v2addmetadatatoaccountrequest.md │ │ │ │ ├── v2addmetadatatoaccountresponse.md │ │ │ │ ├── v2countaccountsrequest.md │ │ │ │ ├── v2countaccountsresponse.md │ │ │ │ ├── v2counttransactionsrequest.md │ │ │ │ ├── v2counttransactionsresponse.md │ │ │ │ ├── v2createbulkrequest.md │ │ │ │ ├── v2createbulkresponse.md │ │ │ │ ├── v2createledgerrequest.md │ │ │ │ ├── v2createledgerresponse.md │ │ │ │ ├── v2createtransactionrequest.md │ │ │ │ ├── v2createtransactionresponse.md │ │ │ │ ├── v2deleteaccountmetadatarequest.md │ │ │ │ ├── v2deleteaccountmetadataresponse.md │ │ │ │ ├── v2deleteledgermetadatarequest.md │ │ │ │ ├── v2deleteledgermetadataresponse.md │ │ │ │ ├── v2deletetransactionmetadatarequest.md │ │ │ │ ├── v2deletetransactionmetadataresponse.md │ │ │ │ ├── v2exportlogsrequest.md │ │ │ │ ├── v2exportlogsresponse.md │ │ │ │ ├── v2getaccountrequest.md │ │ │ │ ├── v2getaccountresponse.md │ │ │ │ ├── v2getbalancesaggregatedrequest.md │ │ │ │ ├── v2getbalancesaggregatedresponse.md │ │ │ │ ├── v2getinforesponse.md │ │ │ │ ├── v2getledgerinforequest.md │ │ │ │ ├── v2getledgerinforesponse.md │ │ │ │ ├── v2getledgerrequest.md │ │ │ │ ├── v2getledgerresponse.md │ │ │ │ ├── v2gettransactionrequest.md │ │ │ │ ├── v2gettransactionresponse.md │ │ │ │ ├── v2getvolumeswithbalancesrequest.md │ │ │ │ ├── v2getvolumeswithbalancesresponse.md │ │ │ │ ├── v2importlogsrequest.md │ │ │ │ ├── v2importlogsresponse.md │ │ │ │ ├── v2listaccountsrequest.md │ │ │ │ ├── v2listaccountsresponse.md │ │ │ │ ├── v2listledgersrequest.md │ │ │ │ ├── v2listledgersresponse.md │ │ │ │ ├── v2listlogsrequest.md │ │ │ │ ├── v2listlogsresponse.md │ │ │ │ ├── v2listtransactionsrequest.md │ │ │ │ ├── v2listtransactionsresponse.md │ │ │ │ ├── v2readstatsrequest.md │ │ │ │ ├── v2readstatsresponse.md │ │ │ │ ├── v2reverttransactionrequest.md │ │ │ │ ├── v2reverttransactionresponse.md │ │ │ │ ├── v2updateledgermetadatarequest.md │ │ │ │ └── v2updateledgermetadataresponse.md │ │ │ └── sdkerrors │ │ │ │ ├── errorresponse.md │ │ │ │ └── v2errorresponse.md │ │ └── sdks │ │ │ ├── formance │ │ │ └── README.md │ │ │ ├── ledger │ │ │ └── README.md │ │ │ ├── v1 │ │ │ └── README.md │ │ │ └── v2 │ │ │ └── README.md │ ├── formance.go │ ├── go.mod │ ├── go.sum │ ├── internal │ │ ├── hooks │ │ │ ├── clientcredentials.go │ │ │ ├── hooks.go │ │ │ └── registration.go │ │ └── utils │ │ │ ├── contenttype.go │ │ │ ├── env.go │ │ │ ├── form.go │ │ │ ├── headers.go │ │ │ ├── json.go │ │ │ ├── pathparams.go │ │ │ ├── queryparams.go │ │ │ ├── requestbody.go │ │ │ ├── retries.go │ │ │ ├── security.go │ │ │ └── utils.go │ ├── ledger.go │ ├── models │ │ ├── components │ │ │ ├── account.go │ │ │ ├── accountresponse.go │ │ │ ├── accountscursorresponse.go │ │ │ ├── accountwithvolumesandbalances.go │ │ │ ├── aggregatebalancesresponse.go │ │ │ ├── balancescursorresponse.go │ │ │ ├── config.go │ │ │ ├── configinfo.go │ │ │ ├── configinforesponse.go │ │ │ ├── contract.go │ │ │ ├── errorresponse.go │ │ │ ├── errorsenum.go │ │ │ ├── httpmetadata.go │ │ │ ├── ledgerinfo.go │ │ │ ├── ledgerinforesponse.go │ │ │ ├── ledgerstorage.go │ │ │ ├── log.go │ │ │ ├── logscursorresponse.go │ │ │ ├── mapping.go │ │ │ ├── mappingresponse.go │ │ │ ├── migrationinfo.go │ │ │ ├── posting.go │ │ │ ├── posttransaction.go │ │ │ ├── script.go │ │ │ ├── scriptresponse.go │ │ │ ├── security.go │ │ │ ├── stats.go │ │ │ ├── statsresponse.go │ │ │ ├── transaction.go │ │ │ ├── transactiondata.go │ │ │ ├── transactionresponse.go │ │ │ ├── transactions.go │ │ │ ├── transactionscursorresponse.go │ │ │ ├── transactionsresponse.go │ │ │ ├── v2account.go │ │ │ ├── v2accountresponse.go │ │ │ ├── v2accountscursorresponse.go │ │ │ ├── v2aggregatebalancesresponse.go │ │ │ ├── v2bulkelement.go │ │ │ ├── v2bulkelementaddmetadata.go │ │ │ ├── v2bulkelementcreatetransaction.go │ │ │ ├── v2bulkelementdeletemetadata.go │ │ │ ├── v2bulkelementresult.go │ │ │ ├── v2bulkelementreverttransaction.go │ │ │ ├── v2bulkresponse.go │ │ │ ├── v2configinforesponse.go │ │ │ ├── v2createledgerrequest.go │ │ │ ├── v2createtransactionresponse.go │ │ │ ├── v2errorresponse.go │ │ │ ├── v2errorsenum.go │ │ │ ├── v2getledgerresponse.go │ │ │ ├── v2gettransactionresponse.go │ │ │ ├── v2ledger.go │ │ │ ├── v2ledgerinfo.go │ │ │ ├── v2ledgerinforesponse.go │ │ │ ├── v2ledgerlistresponse.go │ │ │ ├── v2log.go │ │ │ ├── v2logscursorresponse.go │ │ │ ├── v2migrationinfo.go │ │ │ ├── v2posting.go │ │ │ ├── v2posttransaction.go │ │ │ ├── v2reverttransactionresponse.go │ │ │ ├── v2stats.go │ │ │ ├── v2statsresponse.go │ │ │ ├── v2targetid.go │ │ │ ├── v2targettype.go │ │ │ ├── v2transaction.go │ │ │ ├── v2transactionscursorresponse.go │ │ │ ├── v2volume.go │ │ │ ├── v2volumeswithbalance.go │ │ │ ├── v2volumeswithbalancecursorresponse.go │ │ │ └── volume.go │ │ ├── operations │ │ │ ├── addmetadataontransaction.go │ │ │ ├── addmetadatatoaccount.go │ │ │ ├── countaccounts.go │ │ │ ├── counttransactions.go │ │ │ ├── createtransaction.go │ │ │ ├── createtransactions.go │ │ │ ├── getaccount.go │ │ │ ├── getbalances.go │ │ │ ├── getbalancesaggregated.go │ │ │ ├── getinfo.go │ │ │ ├── getledgerinfo.go │ │ │ ├── getmapping.go │ │ │ ├── getmetrics.go │ │ │ ├── gettransaction.go │ │ │ ├── listaccounts.go │ │ │ ├── listlogs.go │ │ │ ├── listtransactions.go │ │ │ ├── options.go │ │ │ ├── readstats.go │ │ │ ├── reverttransaction.go │ │ │ ├── runscript.go │ │ │ ├── updatemapping.go │ │ │ ├── v2addmetadataontransaction.go │ │ │ ├── v2addmetadatatoaccount.go │ │ │ ├── v2countaccounts.go │ │ │ ├── v2counttransactions.go │ │ │ ├── v2createbulk.go │ │ │ ├── v2createledger.go │ │ │ ├── v2createtransaction.go │ │ │ ├── v2deleteaccountmetadata.go │ │ │ ├── v2deleteledgermetadata.go │ │ │ ├── v2deletetransactionmetadata.go │ │ │ ├── v2exportlogs.go │ │ │ ├── v2getaccount.go │ │ │ ├── v2getbalancesaggregated.go │ │ │ ├── v2getinfo.go │ │ │ ├── v2getledger.go │ │ │ ├── v2getledgerinfo.go │ │ │ ├── v2gettransaction.go │ │ │ ├── v2getvolumeswithbalances.go │ │ │ ├── v2importlogs.go │ │ │ ├── v2listaccounts.go │ │ │ ├── v2listledgers.go │ │ │ ├── v2listlogs.go │ │ │ ├── v2listtransactions.go │ │ │ ├── v2readstats.go │ │ │ ├── v2reverttransaction.go │ │ │ └── v2updateledgermetadata.go │ │ └── sdkerrors │ │ │ ├── errorresponse.go │ │ │ ├── sdkerror.go │ │ │ └── v2errorresponse.go │ ├── retry │ │ └── config.go │ ├── types │ │ ├── bigint.go │ │ ├── date.go │ │ ├── datetime.go │ │ ├── decimal.go │ │ └── pointers.go │ ├── v1.go │ └── v2.go ├── events │ └── events.go ├── features │ └── features.go ├── generate │ ├── generator.go │ ├── generator_test.go │ └── set.go └── testserver │ ├── client.go │ ├── ginkgo │ ├── helpers.go │ └── matchers.go │ ├── server.go │ ├── utils.go │ └── worker.go ├── scratch.Dockerfile ├── test ├── e2e │ ├── api_accounts_list_test.go │ ├── api_accounts_metadata_test.go │ ├── api_balances_aggregated_test.go │ ├── api_bulk_test.go │ ├── api_idempotency_test.go │ ├── api_ledgers_create_test.go │ ├── api_ledgers_import_test.go │ ├── api_ledgers_list_test.go │ ├── api_ledgers_metadata_test.go │ ├── api_logs_list_test.go │ ├── api_transactions_create_test.go │ ├── api_transactions_list_test.go │ ├── api_transactions_metadata_test.go │ ├── api_transactions_revert_test.go │ ├── api_volumes_test.go │ ├── app_lifecycle_test.go │ ├── app_logs_blocks_async_test.go │ ├── app_multiple_instance_test.go │ ├── suite_test.go │ └── v1_api_balances_test.go ├── migrations │ ├── README.md │ └── upgrade_test.go ├── performance │ ├── .gitignore │ ├── README.md │ ├── justfile │ └── pkg │ │ ├── env │ │ ├── configure.go │ │ ├── env.go │ │ ├── env_remote_ledger.go │ │ └── features.go │ │ ├── read │ │ ├── examples │ │ │ └── config.yml │ │ ├── justfile │ │ └── read_test.go │ │ └── write │ │ ├── charts │ │ ├── .gitignore │ │ ├── index.ts │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── src │ │ │ ├── colors.ts │ │ │ ├── graphs.ts │ │ │ └── report.ts │ │ └── tsconfig.json │ │ ├── example_scripts │ │ └── example1.js │ │ ├── justfile │ │ ├── local_env_test.go │ │ ├── report_test.go │ │ ├── scripts │ │ ├── any_bounded_to_any.js │ │ ├── any_to_bank.js │ │ ├── any_unbounded_to_any.js │ │ ├── world_to_any.js │ │ └── world_to_bank.js │ │ └── write_test.go └── stress │ ├── stress_test.go │ └── suite_test.go └── tools ├── generator ├── Earthfile ├── cmd │ └── root.go ├── examples │ └── example1.js ├── examples_test.go ├── go.mod ├── go.sum └── main.go └── provisioner ├── Dockerfile ├── cmd └── root.go ├── go.mod ├── go.sum ├── justfile ├── main.go └── pkg ├── config.go ├── reconciler.go ├── state.go └── store.go /.dockerignore: -------------------------------------------------------------------------------- 1 | vendor 2 | sdk 3 | .git 4 | .devbox 5 | .direnv 6 | .github 7 | .moon 8 | sdks 9 | config 10 | docs 11 | nix 12 | openapi 13 | tests 14 | worktrees 15 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake --impure 2 | dotenv -------------------------------------------------------------------------------- /.github/actions/default/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Env 2 | description: Setup Env for Linux x64 3 | inputs: 4 | token: 5 | description: 'A Github PAT' 6 | required: true 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Install Nix 11 | uses: cachix/install-nix-action@v31 12 | - name: Cache dependencies 13 | uses: nix-community/cache-nix-action@v6 14 | with: 15 | primary-key: nix-${{ runner.os }}-${{ hashFiles('**/flake.nix', '**/flake.lock') }} 16 | restore-prefixes-first-match: nix-${{ runner.os }}- 17 | - name: Load dependencies 18 | shell: bash 19 | run: nix develop --install 20 | - uses: actions/cache@v4 21 | with: 22 | path: | 23 | ~/.cache/go-build 24 | /tmp/go/pkg/mod/ 25 | key: ${{ runner.os }}-${{ github.job }}-go-${{ hashFiles('**/go.sum') }} 26 | restore-keys: | 27 | ${{ runner.os }}-${{ github.job }}-go- -------------------------------------------------------------------------------- /.github/actions/env/action.yml: -------------------------------------------------------------------------------- 1 | name: Setup Env 2 | description: Setup Env for Linux x64 3 | inputs: 4 | token: 5 | description: 'A Github PAT' 6 | required: true 7 | runs: 8 | using: composite 9 | steps: 10 | - name: Set up QEMU 11 | uses: docker/setup-qemu-action@v3 12 | - name: Set up Docker Buildx 13 | uses: docker/setup-buildx-action@v3 14 | - name: "Put back the git branch into git (Earthly uses it for tagging)" 15 | shell: bash 16 | run: | 17 | branch="" 18 | if [ -n "$GITHUB_HEAD_REF" ]; then 19 | branch="$GITHUB_HEAD_REF" 20 | else 21 | branch="${GITHUB_REF##*/}" 22 | fi 23 | git checkout -b "$branch" || true 24 | 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directories: 5 | - / 6 | - /tools/generator 7 | - /tools/provisioner 8 | schedule: 9 | interval: daily 10 | open-pull-requests-limit: 40 11 | labels: [ "dependencies" ] 12 | # Groups are updated together in one pull request 13 | groups: 14 | all: 15 | patterns: 16 | - "*" 17 | allow: 18 | - dependency-type: all 19 | 20 | - package-ecosystem: "github-actions" 21 | directory: "/" 22 | schedule: 23 | interval: "weekly" 24 | labels: [ "dependencies" ] 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cover.out 2 | go.work* 3 | *.jar 4 | node_modules 5 | dist 6 | vendor 7 | worktrees 8 | dumps 9 | .env 10 | !.envrc 11 | Pulumi.*.yaml 12 | coverage.txt -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | settings: 4 | staticcheck: 5 | dot-import-whitelist: 6 | - github.com/formancehq/go-libs/v3/testing/deferred/ginkgo 7 | - github.com/formancehq/go-libs/v3/collectionutils 8 | - github.com/formancehq/go-libs/v3/testing/testservice/ginkgo 9 | - github.com/onsi/gomega -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @formancehq/backend 2 | -------------------------------------------------------------------------------- /build.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/formancehq/base:22.04 2 | COPY ledger /usr/bin/ledger 3 | ENV OTEL_SERVICE_NAME ledger 4 | ENTRYPOINT ["/usr/bin/ledger"] 5 | CMD ["serve"] -------------------------------------------------------------------------------- /cmd/buckets.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | func NewBucketsCommand() *cobra.Command { 8 | ret := &cobra.Command{ 9 | Use: "buckets", 10 | Aliases: []string{"storage"}, 11 | } 12 | 13 | ret.AddCommand(NewBucketUpgrade()) 14 | return ret 15 | } 16 | -------------------------------------------------------------------------------- /cmd/config.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | "github.com/spf13/cobra" 6 | "github.com/spf13/viper" 7 | ) 8 | 9 | func LoadConfig[V any](cmd *cobra.Command) (*V, error){ 10 | v := viper.New() 11 | if err := v.BindPFlags(cmd.Flags()); err != nil { 12 | return nil, fmt.Errorf("binding flags: %w", err) 13 | } 14 | 15 | var cfg V 16 | if err := v.Unmarshal(&cfg); err != nil { 17 | return nil, fmt.Errorf("unmarshalling config: %w", err) 18 | } 19 | 20 | return &cfg, nil 21 | } 22 | -------------------------------------------------------------------------------- /cmd/docs.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import "github.com/spf13/cobra" 4 | 5 | func NewDocsCommand() *cobra.Command { 6 | ret := &cobra.Command{ 7 | Use: "docs", 8 | } 9 | ret.AddCommand(NewDocFlagsCommand()) 10 | ret.AddCommand(NewDocEventsCommand()) 11 | 12 | return ret 13 | } 14 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | func PrintVersion(_ *cobra.Command, _ []string) { 10 | fmt.Printf("Version: %s \n", Version) 11 | fmt.Printf("Date: %s \n", BuildDate) 12 | fmt.Printf("Commit: %s \n", Commit) 13 | } 14 | 15 | func NewVersionCommand() *cobra.Command { 16 | return &cobra.Command{ 17 | Use: "version", 18 | Short: "Get version", 19 | Run: PrintVersion, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /deployments/docker-compose/prometheus.yaml: -------------------------------------------------------------------------------- 1 | scrape_configs: 2 | - job_name: 'otel' 3 | scrape_interval: 1s 4 | static_configs: 5 | - targets: ['otel:8889'] 6 | -------------------------------------------------------------------------------- /deployments/pulumi/.gitignore: -------------------------------------------------------------------------------- 1 | Pulumi.*.yaml 2 | -------------------------------------------------------------------------------- /deployments/pulumi/.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | settings: 4 | staticcheck: 5 | dot-import-whitelist: 6 | - github.com/formancehq/ledger/deployments/pulumi/pkg/common 7 | - github.com/formancehq/ledger/deployments/pulumi/pkg/utils 8 | - github.com/formancehq/go-libs/v3/collectionutils -------------------------------------------------------------------------------- /deployments/pulumi/Pulumi.yaml: -------------------------------------------------------------------------------- 1 | name: ledger 2 | description: Ledger deployment 3 | runtime: go 4 | config: 5 | pulumi:tags: 6 | value: 7 | pulumi:template: kubernetes-go 8 | -------------------------------------------------------------------------------- /deployments/pulumi/README.md: -------------------------------------------------------------------------------- 1 | # Pulumi 2 | 3 | > [!WARNING] 4 | > This Pulumi app is used for testing only. It is not intended for production use. 5 | > It can be broken or removed at any time. 6 | 7 | See [schema](./docs/schema.md) for the full schema. -------------------------------------------------------------------------------- /deployments/pulumi/justfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env just --justfile 2 | 3 | update-doc: 4 | go run tools/main.go schema > docs/schema.json 5 | cat docs/schema.json | docker run --rm -i elisiariocouto/jsonschema-markdown --no-empty-columns - > docs/schema.md -------------------------------------------------------------------------------- /deployments/pulumi/pkg/utils/convert.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/pulumi/pulumi/sdk/v3/go/pulumi" 5 | "github.com/pulumi/pulumi/sdk/v3/go/pulumix" 6 | ) 7 | 8 | func GetMainImage(tag pulumix.Input[string]) pulumi.StringOutput { 9 | return GetImage(pulumi.String("ledger"), tag) 10 | } 11 | 12 | func GetImage(component, tag pulumix.Input[string]) pulumi.StringOutput { 13 | return pulumi.Sprintf("ghcr.io/formancehq/%s:%s", component, pulumix.Apply(tag, func(version string) string { 14 | if version == "" { 15 | return "latest" 16 | } 17 | return version 18 | })) 19 | } 20 | 21 | func BoolToString(output pulumix.Input[bool]) pulumix.Output[string] { 22 | return pulumix.Apply(output, func(v bool) string { 23 | if v { 24 | return "true" 25 | } 26 | return "false" 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /deployments/pulumi/tools/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/formancehq/ledger/deployments/pulumi/pkg/config" 7 | "github.com/invopop/jsonschema" 8 | "github.com/spf13/cobra" 9 | "os" 10 | ) 11 | 12 | func main() { 13 | cmd := &cobra.Command{ 14 | Use: "tools", 15 | } 16 | schema := &cobra.Command{ 17 | Use: "schema", 18 | RunE: printSchema, 19 | } 20 | cmd.AddCommand(schema) 21 | 22 | if err := cmd.Execute(); err != nil { 23 | _, _ = fmt.Fprintln(os.Stderr, err) 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | func printSchema(_ *cobra.Command, _ []string) error { 29 | reflector := jsonschema.Reflector{ 30 | //DoNotReference: true, 31 | RequiredFromJSONSchemaTags: true, 32 | } 33 | if err := reflector.AddGoComments("github.com/formancehq/ledger/deployments/pulumi", "./pkg"); err != nil { 34 | return err 35 | } 36 | schema := reflector.Reflect(config.Config{}) 37 | 38 | enc := json.NewEncoder(os.Stdout) 39 | enc.SetIndent("", " ") 40 | 41 | return enc.Encode(schema) 42 | } 43 | -------------------------------------------------------------------------------- /docs/database/_default/diagrams/orphans/orphans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/orphans/orphans.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/summary/relationships.real.compact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/summary/relationships.real.compact.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/summary/relationships.real.large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/summary/relationships.real.large.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/accounts.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/accounts.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/accounts.2degrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/accounts.2degrees.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/accounts_metadata.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/accounts_metadata.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/accounts_metadata.2degrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/accounts_metadata.2degrees.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/accounts_volumes.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/accounts_volumes.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/goose_db_version.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/goose_db_version.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/logs.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/logs.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/moves.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/moves.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/moves.2degrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/moves.2degrees.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/transactions.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/transactions.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/transactions.2degrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/transactions.2degrees.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/transactions_metadata.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/transactions_metadata.1degree.png -------------------------------------------------------------------------------- /docs/database/_default/diagrams/tables/transactions_metadata.2degrees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_default/diagrams/tables/transactions_metadata.2degrees.png -------------------------------------------------------------------------------- /docs/database/_system/diagrams/orphans/orphans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_system/diagrams/orphans/orphans.png -------------------------------------------------------------------------------- /docs/database/_system/diagrams/tables/goose_db_version.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_system/diagrams/tables/goose_db_version.1degree.png -------------------------------------------------------------------------------- /docs/database/_system/diagrams/tables/ledgers.1degree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/docs/database/_system/diagrams/tables/ledgers.1degree.png -------------------------------------------------------------------------------- /docs/events/DeletedMetadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/formancehq/ledger/internal/bus/deleted-metadata", 4 | "$ref": "#/$defs/DeletedMetadata", 5 | "$defs": { 6 | "DeletedMetadata": { 7 | "properties": { 8 | "ledger": { 9 | "type": "string" 10 | }, 11 | "targetType": { 12 | "type": "string" 13 | }, 14 | "targetId": true, 15 | "key": { 16 | "type": "string" 17 | } 18 | }, 19 | "additionalProperties": false, 20 | "type": "object", 21 | "required": [ 22 | "ledger", 23 | "targetType", 24 | "targetId", 25 | "key" 26 | ] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /docs/events/SavedMetadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/formancehq/ledger/internal/bus/saved-metadata", 4 | "$ref": "#/$defs/SavedMetadata", 5 | "$defs": { 6 | "Metadata": { 7 | "additionalProperties": { 8 | "type": "string" 9 | }, 10 | "type": "object" 11 | }, 12 | "SavedMetadata": { 13 | "properties": { 14 | "ledger": { 15 | "type": "string" 16 | }, 17 | "targetType": { 18 | "type": "string" 19 | }, 20 | "targetId": { 21 | "type": "string" 22 | }, 23 | "metadata": { 24 | "$ref": "#/$defs/Metadata" 25 | } 26 | }, 27 | "additionalProperties": false, 28 | "type": "object", 29 | "required": [ 30 | "ledger", 31 | "targetType", 32 | "targetId", 33 | "metadata" 34 | ] 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /examples/publisher-http/Caddyfile: -------------------------------------------------------------------------------- 1 | :8080 { 2 | log { 3 | output stdout 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /examples/publisher-http/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | volumes: 3 | postgres: 4 | services: 5 | postgres: 6 | extends: 7 | file: ../../docker-compose.yml 8 | service: postgres 9 | listener: 10 | image: caddy 11 | volumes: 12 | - ./Caddyfile:/etc/caddy/Caddyfile 13 | ledger: 14 | extends: 15 | file: ../../docker-compose.yml 16 | service: ledger 17 | depends_on: 18 | - postgres 19 | - listener 20 | image: golang:1.23-alpine 21 | entrypoint: go run main.go serve 22 | volumes: 23 | - ../..:/src 24 | working_dir: /src 25 | environment: 26 | CGO_ENABLED: 0 27 | DEBUG: "true" 28 | PUBLISHER_HTTP_ENABLED: "true" 29 | PUBLISHER_TOPIC_MAPPING: "*:http://listener:8080" 30 | -------------------------------------------------------------------------------- /internal/api/bulking/factory.go: -------------------------------------------------------------------------------- 1 | package bulking 2 | 3 | import "net/http" 4 | 5 | type Handler interface { 6 | GetChannels(w http.ResponseWriter, r *http.Request) (Bulk, chan BulkElementResult, bool) 7 | Terminate(w http.ResponseWriter, r *http.Request) 8 | } 9 | 10 | type HandlerFactory interface { 11 | CreateBulkHandler() Handler 12 | } -------------------------------------------------------------------------------- /internal/api/bulking/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/ledger/controller.go -destination mocks_ledger_controller_test.go -package bulking --mock_names Controller=LedgerController . Controller 2 | package bulking 3 | -------------------------------------------------------------------------------- /internal/api/bulking/result.go: -------------------------------------------------------------------------------- 1 | package bulking 2 | 3 | type APIResult struct { 4 | ErrorCode string `json:"errorCode,omitempty"` 5 | ErrorDescription string `json:"errorDescription,omitempty"` 6 | Data any `json:"data,omitempty"` 7 | ResponseType string `json:"responseType"` // Added for sdk generation (discriminator in oneOf) 8 | LogID uint64 `json:"logID"` 9 | } 10 | -------------------------------------------------------------------------------- /internal/api/common/context.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/formancehq/ledger/internal/controller/ledger" 7 | ) 8 | 9 | type ledgerKey struct{} 10 | 11 | var _ledgerKey = ledgerKey{} 12 | 13 | func ContextWithLedger(ctx context.Context, ledger ledger.Controller) context.Context { 14 | return context.WithValue(ctx, _ledgerKey, ledger) 15 | } 16 | 17 | func LedgerFromContext(ctx context.Context) ledger.Controller { 18 | return ctx.Value(_ledgerKey).(ledger.Controller) 19 | } 20 | -------------------------------------------------------------------------------- /internal/api/common/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/system/controller.go -destination mocks_system_controller_test.go -package common --mock_names Controller=SystemController . Controller 2 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/ledger/controller.go -destination mocks_ledger_controller_test.go -package common --mock_names Controller=LedgerController . Controller 3 | package common 4 | -------------------------------------------------------------------------------- /internal/api/common/pagination.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | type PaginationConfig struct { 4 | MaxPageSize uint64 5 | DefaultPageSize uint64 6 | } 7 | -------------------------------------------------------------------------------- /internal/api/v1/api_utils_test.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "testing" 5 | 6 | ledger "github.com/formancehq/ledger/internal" 7 | 8 | "go.uber.org/mock/gomock" 9 | ) 10 | 11 | func newTestingSystemController(t *testing.T, expectedSchemaCheck bool) (*SystemController, *LedgerController) { 12 | t.Helper() 13 | 14 | ctrl := gomock.NewController(t) 15 | mockLedger := NewLedgerController(ctrl) 16 | backend := NewSystemController(ctrl) 17 | backend. 18 | EXPECT(). 19 | GetLedger(gomock.Any(), gomock.Any()). 20 | MinTimes(0). 21 | Return(&ledger.Ledger{}, nil) 22 | t.Cleanup(func() { 23 | ctrl.Finish() 24 | }) 25 | backend. 26 | EXPECT(). 27 | GetLedgerController(gomock.Any(), gomock.Any()). 28 | MinTimes(0). 29 | Return(mockLedger, nil) 30 | t.Cleanup(func() { 31 | ctrl.Finish() 32 | }) 33 | if expectedSchemaCheck { 34 | mockLedger.EXPECT(). 35 | IsDatabaseUpToDate(gomock.Any()). 36 | Return(true, nil) 37 | } 38 | return backend, mockLedger 39 | } 40 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_accounts_delete_metadata.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | 7 | "github.com/formancehq/ledger/internal/controller/ledger" 8 | 9 | "github.com/formancehq/go-libs/v3/api" 10 | "github.com/formancehq/ledger/internal/api/common" 11 | "github.com/go-chi/chi/v5" 12 | ) 13 | 14 | func deleteAccountMetadata(w http.ResponseWriter, r *http.Request) { 15 | address, err := url.PathUnescape(chi.URLParam(r, "address")) 16 | if err != nil { 17 | api.BadRequestWithDetails(w, common.ErrValidation, err, err.Error()) 18 | return 19 | } 20 | 21 | if _, err := common.LedgerFromContext(r.Context()). 22 | DeleteAccountMetadata( 23 | r.Context(), 24 | getCommandParameters(r, ledger.DeleteAccountMetadata{ 25 | Address: address, 26 | Key: chi.URLParam(r, "key"), 27 | }), 28 | ); err != nil { 29 | common.HandleCommonWriteErrors(w, r, err) 30 | return 31 | } 32 | 33 | api.NoContent(w) 34 | } 35 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_accounts_list.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | 6 | "errors" 7 | "github.com/formancehq/go-libs/v3/api" 8 | "github.com/formancehq/ledger/internal/api/common" 9 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 10 | ) 11 | 12 | func listAccounts(w http.ResponseWriter, r *http.Request) { 13 | l := common.LedgerFromContext(r.Context()) 14 | 15 | rq, err := getOffsetPaginatedQuery[any](r) 16 | if err != nil { 17 | api.BadRequest(w, common.ErrValidation, err) 18 | return 19 | } 20 | 21 | rq.Options.Builder, err = buildAccountsFilterQuery(r) 22 | if err != nil { 23 | api.BadRequest(w, common.ErrValidation, err) 24 | return 25 | } 26 | 27 | cursor, err := l.ListAccounts(r.Context(), *rq) 28 | if err != nil { 29 | switch { 30 | case errors.Is(err, ledgercontroller.ErrMissingFeature{}): 31 | api.BadRequest(w, common.ErrValidation, err) 32 | default: 33 | common.HandleCommonErrors(w, r, err) 34 | } 35 | return 36 | } 37 | 38 | api.RenderCursor(w, *cursor) 39 | } 40 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_info.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/chi/v5" 7 | 8 | "github.com/formancehq/go-libs/v3/api" 9 | "github.com/formancehq/go-libs/v3/migrations" 10 | "github.com/formancehq/ledger/internal/api/common" 11 | ) 12 | 13 | type Info struct { 14 | Name string `json:"name"` 15 | Storage StorageInfo `json:"storage"` 16 | } 17 | 18 | type StorageInfo struct { 19 | Migrations []migrations.Info `json:"migrations"` 20 | } 21 | 22 | func getLedgerInfo(w http.ResponseWriter, r *http.Request) { 23 | ledger := common.LedgerFromContext(r.Context()) 24 | 25 | var err error 26 | res := Info{ 27 | Name: chi.URLParam(r, "ledger"), 28 | Storage: StorageInfo{}, 29 | } 30 | res.Storage.Migrations, err = ledger.GetMigrationsInfo(r.Context()) 31 | if err != nil { 32 | common.HandleCommonErrors(w, r, err) 33 | return 34 | } 35 | 36 | api.Ok(w, res) 37 | } 38 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_stats.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/formancehq/go-libs/v3/api" 7 | "github.com/formancehq/ledger/internal/api/common" 8 | ) 9 | 10 | func getStats(w http.ResponseWriter, r *http.Request) { 11 | l := common.LedgerFromContext(r.Context()) 12 | 13 | stats, err := l.GetStats(r.Context()) 14 | if err != nil { 15 | common.HandleCommonErrors(w, r, err) 16 | return 17 | } 18 | 19 | api.Ok(w, stats) 20 | } 21 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_transactions_count.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/formancehq/go-libs/v3/api" 8 | "github.com/formancehq/ledger/internal/api/common" 9 | ) 10 | 11 | func countTransactions(w http.ResponseWriter, r *http.Request) { 12 | 13 | rq, err := getResourceQuery[any](r) 14 | if err != nil { 15 | return 16 | } 17 | rq.Builder = buildGetTransactionsQuery(r) 18 | 19 | count, err := common.LedgerFromContext(r.Context()).CountTransactions(r.Context(), *rq) 20 | if err != nil { 21 | common.HandleCommonErrors(w, r, err) 22 | return 23 | } 24 | 25 | w.Header().Set("Count", fmt.Sprint(count)) 26 | api.NoContent(w) 27 | } 28 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_transactions_delete_metadata.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | "strconv" 6 | 7 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 8 | 9 | "errors" 10 | 11 | "github.com/formancehq/go-libs/v3/api" 12 | "github.com/formancehq/ledger/internal/api/common" 13 | "github.com/go-chi/chi/v5" 14 | ) 15 | 16 | func deleteTransactionMetadata(w http.ResponseWriter, r *http.Request) { 17 | l := common.LedgerFromContext(r.Context()) 18 | 19 | transactionID, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64) 20 | if err != nil { 21 | api.BadRequest(w, common.ErrValidation, errors.New("invalid transaction ID")) 22 | return 23 | } 24 | 25 | metadataKey := chi.URLParam(r, "key") 26 | 27 | if _, err := l.DeleteTransactionMetadata(r.Context(), getCommandParameters(r, ledgercontroller.DeleteTransactionMetadata{ 28 | TransactionID: transactionID, 29 | Key: metadataKey, 30 | })); err != nil { 31 | common.HandleCommonWriteErrors(w, r, err) 32 | return 33 | } 34 | 35 | api.NoContent(w) 36 | } 37 | -------------------------------------------------------------------------------- /internal/api/v1/controllers_transactions_list.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/formancehq/go-libs/v3/api" 7 | "github.com/formancehq/go-libs/v3/bun/bunpaginate" 8 | "github.com/formancehq/ledger/internal/api/common" 9 | ) 10 | 11 | func listTransactions(w http.ResponseWriter, r *http.Request) { 12 | l := common.LedgerFromContext(r.Context()) 13 | 14 | paginatedQuery, err := getColumnPaginatedQuery[any](r, "id", bunpaginate.OrderDesc) 15 | if err != nil { 16 | api.BadRequest(w, common.ErrValidation, err) 17 | return 18 | } 19 | paginatedQuery.Options.Builder = buildGetTransactionsQuery(r) 20 | paginatedQuery.Options.Expand = []string{"volumes"} 21 | 22 | cursor, err := l.ListTransactions(r.Context(), *paginatedQuery) 23 | if err != nil { 24 | common.HandleCommonErrors(w, r, err) 25 | return 26 | } 27 | 28 | api.RenderCursor(w, *bunpaginate.MapCursor(cursor, mapTransactionToV1)) 29 | } 30 | -------------------------------------------------------------------------------- /internal/api/v1/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/system/controller.go -destination mocks_system_controller_test.go -package v1 --mock_names Controller=SystemController . Controller 2 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/ledger/controller.go -destination mocks_ledger_controller_test.go -package v1 --mock_names Controller=LedgerController . Controller 3 | package v1 4 | -------------------------------------------------------------------------------- /internal/api/v1/query.go: -------------------------------------------------------------------------------- 1 | package v1 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | const ( 8 | MaxPageSize = 1000 9 | DefaultPageSize = 15 10 | 11 | QueryKeyCursor = "cursor" 12 | QueryKeyBalanceOperator = "balanceOperator" 13 | ) 14 | 15 | func getBalanceOperator(c *http.Request) string { 16 | balanceOperator := "eq" 17 | balanceOperatorStr := c.URL.Query().Get(QueryKeyBalanceOperator) 18 | if balanceOperatorStr != "" { 19 | return balanceOperatorStr 20 | } 21 | 22 | return balanceOperator 23 | } 24 | -------------------------------------------------------------------------------- /internal/api/v2/api_utils_test.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "testing" 5 | 6 | "go.uber.org/mock/gomock" 7 | ) 8 | 9 | func newTestingSystemController(t *testing.T, expectedSchemaCheck bool) (*SystemController, *LedgerController) { 10 | ctrl := gomock.NewController(t) 11 | mockLedger := NewLedgerController(ctrl) 12 | backend := NewSystemController(ctrl) 13 | backend. 14 | EXPECT(). 15 | GetLedgerController(gomock.Any(), gomock.Any()). 16 | MinTimes(0). 17 | Return(mockLedger, nil) 18 | t.Cleanup(func() { 19 | ctrl.Finish() 20 | }) 21 | if expectedSchemaCheck { 22 | mockLedger.EXPECT(). 23 | IsDatabaseUpToDate(gomock.Any()). 24 | Return(true, nil) 25 | } 26 | return backend, mockLedger 27 | } 28 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_accounts_count.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "fmt" 5 | storagecommon "github.com/formancehq/ledger/internal/storage/common" 6 | "net/http" 7 | 8 | "errors" 9 | "github.com/formancehq/go-libs/v3/api" 10 | "github.com/formancehq/ledger/internal/api/common" 11 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 12 | ) 13 | 14 | func countAccounts(w http.ResponseWriter, r *http.Request) { 15 | l := common.LedgerFromContext(r.Context()) 16 | 17 | rq, err := getResourceQuery[any](r) 18 | if err != nil { 19 | api.BadRequest(w, common.ErrValidation, err) 20 | return 21 | } 22 | 23 | count, err := l.CountAccounts(r.Context(), *rq) 24 | if err != nil { 25 | switch { 26 | case errors.Is(err, storagecommon.ErrInvalidQuery{}) || errors.Is(err, ledgercontroller.ErrMissingFeature{}): 27 | api.BadRequest(w, common.ErrValidation, err) 28 | default: 29 | common.HandleCommonErrors(w, r, err) 30 | } 31 | return 32 | } 33 | 34 | w.Header().Set("Count", fmt.Sprint(count)) 35 | api.NoContent(w) 36 | } 37 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_accounts_delete_metadata.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | 7 | "github.com/formancehq/ledger/internal/controller/ledger" 8 | 9 | "github.com/go-chi/chi/v5" 10 | 11 | "github.com/formancehq/go-libs/v3/api" 12 | "github.com/formancehq/ledger/internal/api/common" 13 | ) 14 | 15 | func deleteAccountMetadata(w http.ResponseWriter, r *http.Request) { 16 | address, err := url.PathUnescape(chi.URLParam(r, "address")) 17 | if err != nil { 18 | api.BadRequestWithDetails(w, common.ErrValidation, err, err.Error()) 19 | return 20 | } 21 | 22 | if _, err := common.LedgerFromContext(r.Context()). 23 | DeleteAccountMetadata( 24 | r.Context(), 25 | getCommandParameters(r, ledger.DeleteAccountMetadata{ 26 | Address: address, 27 | Key: chi.URLParam(r, "key"), 28 | }), 29 | ); err != nil { 30 | common.HandleCommonWriteErrors(w, r, err) 31 | return 32 | } 33 | 34 | api.NoContent(w) 35 | } 36 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_ledgers_delete_metadata.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/formancehq/ledger/internal/api/common" 7 | 8 | "github.com/formancehq/ledger/internal/controller/system" 9 | 10 | "github.com/formancehq/go-libs/v3/api" 11 | "github.com/go-chi/chi/v5" 12 | ) 13 | 14 | func deleteLedgerMetadata(b system.Controller) http.HandlerFunc { 15 | return func(w http.ResponseWriter, r *http.Request) { 16 | if err := b.DeleteLedgerMetadata(r.Context(), chi.URLParam(r, "ledger"), chi.URLParam(r, "key")); err != nil { 17 | common.HandleCommonWriteErrors(w, r, err) 18 | return 19 | } 20 | 21 | api.NoContent(w) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_ledgers_info.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/chi/v5" 7 | 8 | "github.com/formancehq/go-libs/v3/api" 9 | "github.com/formancehq/go-libs/v3/migrations" 10 | "github.com/formancehq/ledger/internal/api/common" 11 | ) 12 | 13 | type Info struct { 14 | Name string `json:"name"` 15 | Storage StorageInfo `json:"storage"` 16 | } 17 | 18 | type StorageInfo struct { 19 | Migrations []migrations.Info `json:"migrations"` 20 | } 21 | 22 | func getLedgerInfo(w http.ResponseWriter, r *http.Request) { 23 | ledger := common.LedgerFromContext(r.Context()) 24 | 25 | var err error 26 | res := Info{ 27 | Name: chi.URLParam(r, "ledger"), 28 | Storage: StorageInfo{}, 29 | } 30 | res.Storage.Migrations, err = ledger.GetMigrationsInfo(r.Context()) 31 | if err != nil { 32 | common.HandleCommonErrors(w, r, err) 33 | return 34 | } 35 | 36 | api.Ok(w, res) 37 | } 38 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_ledgers_read.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "github.com/formancehq/ledger/internal/api/common" 5 | "net/http" 6 | 7 | "github.com/formancehq/ledger/internal/controller/system" 8 | 9 | "github.com/formancehq/go-libs/v3/platform/postgres" 10 | 11 | "github.com/formancehq/go-libs/v3/api" 12 | "github.com/go-chi/chi/v5" 13 | ) 14 | 15 | func readLedger(b system.Controller) http.HandlerFunc { 16 | return func(w http.ResponseWriter, r *http.Request) { 17 | ledger, err := b.GetLedger(r.Context(), chi.URLParam(r, "ledger")) 18 | if err != nil { 19 | switch { 20 | case postgres.IsNotFoundError(err): 21 | api.NotFound(w, err) 22 | default: 23 | common.HandleCommonErrors(w, r, err) 24 | } 25 | return 26 | } 27 | api.Ok(w, ledger) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_ledgers_update_metadata.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/formancehq/ledger/internal/api/common" 8 | 9 | "errors" 10 | 11 | "github.com/formancehq/go-libs/v3/api" 12 | "github.com/formancehq/go-libs/v3/metadata" 13 | systemcontroller "github.com/formancehq/ledger/internal/controller/system" 14 | "github.com/go-chi/chi/v5" 15 | ) 16 | 17 | func updateLedgerMetadata(systemController systemcontroller.Controller) http.HandlerFunc { 18 | return func(w http.ResponseWriter, r *http.Request) { 19 | 20 | m := metadata.Metadata{} 21 | if err := json.NewDecoder(r.Body).Decode(&m); err != nil { 22 | api.BadRequest(w, common.ErrValidation, errors.New("invalid format")) 23 | return 24 | } 25 | 26 | if err := systemController.UpdateLedgerMetadata(r.Context(), chi.URLParam(r, "ledger"), m); err != nil { 27 | common.HandleCommonWriteErrors(w, r, err) 28 | return 29 | } 30 | 31 | api.NoContent(w) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_logs_export.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | 8 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 9 | 10 | ledger "github.com/formancehq/ledger/internal" 11 | "github.com/formancehq/ledger/internal/api/common" 12 | ) 13 | 14 | func exportLogs(w http.ResponseWriter, r *http.Request) { 15 | enc := json.NewEncoder(w) 16 | w.Header().Set("Content-Type", "application/octet-stream") 17 | if err := common.LedgerFromContext(r.Context()).Export(r.Context(), ledgercontroller.ExportWriterFn(func(ctx context.Context, log ledger.Log) error { 18 | return enc.Encode(log) 19 | })); err != nil { 20 | common.HandleCommonErrors(w, r, err) 21 | return 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_stats.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/formancehq/go-libs/v3/api" 7 | "github.com/formancehq/ledger/internal/api/common" 8 | ) 9 | 10 | func readStats(w http.ResponseWriter, r *http.Request) { 11 | l := common.LedgerFromContext(r.Context()) 12 | 13 | stats, err := l.GetStats(r.Context()) 14 | if err != nil { 15 | common.HandleCommonErrors(w, r, err) 16 | return 17 | } 18 | 19 | api.Ok(w, stats) 20 | } 21 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_transactions_count.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "fmt" 5 | storagecommon "github.com/formancehq/ledger/internal/storage/common" 6 | "net/http" 7 | 8 | "errors" 9 | "github.com/formancehq/go-libs/v3/api" 10 | "github.com/formancehq/ledger/internal/api/common" 11 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 12 | ) 13 | 14 | func countTransactions(w http.ResponseWriter, r *http.Request) { 15 | 16 | rq, err := getResourceQuery[any](r) 17 | if err != nil { 18 | api.BadRequest(w, common.ErrValidation, err) 19 | return 20 | } 21 | 22 | count, err := common.LedgerFromContext(r.Context()).CountTransactions(r.Context(), *rq) 23 | if err != nil { 24 | switch { 25 | case errors.Is(err, storagecommon.ErrInvalidQuery{}) || errors.Is(err, ledgercontroller.ErrMissingFeature{}): 26 | api.BadRequest(w, common.ErrValidation, err) 27 | default: 28 | common.HandleCommonErrors(w, r, err) 29 | } 30 | return 31 | } 32 | 33 | w.Header().Set("Count", fmt.Sprint(count)) 34 | api.NoContent(w) 35 | } 36 | -------------------------------------------------------------------------------- /internal/api/v2/controllers_transactions_delete_metadata.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | "strconv" 6 | 7 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 8 | 9 | "github.com/go-chi/chi/v5" 10 | 11 | "github.com/formancehq/ledger/internal/api/common" 12 | 13 | "github.com/formancehq/go-libs/v3/api" 14 | ) 15 | 16 | func deleteTransactionMetadata(w http.ResponseWriter, r *http.Request) { 17 | l := common.LedgerFromContext(r.Context()) 18 | 19 | txID, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 64) 20 | if err != nil { 21 | api.BadRequest(w, common.ErrValidation, err) 22 | return 23 | } 24 | 25 | metadataKey := chi.URLParam(r, "key") 26 | 27 | if _, err := l.DeleteTransactionMetadata(r.Context(), getCommandParameters(r, ledgercontroller.DeleteTransactionMetadata{ 28 | TransactionID: txID, 29 | Key: metadataKey, 30 | })); err != nil { 31 | common.HandleCommonWriteErrors(w, r, err) 32 | return 33 | } 34 | 35 | api.NoContent(w) 36 | } 37 | -------------------------------------------------------------------------------- /internal/api/v2/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/system/controller.go -destination mocks_system_controller_test.go -package v2 --mock_names Controller=SystemController . Controller 2 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../controller/ledger/controller.go -destination mocks_ledger_controller_test.go -package v2 --mock_names Controller=LedgerController . Controller 3 | package v2 4 | -------------------------------------------------------------------------------- /internal/api/v2/query.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/formancehq/ledger/internal/controller/ledger" 7 | 8 | "github.com/formancehq/go-libs/v3/api" 9 | ) 10 | 11 | func getCommandParameters[INPUT any](r *http.Request, input INPUT) ledger.Parameters[INPUT] { 12 | return ledger.Parameters[INPUT]{ 13 | DryRun: api.QueryParamBool(r, "dryRun"), 14 | IdempotencyKey: api.IdempotencyKeyFromRequest(r), 15 | Input: input, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /internal/bigint.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | var Zero = big.NewInt(0) 8 | -------------------------------------------------------------------------------- /internal/bus/module.go: -------------------------------------------------------------------------------- 1 | package bus 2 | 3 | import ( 4 | "github.com/formancehq/ledger/internal/controller/ledger" 5 | "go.uber.org/fx" 6 | ) 7 | 8 | func NewFxModule() fx.Option { 9 | return fx.Options( 10 | fx.Provide(fx.Annotate(NewLedgerListener, fx.As(new(ledger.Listener)))), 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /internal/controller/ledger/export.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "context" 5 | 6 | ledger "github.com/formancehq/ledger/internal" 7 | ) 8 | 9 | type ExportWriter interface { 10 | Write(ctx context.Context, log ledger.Log) error 11 | } 12 | 13 | type ExportWriterFn func(ctx context.Context, log ledger.Log) error 14 | 15 | func (fn ExportWriterFn) Write(ctx context.Context, log ledger.Log) error { 16 | return fn(ctx, log) 17 | } 18 | -------------------------------------------------------------------------------- /internal/controller/ledger/listener.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/formancehq/go-libs/v3/metadata" 7 | ledger "github.com/formancehq/ledger/internal" 8 | ) 9 | 10 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source listener.go -destination listener_generated_test.go -package ledger . Listener 11 | type Listener interface { 12 | CommittedTransactions(ctx context.Context, ledger string, res ledger.Transaction, accountMetadata ledger.AccountMetadata) 13 | SavedMetadata(ctx context.Context, ledger string, targetType, id string, metadata metadata.Metadata) 14 | RevertedTransaction(ctx context.Context, ledger string, reverted, revert ledger.Transaction) 15 | DeletedMetadata(ctx context.Context, ledger string, targetType string, targetID any, key string) 16 | } 17 | -------------------------------------------------------------------------------- /internal/controller/ledger/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../storage/common/resource.go -destination mocks_test.go -package ledger . Resource 2 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../../storage/common/resource.go -destination mocks_test.go -package ledger . PaginatedResource 3 | package ledger 4 | -------------------------------------------------------------------------------- /internal/controller/ledger/parameters.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | type Parameters[INPUT any] struct { 4 | DryRun bool 5 | IdempotencyKey string 6 | Input INPUT 7 | } 8 | -------------------------------------------------------------------------------- /internal/controller/ledger/stats.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/formancehq/ledger/internal/storage/common" 7 | ) 8 | 9 | type Stats struct { 10 | Transactions int `json:"transactions"` 11 | Accounts int `json:"accounts"` 12 | } 13 | 14 | func (ctrl *DefaultController) GetStats(ctx context.Context) (Stats, error) { 15 | var stats Stats 16 | 17 | transactions, err := ctrl.store.Transactions().Count(ctx, common.ResourceQuery[any]{}) 18 | if err != nil { 19 | return stats, fmt.Errorf("counting transactions: %w", err) 20 | } 21 | 22 | accounts, err := ctrl.store.Accounts().Count(ctx, common.ResourceQuery[any]{}) 23 | if err != nil { 24 | return stats, fmt.Errorf("counting accounts: %w", err) 25 | } 26 | 27 | return Stats{ 28 | Transactions: transactions, 29 | Accounts: accounts, 30 | }, nil 31 | } 32 | -------------------------------------------------------------------------------- /internal/controller/system/errors.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | var ( 9 | ErrLedgerAlreadyExists = errors.New("ledger already exists") 10 | ErrBucketOutdated = errors.New("bucket is outdated, you need to upgrade it before adding a new ledger") 11 | ErrExperimentalFeaturesDisabled = errors.New("experimental features are disabled") 12 | ) 13 | 14 | type ErrInvalidLedgerConfiguration struct { 15 | err error 16 | } 17 | 18 | func (e ErrInvalidLedgerConfiguration) Error() string { 19 | return fmt.Sprintf("invalid ledger configuration: %s", e.err) 20 | } 21 | 22 | func (e ErrInvalidLedgerConfiguration) Is(err error) bool { 23 | _, ok := err.(ErrInvalidLedgerConfiguration) 24 | return ok 25 | } 26 | 27 | func newErrInvalidLedgerConfiguration(err error) ErrInvalidLedgerConfiguration { 28 | return ErrInvalidLedgerConfiguration{ 29 | err: err, 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /internal/controller/system/store.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "context" 5 | "github.com/formancehq/ledger/internal/storage/common" 6 | 7 | ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" 8 | 9 | "github.com/formancehq/go-libs/v3/bun/bunpaginate" 10 | "github.com/formancehq/go-libs/v3/metadata" 11 | ledger "github.com/formancehq/ledger/internal" 12 | ) 13 | 14 | type Store interface { 15 | GetLedger(ctx context.Context, name string) (*ledger.Ledger, error) 16 | ListLedgers(ctx context.Context, query common.ColumnPaginatedQuery[any]) (*bunpaginate.Cursor[ledger.Ledger], error) 17 | UpdateLedgerMetadata(ctx context.Context, name string, m metadata.Metadata) error 18 | DeleteLedgerMetadata(ctx context.Context, param string, key string) error 19 | OpenLedger(context.Context, string) (ledgercontroller.Store, *ledger.Ledger, error) 20 | CreateLedger(context.Context, *ledger.Ledger) error 21 | } 22 | -------------------------------------------------------------------------------- /internal/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate gomarkdoc -o README.md --repository.default-branch main --repository.url https://github.com/formancehq/ledger 2 | package ledger 3 | -------------------------------------------------------------------------------- /internal/errors.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import "fmt" 4 | 5 | type ErrInvalidLedgerName struct { 6 | err error 7 | name string 8 | } 9 | 10 | func (e ErrInvalidLedgerName) Error() string { 11 | return fmt.Sprintf("invalid ledger name '%s': %s", e.name, e.err) 12 | } 13 | 14 | func (e ErrInvalidLedgerName) Is(err error) bool { 15 | _, ok := err.(ErrInvalidLedgerName) 16 | return ok 17 | } 18 | 19 | func newErrInvalidLedgerName(name string, err error) ErrInvalidLedgerName { 20 | return ErrInvalidLedgerName{err: err, name: name} 21 | } 22 | 23 | type ErrInvalidBucketName struct { 24 | err error 25 | bucket string 26 | } 27 | 28 | func (e ErrInvalidBucketName) Error() string { 29 | return fmt.Sprintf("invalid bucket name '%s': %s", e.bucket, e.err) 30 | } 31 | 32 | func (e ErrInvalidBucketName) Is(err error) bool { 33 | _, ok := err.(ErrInvalidBucketName) 34 | return ok 35 | } 36 | 37 | func newErrInvalidBucketName(bucket string, err error) ErrInvalidBucketName { 38 | return ErrInvalidBucketName{err: err, bucket: bucket} 39 | } 40 | -------------------------------------------------------------------------------- /internal/ledger_test.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "github.com/formancehq/ledger/pkg/features" 5 | "github.com/stretchr/testify/require" 6 | "testing" 7 | ) 8 | 9 | func TestFeatures(t *testing.T) { 10 | f := features.MinimalFeatureSet.With(features.FeatureMovesHistory, "DISABLED") 11 | require.Equal(t, "DISABLED", f[features.FeatureMovesHistory]) 12 | require.Equal(t, "AMH=DISABLED,HL=DISABLED,MH=DISABLED,MHPCEV=DISABLED,TMH=DISABLED", f.String()) 13 | } 14 | -------------------------------------------------------------------------------- /internal/machine/account.go: -------------------------------------------------------------------------------- 1 | package machine 2 | 3 | import ( 4 | "fmt" 5 | "github.com/formancehq/ledger/pkg/accounts" 6 | ) 7 | 8 | type AccountAddress string 9 | 10 | func (AccountAddress) GetType() Type { return TypeAccount } 11 | func (a AccountAddress) String() string { 12 | return fmt.Sprintf("@%v", string(a)) 13 | } 14 | 15 | func ValidateAccountAddress(acc AccountAddress) error { 16 | if !accounts.Regexp.MatchString(string(acc)) { 17 | return fmt.Errorf("accounts should respect pattern %s", accounts.Pattern) 18 | } 19 | return nil 20 | } 21 | -------------------------------------------------------------------------------- /internal/machine/address.go: -------------------------------------------------------------------------------- 1 | package machine 2 | 3 | import "encoding/binary" 4 | 5 | // Address represents an address in the machine's resources, which include 6 | // constants (literals) and variables passed to the program 7 | type Address uint16 8 | 9 | func NewAddress(x uint16) Address { 10 | return Address(x) 11 | } 12 | 13 | func (a Address) ToBytes() []byte { 14 | bytes := make([]byte, 2) 15 | binary.LittleEndian.PutUint16(bytes, uint16(a)) 16 | return bytes 17 | } 18 | 19 | type Addresses []Address 20 | 21 | func (a Addresses) Len() int { 22 | return len(a) 23 | } 24 | 25 | func (a Addresses) Less(i, j int) bool { 26 | return a[i] < a[j] 27 | } 28 | 29 | func (a Addresses) Swap(i, j int) { 30 | a[i], a[j] = a[j], a[i] 31 | } 32 | -------------------------------------------------------------------------------- /internal/machine/asset.go: -------------------------------------------------------------------------------- 1 | package machine 2 | 3 | import ( 4 | "fmt" 5 | "github.com/formancehq/ledger/pkg/assets" 6 | ) 7 | 8 | type Asset string 9 | 10 | func (Asset) GetType() Type { return TypeAsset } 11 | func (a Asset) String() string { 12 | return fmt.Sprintf("%v", string(a)) 13 | } 14 | 15 | type HasAsset interface { 16 | GetAsset() Asset 17 | } 18 | 19 | func (a Asset) GetAsset() Asset { return a } 20 | 21 | func ValidateAsset(ass Asset) error { 22 | if !assets.Regexp.MatchString(string(ass)) { 23 | return fmt.Errorf("asset should respect pattern '%s'", assets.Pattern) 24 | } 25 | return nil 26 | } 27 | -------------------------------------------------------------------------------- /internal/machine/docs/instructions.md: -------------------------------------------------------------------------------- 1 | # Formance Machine Instruction Set 2 | 3 | ``` 4 | INIT 5 | LOAD address 6 | BEGIN 7 | BALANCE asset, address 8 | IPUSH value 9 | MPUSH value 10 | RPUSH value 11 | GET register 12 | SET register 13 | IADD 14 | ISUB 15 | IMUL 16 | MADD 17 | MSUB 18 | RMUL 19 | RDD 20 | RSUB 21 | TXSTART size 22 | TXEND 23 | SEND source, destination, value 24 | FLUSH 25 | COMMIT 26 | ABORT 27 | ``` 28 | -------------------------------------------------------------------------------- /internal/machine/docs/types.md: -------------------------------------------------------------------------------- 1 | # Formance Machine Types 2 | 3 | ``` 4 | # Integers 5 | unsigned 128 bits integers 6 | 7 | # Monetary values 8 | {USD/2 100} 9 | ``` 10 | -------------------------------------------------------------------------------- /internal/machine/number.go: -------------------------------------------------------------------------------- 1 | package machine 2 | 3 | type Number = *MonetaryInt 4 | 5 | func NewNumber(i int64) Number { 6 | return NewMonetaryInt(i) 7 | } 8 | 9 | func ParseNumber(s string) (Number, error) { 10 | return ParseMonetaryInt(s) 11 | } 12 | -------------------------------------------------------------------------------- /internal/machine/script/compiler/error_test.go: -------------------------------------------------------------------------------- 1 | package compiler 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestEndCharacter(t *testing.T) { 8 | src := ` 9 | send [CREDIT 200] ( 10 | source = @a 11 | destination = { 12 | 500% to @b 13 | 50% to @c 14 | } 15 | ) 16 | ` 17 | 18 | _, err := Compile(src) 19 | if err == nil { 20 | t.Fatal("expected error and got none") 21 | } 22 | 23 | if _, ok := err.(*CompileErrorList); !ok { 24 | t.Fatal("error had wrong type") 25 | } 26 | 27 | compErr := err.(*CompileErrorList).Errors[0] 28 | 29 | if compErr.StartL != 5 { 30 | t.Fatalf("start line was %v", compErr.StartL) 31 | } 32 | if compErr.StartC != 3 { 33 | t.Fatalf("start character was %v", compErr.StartC) 34 | } 35 | if compErr.EndL != 5 { 36 | t.Fatalf("end line was %v", compErr.EndL) 37 | } 38 | if compErr.EndC != 7 { 39 | t.Fatalf("end character was %v", compErr.EndC) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /internal/machine/script/generate.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | //go:generate ./generate.sh 4 | -------------------------------------------------------------------------------- /internal/machine/script/generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | if [[ "${TRACE-0}" == "1" ]]; then 7 | set -o xtrace 8 | fi 9 | 10 | cd "$(dirname "$0")" 11 | 12 | ANTLR_VERSION='4.10.1' 13 | 14 | main() { 15 | curl --continue-at - https://www.antlr.org/download/antlr-$ANTLR_VERSION-complete.jar -O 16 | java -Xmx500M -cp "./antlr-$ANTLR_VERSION-complete.jar" org.antlr.v4.Tool -Dlanguage=Go -o parser NumScript.g4 17 | } 18 | 19 | main "$@" 20 | -------------------------------------------------------------------------------- /internal/machine/vm/program/program_test.go: -------------------------------------------------------------------------------- 1 | package program_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/formancehq/ledger/internal/machine/script/compiler" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestProgram_String(t *testing.T) { 11 | p, err := compiler.Compile(` 12 | send [COIN 99] ( 13 | source = @world 14 | destination = @alice 15 | )`) 16 | require.NoError(t, err) 17 | _ = p.String() 18 | } 19 | -------------------------------------------------------------------------------- /internal/machine/vm/program/resource_test.go: -------------------------------------------------------------------------------- 1 | package program 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/formancehq/ledger/internal/machine" 7 | 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestResource(t *testing.T) { 12 | c := Constant{ 13 | Inner: machine.NewMonetaryInt(0), 14 | } 15 | c.GetType() 16 | require.Equal(t, "0", c.String()) 17 | 18 | v := Variable{ 19 | Typ: machine.TypeAccount, 20 | Name: "acc", 21 | } 22 | require.Equal(t, "", v.String()) 23 | 24 | vab := VariableAccountBalance{ 25 | Name: "name", 26 | Account: machine.Address(0), 27 | Asset: machine.Address(1), 28 | } 29 | require.Equal(t, "", vab.String()) 30 | 31 | vam := VariableAccountMetadata{ 32 | Typ: machine.TypeMonetary, 33 | Name: "name", 34 | Account: machine.Address(0), 35 | Key: "key", 36 | } 37 | require.Equal(t, "", vam.String()) 38 | } 39 | -------------------------------------------------------------------------------- /internal/machine/vm/stack.go: -------------------------------------------------------------------------------- 1 | package vm 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/formancehq/ledger/internal/machine" 7 | ) 8 | 9 | func (m *Machine) popValue() machine.Value { 10 | l := len(m.Stack) 11 | x := m.Stack[l-1] 12 | m.Stack = m.Stack[:l-1] 13 | return x 14 | } 15 | 16 | func pop[T machine.Value](m *Machine) T { 17 | x := m.popValue() 18 | if v, ok := x.(T); ok { 19 | return v 20 | } 21 | panic(fmt.Errorf("unexpected type '%T' on stack", x)) 22 | } 23 | 24 | func (m *Machine) pushValue(v machine.Value) { 25 | m.Stack = append(m.Stack, v) 26 | } 27 | -------------------------------------------------------------------------------- /internal/metadata.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "fmt" 5 | "github.com/formancehq/go-libs/v3/metadata" 6 | ) 7 | 8 | const ( 9 | formanceNamespace = "com.formance.spec/" 10 | revertKey = "state/reverts" 11 | 12 | MetaTargetTypeAccount = "ACCOUNT" 13 | MetaTargetTypeTransaction = "TRANSACTION" 14 | ) 15 | 16 | func SpecMetadata(name string) string { 17 | return formanceNamespace + name 18 | } 19 | 20 | func MarkReverts(m metadata.Metadata, txID uint64) metadata.Metadata { 21 | return m.Merge(RevertMetadata(txID)) 22 | } 23 | 24 | func RevertMetadataSpecKey() string { 25 | return SpecMetadata(revertKey) 26 | } 27 | 28 | func ComputeMetadata(key, value string) metadata.Metadata { 29 | return metadata.Metadata{ 30 | key: value, 31 | } 32 | } 33 | 34 | func RevertMetadata(txID uint64) metadata.Metadata { 35 | return ComputeMetadata(RevertMetadataSpecKey(), fmt.Sprint(txID)) 36 | } 37 | -------------------------------------------------------------------------------- /internal/storage/bucket/default_bucket_test.go: -------------------------------------------------------------------------------- 1 | //go:build it 2 | 3 | package bucket_test 4 | 5 | import ( 6 | "github.com/formancehq/go-libs/v3/bun/bundebug" 7 | "github.com/formancehq/ledger/internal/storage/bucket" 8 | "github.com/formancehq/ledger/internal/storage/system" 9 | "go.opentelemetry.io/otel/trace/noop" 10 | "testing" 11 | 12 | "github.com/formancehq/go-libs/v3/bun/bunconnect" 13 | 14 | "github.com/formancehq/go-libs/v3/logging" 15 | "github.com/google/uuid" 16 | "github.com/stretchr/testify/require" 17 | ) 18 | 19 | func TestBuckets(t *testing.T) { 20 | ctx := logging.TestingContext() 21 | name := uuid.NewString()[:8] 22 | 23 | pgDatabase := srv.NewDatabase(t) 24 | db, err := bunconnect.OpenSQLDB(ctx, pgDatabase.ConnectionOptions()) 25 | require.NoError(t, err) 26 | 27 | if testing.Verbose() { 28 | db.AddQueryHook(bundebug.NewQueryHook()) 29 | } 30 | 31 | require.NoError(t, system.Migrate(ctx, db)) 32 | 33 | b := bucket.NewDefault(noop.Tracer{}, name) 34 | require.NoError(t, b.Migrate(ctx, db)) 35 | } 36 | -------------------------------------------------------------------------------- /internal/storage/bucket/main_test.go: -------------------------------------------------------------------------------- 1 | //go:build it 2 | 3 | package bucket_test 4 | 5 | import ( 6 | . "github.com/formancehq/go-libs/v3/testing/utils" 7 | "testing" 8 | 9 | "github.com/formancehq/go-libs/v3/logging" 10 | "github.com/formancehq/go-libs/v3/testing/docker" 11 | "github.com/formancehq/go-libs/v3/testing/platform/pgtesting" 12 | ) 13 | 14 | var ( 15 | srv *pgtesting.PostgresServer 16 | ) 17 | 18 | func TestMain(m *testing.M) { 19 | WithTestMain(func(t *TestingTForMain) int { 20 | srv = pgtesting.CreatePostgresServer(t, docker.NewPool(t, logging.Testing())) 21 | 22 | return m.Run() 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/0-init-schema/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Initialize schema 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/1-fix-trigger/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix triggers 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/10-fillfactor-on-moves/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Define fill factor of moves table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/10-fillfactor-on-moves/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | alter table moves set (fillfactor = 80); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/11-make-stateless/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Make stateless 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/12-transaction-sequence-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create transaction sequences index concurrently 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/12-transaction-sequence-index/up.sql: -------------------------------------------------------------------------------- 1 | create index {{ if not .Transactional }}concurrently{{end}} transactions_sequences on "{{.Schema}}".transactions (id, seq); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/13-accounts-sequence-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create accounts sequences index concurrently 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/13-accounts-sequence-index/up.sql: -------------------------------------------------------------------------------- 1 | create index {{ if not .Transactional }}concurrently{{end}} accounts_sequences on "{{.Schema}}".accounts (address, seq); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/14-transaction-reference-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create transaction reference index concurrently 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/14-transaction-reference-index/up.sql: -------------------------------------------------------------------------------- 1 | create unique index {{ if not .Transactional }}concurrently{{end}} transactions_reference2 on "{{.Schema}}".transactions (ledger, reference) where reference <> ''; -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/15-create-ledger-indexes/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create ledger indexes 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/15-create-ledger-indexes/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | drop trigger enforce_reference_uniqueness on transactions; 4 | drop function enforce_reference_uniqueness(); 5 | 6 | drop index transactions_reference; 7 | alter index transactions_reference2 rename to transactions_reference; -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create transaction id index on moves 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/up.sql: -------------------------------------------------------------------------------- 1 | create index {{ if not .Transactional }}concurrently{{end}} moves_transactions_id on "{{ .Schema }}".moves(transactions_id); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/17-moves-fill-transaction-id/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill transaction ids of table moves 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/17-moves-fill-transaction-id/up_tests_after.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/internal/storage/bucket/migrations/17-moves-fill-transaction-id/up_tests_after.sql -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/17-moves-fill-transaction-id/up_tests_before.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/internal/storage/bucket/migrations/17-moves-fill-transaction-id/up_tests_before.sql -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/18-transactions-fill-inserted-at/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill inserted_at column of transactions table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/18-transactions-fill-inserted-at/up_tests_after.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | begin 3 | set search_path = '{{.Schema}}'; 4 | assert (select count(*) from transactions where inserted_at is null) = 0, 'inserted_at should not be null'; 5 | end; 6 | $$ -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/18-transactions-fill-inserted-at/up_tests_before.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/internal/storage/bucket/migrations/18-transactions-fill-inserted-at/up_tests_before.sql -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/19-transactions-fill-pcv/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill post_commit_volumes column of transactions table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/19-transactions-fill-pcv/up_tests_after.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | declare 3 | expected varchar = '{"fees": {"USD": {"input": 1, "output": 0}}, "world": {"USD": {"input": 0, "output": 100}, "SELL": {"input": 0, "output": 1}}, "orders:0": {"USD": {"input": 100, "output": 100}}, "sellers:0": {"USD": {"input": 99, "output": 0}, "SELL": {"input": 1, "output": 0}}}'; 4 | begin 5 | set search_path = '{{.Schema}}'; 6 | assert (select post_commit_volumes::varchar from transactions where id = 0) = expected, 7 | 'post_commit_volumes should be equals to ' || expected || ' but was ' || (select to_jsonb(post_commit_volumes) from transactions where id = 0); 8 | end; 9 | $$ -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/19-transactions-fill-pcv/up_tests_before.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/formancehq/ledger/b9b8f1494ce9dc7a3b367dce85c89d9f4bbfaeff/internal/storage/bucket/migrations/19-transactions-fill-pcv/up_tests_before.sql -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/2-fix-volumes-aggregation/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix volumes aggregation 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/2-fix-volumes-aggregation/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | create or replace function get_all_account_volumes(_ledger varchar, _account varchar, _before timestamp default null) 4 | returns setof volumes_with_asset 5 | language sql 6 | stable 7 | as 8 | $$ 9 | with all_assets as (select v.v as asset 10 | from get_all_assets(_ledger) v), 11 | moves as (select m.* 12 | from all_assets assets 13 | join lateral ( 14 | select * 15 | from moves s 16 | where (_before is null or s.effective_date <= _before) 17 | and s.account_address = _account 18 | and s.asset = assets.asset 19 | and s.ledger = _ledger 20 | order by seq desc 21 | limit 1 22 | ) m on true) 23 | select moves.asset, moves.post_commit_volumes 24 | from moves 25 | $$ set search_path from current; -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/20-accounts-volumes-fill-history/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Populate accounts_volumes table with historic data 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/21-transactions-metadata-fill-transaction-id/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill transactions_id column of transactions_metadata table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/22-accounts-metadata-fill-address/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill accounts_address column of accounts_metadata table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/23-logs-fill-memento/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill memento column of logs table 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/23-logs-fill-memento/up.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | declare 3 | _batch_size integer := 1000; 4 | _count integer; 5 | begin 6 | set search_path = '{{.Schema}}'; 7 | 8 | select count(seq) 9 | from logs 10 | where memento is null 11 | into _count; 12 | 13 | perform pg_notify('migrations-{{ .Schema }}', 'init: ' || _count); 14 | 15 | loop 16 | with _outdated_logs as ( 17 | select seq 18 | from logs 19 | where memento is null 20 | limit _batch_size 21 | ) 22 | update logs 23 | set memento = convert_to(data::varchar, 'UTF-8')::bytea 24 | from _outdated_logs 25 | where logs.seq in (_outdated_logs.seq); 26 | 27 | exit when not found; 28 | 29 | commit; 30 | 31 | perform pg_notify('migrations-{{ .Schema }}', 'continue: ' || _batch_size); 32 | end loop; 33 | 34 | alter table logs 35 | add constraint memento_not_null 36 | check (memento is not null) 37 | not valid; 38 | end 39 | $$; 40 | 41 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/24-accounts-metadata-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create accounts metadata index concurrently 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/24-accounts-metadata-index/up.sql: -------------------------------------------------------------------------------- 1 | create index {{ if not .Transactional }}concurrently{{end}} accounts_metadata_idx on "{{.Schema}}".accounts using gin(metadata JSONB_PATH_OPS); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/25-accounts-volumes-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create accounts volumes index concurrently 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/25-accounts-volumes-index/up.sql: -------------------------------------------------------------------------------- 1 | create index {{ if not .Transactional }}concurrently{{end}} accounts_volumes_idx on "{{.Schema}}".accounts_volumes (ledger, accounts_address, asset) include (input, output); 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/26-fix-hashing-function/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix hashing function 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/27-fix-invalid-pcv/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill invalid post_commit_volumes after upgrade existing txs to v2.2 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/28-fix-pcv-missing-asset/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill invalid post_commit_volumes (missing asset) 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill invalid metadata on reverts transactions 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up_tests_after.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | declare 3 | expected varchar = '{"tax": "1%", "com.formance.spec/state/reverts": "2"}'; 4 | begin 5 | set search_path = '{{.Schema}}'; 6 | assert (select metadata::varchar from transactions where id = 22 and ledger = 'ledger0') = expected, 7 | 'metadata should be equals to ' || expected || ' but was ' || (select to_jsonb(metadata) from transactions where id = 22 and ledger = 'ledger0'); 8 | end; 9 | $$ -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/29-fix-invalid-metadata-on-reverts/up_tests_before.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | declare 3 | expected varchar = '{"tax": "1%"}'; 4 | begin 5 | set search_path = '{{.Schema}}'; 6 | 7 | insert into transactions ( 8 | ledger, 9 | id, 10 | inserted_at, 11 | postings, 12 | post_commit_volumes 13 | ) values ( 14 | 'ledger0', 15 | nextval('transaction_id_1'), 16 | now(), 17 | '[{"source": "world", "destination": "bank", "asset": "USD", "amount": 100}]', 18 | '{}' 19 | ); 20 | 21 | assert (select metadata::varchar from transactions where id = 22 and ledger = 'ledger0') = expected, 22 | 'metadata should be equals to ' || expected || ' but was ' || (select to_jsonb(metadata) from transactions where id = 22 and ledger = 'ledger0'); 23 | end; 24 | $$ -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/3-fix-trigger-inserting-backdated-transactions/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix backdated transactions insertion 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/30-transaction-updated-at-trigger/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill transaction updated_at 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/30-transaction-updated-at-trigger/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{ .Schema }}'; 2 | 3 | create or replace function set_transaction_updated_at() returns trigger 4 | security definer 5 | language plpgsql 6 | as 7 | $$ 8 | begin 9 | new.updated_at = new.inserted_at; 10 | 11 | return new; 12 | end 13 | $$ set search_path from current; 14 | 15 | create trigger set_transaction_updated_at 16 | before insert on transactions 17 | for each row 18 | when ( new.updated_at is null ) 19 | execute procedure set_transaction_updated_at(); 20 | 21 | alter table transactions 22 | add constraint transactions_updated_at_not_null 23 | check (updated_at is not null) 24 | not valid; -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/31-fix-transaction-updated-at/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill transaction updated_at 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/31-fix-transaction-updated-at/up_tests_after.sql: -------------------------------------------------------------------------------- 1 | do $$ 2 | begin 3 | set search_path = '{{.Schema}}'; 4 | assert (select count(*) from transactions where updated_at is null) = 0, 'updated_at should not be null'; 5 | end; 6 | $$ -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/32-fix-log-data-for-reverted-transactions/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fill log data for reverted transactions 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/33-fix-invalid-date-format/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix invalid date format 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/34-fix-memento-format/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix memento format 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/35-create-compute-hash-function/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create compute_hash function 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/36-accounts-recreate-unique-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Recreate accounts unique index 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/36-accounts-recreate-unique-index/up.sql: -------------------------------------------------------------------------------- 1 | -- There is already a covering index on accounts table (including seq column). 2 | -- As we will remove the seq column in next migration, we have to create a new index without it (PG will remove it automatically in background). 3 | -- Also, we create the index concurrently to avoid locking the table. 4 | -- And, as there is already an index on this table, the index creation should not fail. 5 | -- 6 | -- We create this index in a dedicated as, as the doc mentions it (https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-MULTI-STATEMENT) 7 | -- multi statements queries are automatically wrapped inside transaction block, and it's forbidden 8 | -- to create index concurrently inside a transaction block. 9 | create unique index {{ if not .Transactional }}concurrently{{end}} accounts_ledger2 on "{{.Schema}}".accounts (ledger, address) -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/37-clean-database/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Clean not used columns in database 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/38-logs-async-hash-procedure/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Create async hash log procedure -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/39-clean-useless-features/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Clean useless features -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/4-add-account-first-usage-column/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Add first_usage on accounts 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/40-refine-columns-types/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Refine some column types -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/5-add-idempotency-key-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix missing idempotency key index 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/5-add-idempotency-key-index/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | create index logs_idempotency_key on logs (idempotency_key); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/6-add-reference-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix missing reference index 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/6-add-reference-index/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | create index transactions_reference on transactions (reference); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/7-add-ik-unique-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Add unique index on ik 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/7-add-ik-unique-index/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | update logs 4 | set idempotency_key = null 5 | where idempotency_key = ''; 6 | 7 | update logs 8 | set idempotency_key = null 9 | where id in ( 10 | select unnest(duplicateLogIds.ids[2:]) as id 11 | from ( 12 | select array_agg(id order by id) as ids 13 | from logs l 14 | where idempotency_key is not null 15 | group by idempotency_key 16 | having count(*) > 1 17 | ) duplicateLogIds 18 | ); 19 | 20 | drop index logs_idempotency_key; 21 | 22 | create unique index logs_idempotency_key on logs (idempotency_key); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/8-ik-ledger-unique-index/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Add unique index on ledger names 2 | -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/8-ik-ledger-unique-index/up.sql: -------------------------------------------------------------------------------- 1 | set search_path = '{{.Schema}}'; 2 | 3 | drop index logs_idempotency_key; 4 | 5 | create unique index logs_idempotency_key on logs (ledger, idempotency_key); -------------------------------------------------------------------------------- /internal/storage/bucket/migrations/9-fix-incorrect-volumes-aggregation/notes.yaml: -------------------------------------------------------------------------------- 1 | name: Fix incorrect volumes aggregation 2 | -------------------------------------------------------------------------------- /internal/storage/common/errors.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "fmt" 4 | 5 | type ErrInvalidQuery struct { 6 | msg string 7 | } 8 | 9 | func (e ErrInvalidQuery) Error() string { 10 | return e.msg 11 | } 12 | 13 | func (e ErrInvalidQuery) Is(err error) bool { 14 | _, ok := err.(ErrInvalidQuery) 15 | return ok 16 | } 17 | 18 | func NewErrInvalidQuery(msg string, args ...any) ErrInvalidQuery { 19 | return ErrInvalidQuery{ 20 | msg: fmt.Sprintf(msg, args...), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /internal/storage/common/metadata.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "regexp" 4 | 5 | var ( 6 | MetadataRegex = regexp.MustCompile(`metadata\[(.+)]`) 7 | ) 8 | -------------------------------------------------------------------------------- /internal/storage/common/paginator.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/formancehq/go-libs/v3/bun/bunpaginate" 5 | "github.com/uptrace/bun" 6 | ) 7 | 8 | type Paginator[ResourceType any, PaginationOptions any] interface { 9 | Paginate(selectQuery *bun.SelectQuery, opts PaginationOptions) (*bun.SelectQuery, error) 10 | BuildCursor(ret []ResourceType, opts PaginationOptions) (*bunpaginate.Cursor[ResourceType], error) 11 | } 12 | -------------------------------------------------------------------------------- /internal/storage/driver/errors.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | import "fmt" 4 | 5 | type ErrRollbackDetected struct { 6 | LastRegisterVersion int 7 | LastAvailableVersion int 8 | } 9 | 10 | func (e ErrRollbackDetected) Error() string { 11 | return fmt.Sprintf("rollback detected, last register version: %d, last available version: %d", e.LastRegisterVersion, e.LastAvailableVersion) 12 | } 13 | 14 | func (e ErrRollbackDetected) Is(err error) bool { 15 | _, ok := err.(ErrRollbackDetected) 16 | return ok 17 | } 18 | 19 | func newErrRollbackDetected(lastRegisterVersion, lastAvailableVersion int) ErrRollbackDetected { 20 | return ErrRollbackDetected{ 21 | LastRegisterVersion: lastRegisterVersion, 22 | LastAvailableVersion: lastAvailableVersion, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /internal/storage/driver/mocks.go: -------------------------------------------------------------------------------- 1 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../bucket/bucket.go -destination buckets_generated_test.go -package driver . Bucket 2 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../bucket/bucket.go -destination buckets_generated_test.go -package driver --mock_names Factory=BucketFactory . Factory 3 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../ledger/factory.go -destination ledger_generated_test.go -package driver --mock_names Factory=LedgerStoreFactory . Factory 4 | //go:generate mockgen -write_source_comment=false -write_package_comment=false -source ../system/store.go -destination system_generated_test.go -package driver --mock_names Store=SystemStore . Store 5 | 6 | package driver 7 | -------------------------------------------------------------------------------- /internal/storage/driver/rollbacks.go: -------------------------------------------------------------------------------- 1 | package driver 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "github.com/formancehq/go-libs/v3/migrations" 8 | ) 9 | 10 | func detectDowngrades(migrator *migrations.Migrator, ctx context.Context) error { 11 | lastVersion, err := migrator.GetLastVersion(ctx) 12 | if err != nil { 13 | if !errors.Is(err, migrations.ErrMissingVersionTable) { 14 | return fmt.Errorf("failed to get last version: %w", err) 15 | } 16 | } 17 | if err == nil && lastVersion != -1 { 18 | allMigrations, err := migrator.GetMigrations(ctx) 19 | if err != nil { 20 | return fmt.Errorf("failed to get all migrations: %w", err) 21 | } 22 | 23 | if len(allMigrations) < lastVersion { 24 | return newErrRollbackDetected(lastVersion, len(allMigrations)) 25 | } 26 | } 27 | 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /internal/storage/ledger/debug.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "fmt" 7 | "github.com/shomali11/xsql" 8 | "github.com/uptrace/bun" 9 | ) 10 | 11 | //nolint:unused 12 | func (store *Store) DumpTables(ctx context.Context, tables ...string) { 13 | for _, table := range tables { 14 | store.DumpQuery( 15 | ctx, 16 | store.db.NewSelect(). 17 | ModelTableExpr(store.GetPrefixedRelationName(table)), 18 | ) 19 | } 20 | } 21 | 22 | //nolint:unused 23 | func (store *Store) DumpQuery(ctx context.Context, query *bun.SelectQuery) { 24 | fmt.Println(query) 25 | rows, err := query.Rows(ctx) 26 | if err != nil { 27 | panic(err) 28 | } 29 | store.DumpRows(rows) 30 | } 31 | 32 | //nolint:unused 33 | func (store *Store) DumpRows(rows *sql.Rows) { 34 | data, err := xsql.Pretty(rows) 35 | if err != nil { 36 | panic(err) 37 | } 38 | fmt.Println(data) 39 | if err := rows.Close(); err != nil { 40 | panic(err) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /internal/storage/ledger/factory.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | ledger "github.com/formancehq/ledger/internal" 5 | "github.com/formancehq/ledger/internal/storage/bucket" 6 | "github.com/uptrace/bun" 7 | ) 8 | 9 | type Factory interface { 10 | Create(bucket.Bucket, ledger.Ledger) *Store 11 | } 12 | 13 | type DefaultFactory struct { 14 | db *bun.DB 15 | options []Option 16 | } 17 | 18 | func NewFactory(db *bun.DB, options ...Option) *DefaultFactory { 19 | return &DefaultFactory{ 20 | db: db, 21 | options: options, 22 | } 23 | } 24 | 25 | func (d *DefaultFactory) Create(b bucket.Bucket, l ledger.Ledger) *Store { 26 | return New(d.db, b, l, d.options...) 27 | } 28 | -------------------------------------------------------------------------------- /internal/storage/ledger/moves.go: -------------------------------------------------------------------------------- 1 | package ledger 2 | 3 | import ( 4 | "context" 5 | "github.com/formancehq/go-libs/v3/platform/postgres" 6 | ledger "github.com/formancehq/ledger/internal" 7 | "github.com/formancehq/ledger/internal/tracing" 8 | ) 9 | 10 | func (store *Store) InsertMoves(ctx context.Context, moves ...*ledger.Move) error { 11 | _, err := tracing.TraceWithMetric( 12 | ctx, 13 | "InsertMoves", 14 | store.tracer, 15 | store.insertMovesHistogram, 16 | tracing.NoResult(func(ctx context.Context) error { 17 | _, err := store.db.NewInsert(). 18 | Model(&moves). 19 | Value("ledger", "?", store.ledger.Name). 20 | ModelTableExpr(store.GetPrefixedRelationName("moves")). 21 | Returning("post_commit_volumes, post_commit_effective_volumes"). 22 | Exec(ctx) 23 | 24 | return postgres.ResolveError(err) 25 | }), 26 | ) 27 | 28 | return err 29 | } 30 | -------------------------------------------------------------------------------- /internal/storage/system/factory.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "github.com/uptrace/bun" 5 | ) 6 | 7 | type StoreFactory interface { 8 | Create(db bun.IDB) Store 9 | } 10 | 11 | type DefaultStoreFactory struct { 12 | options []Option 13 | } 14 | 15 | func (s DefaultStoreFactory) Create(db bun.IDB) Store { 16 | return New(db, s.options...) 17 | } 18 | 19 | var _ StoreFactory = DefaultStoreFactory{} 20 | 21 | func NewStoreFactory(opts ...Option) DefaultStoreFactory { 22 | return DefaultStoreFactory{options: opts} 23 | } -------------------------------------------------------------------------------- /internal/storage/system/main_test.go: -------------------------------------------------------------------------------- 1 | //go:build it 2 | 3 | package system 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/formancehq/go-libs/v3/testing/docker" 9 | "github.com/formancehq/go-libs/v3/testing/utils" 10 | 11 | "github.com/formancehq/go-libs/v3/logging" 12 | "github.com/formancehq/go-libs/v3/testing/platform/pgtesting" 13 | ) 14 | 15 | var srv *pgtesting.PostgresServer 16 | 17 | func TestMain(m *testing.M) { 18 | utils.WithTestMain(func(t *utils.TestingTForMain) int { 19 | srv = pgtesting.CreatePostgresServer(t, docker.NewPool(t, logging.Testing())) 20 | 21 | return m.Run() 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/formancehq/ledger/cmd" 5 | ) 6 | 7 | func main() { 8 | cmd.Execute() 9 | } 10 | -------------------------------------------------------------------------------- /openapi/overlay.yaml: -------------------------------------------------------------------------------- 1 | paths: 2 | x-speakeasy-errors: 3 | statusCodes: 4 | - default 5 | -------------------------------------------------------------------------------- /pkg/accounts/accounts.go: -------------------------------------------------------------------------------- 1 | package accounts 2 | 3 | import "regexp" 4 | 5 | const SegmentRegex = "[a-zA-Z0-9_-]+" 6 | const Pattern = "^" + SegmentRegex + "(:" + SegmentRegex + ")*$" 7 | 8 | var Regexp = regexp.MustCompile(Pattern) 9 | 10 | func ValidateAddress(addr string) bool { 11 | return Regexp.Match([]byte(addr)) 12 | } 13 | -------------------------------------------------------------------------------- /pkg/assets/asset.go: -------------------------------------------------------------------------------- 1 | package assets 2 | 3 | import ( 4 | "regexp" 5 | ) 6 | 7 | const Pattern = `[A-Z][A-Z0-9]{0,16}(\/\d{1,6})?` 8 | 9 | var Regexp = regexp.MustCompile("^" + Pattern + "$") 10 | 11 | func IsValid(v string) bool { 12 | return Regexp.Match([]byte(v)) 13 | } 14 | -------------------------------------------------------------------------------- /pkg/client/.devcontainer/README.md: -------------------------------------------------------------------------------- 1 | 2 | > **Remember to shutdown a GitHub Codespace when it is not in use!** 3 | 4 | # Dev Containers Quick Start 5 | 6 | The default location for usage snippets is the `samples` directory. 7 | 8 | ## Running a Usage Sample 9 | 10 | A sample usage example has been provided in a `root.go` file. As you work with the SDK, it's expected that you will modify these samples to fit your needs. To execute this particular snippet, use the command below. 11 | 12 | ``` 13 | go run root.go 14 | ``` 15 | 16 | ## Generating Additional Usage Samples 17 | 18 | The speakeasy CLI allows you to generate more usage snippets. Here's how: 19 | 20 | - To generate a sample for a specific operation by providing an operation ID, use: 21 | 22 | ``` 23 | speakeasy generate usage -s openapi/v2.yaml -l go -i {INPUT_OPERATION_ID} -o ./samples 24 | ``` 25 | 26 | - To generate samples for an entire namespace (like a tag or group name), use: 27 | 28 | ``` 29 | speakeasy generate usage -s openapi/v2.yaml -l go -n {INPUT_TAG_NAME} -o ./samples 30 | ``` 31 | -------------------------------------------------------------------------------- /pkg/client/.devcontainer/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Install the speakeasy CLI 4 | curl -fsSL https://raw.githubusercontent.com/speakeasy-api/speakeasy/main/install.sh | sh 5 | 6 | # Setup samples directory 7 | rmdir samples || true 8 | mkdir samples 9 | 10 | # Go module commands 11 | go mod download 12 | go mod tidy 13 | 14 | # Generate starter usage sample with speakeasy 15 | speakeasy generate usage -s openapi/v2.yaml -l go -o samples/root.go -------------------------------------------------------------------------------- /pkg/client/.gitattributes: -------------------------------------------------------------------------------- 1 | # This allows generated code to be indexed correctly 2 | *.go linguist-generated=false -------------------------------------------------------------------------------- /pkg/client/.gitignore: -------------------------------------------------------------------------------- 1 | .speakeasy/reports 2 | # .gitignore 3 | -------------------------------------------------------------------------------- /pkg/client/.speakeasy/workflow.lock: -------------------------------------------------------------------------------- 1 | speakeasyVersion: 1.517.3 2 | sources: {} 3 | targets: 4 | formance: 5 | source: Formance-OAS 6 | workflow: 7 | workflowVersion: 1.0.0 8 | speakeasyVersion: v1.517.3 9 | sources: 10 | Formance-OAS: 11 | inputs: 12 | - location: ../../openapi.yaml 13 | registry: 14 | location: registry.speakeasyapi.dev/formance/gfyrag/formance-oas 15 | targets: 16 | formance: 17 | target: go 18 | source: Formance-OAS 19 | codeSamples: 20 | registry: 21 | location: registry.speakeasyapi.dev/formance/gfyrag/formance-oas-go-code-samples 22 | labelOverride: 23 | fixedValue: Go (SDK) 24 | blocking: false 25 | -------------------------------------------------------------------------------- /pkg/client/.speakeasy/workflow.yaml: -------------------------------------------------------------------------------- 1 | workflowVersion: 1.0.0 2 | speakeasyVersion: v1.517.3 3 | sources: 4 | Formance-OAS: 5 | inputs: 6 | - location: ../../openapi.yaml 7 | registry: 8 | location: registry.speakeasyapi.dev/formance/gfyrag/formance-oas 9 | targets: 10 | formance: 11 | target: go 12 | source: Formance-OAS 13 | codeSamples: 14 | registry: 15 | location: registry.speakeasyapi.dev/formance/gfyrag/formance-oas-go-code-samples 16 | labelOverride: 17 | fixedValue: Go (SDK) 18 | blocking: false 19 | -------------------------------------------------------------------------------- /pkg/client/USAGE.md: -------------------------------------------------------------------------------- 1 | 2 | ```go 3 | package main 4 | 5 | import ( 6 | "context" 7 | "github.com/formancehq/ledger/pkg/client" 8 | "github.com/formancehq/ledger/pkg/client/models/components" 9 | "log" 10 | "os" 11 | ) 12 | 13 | func main() { 14 | ctx := context.Background() 15 | 16 | s := client.New( 17 | client.WithSecurity(components.Security{ 18 | ClientID: client.String(os.Getenv("FORMANCE_CLIENT_ID")), 19 | ClientSecret: client.String(os.Getenv("FORMANCE_CLIENT_SECRET")), 20 | }), 21 | ) 22 | 23 | res, err := s.Ledger.GetInfo(ctx) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | if res.V2ConfigInfoResponse != nil { 28 | // handle response 29 | } 30 | } 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/accountscursorresponse.md: -------------------------------------------------------------------------------- 1 | # AccountsCursorResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | 8 | | `Cursor` | [components.Cursor](../../models/components/cursor.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/aggregatebalancesresponse.md: -------------------------------------------------------------------------------- 1 | # AggregateBalancesResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------------- | ------------------------- | ------------------------- | ------------------------- | ------------------------- | 8 | | `Data` | map[string]*int64* | :heavy_check_mark: | N/A | {
"USD": 100,
"EUR": 12
} | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/config.md: -------------------------------------------------------------------------------- 1 | # Config 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | 8 | | `Storage` | [components.LedgerStorage](../../models/components/ledgerstorage.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/configinforesponse.md: -------------------------------------------------------------------------------- 1 | # ConfigInfoResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- | 8 | | `Data` | [components.ConfigInfo](../../models/components/configinfo.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/errorsenum.md: -------------------------------------------------------------------------------- 1 | # ErrorsEnum 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ----------------------------- | ----------------------------- | 8 | | `ErrorsEnumInternal` | INTERNAL | 9 | | `ErrorsEnumInsufficientFund` | INSUFFICIENT_FUND | 10 | | `ErrorsEnumValidation` | VALIDATION | 11 | | `ErrorsEnumConflict` | CONFLICT | 12 | | `ErrorsEnumNoScript` | NO_SCRIPT | 13 | | `ErrorsEnumCompilationFailed` | COMPILATION_FAILED | 14 | | `ErrorsEnumMetadataOverride` | METADATA_OVERRIDE | 15 | | `ErrorsEnumNotFound` | NOT_FOUND | 16 | | `ErrorsEnumTimeout` | TIMEOUT | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/expr.md: -------------------------------------------------------------------------------- 1 | # Expr 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ----------- | ----------- | ----------- | ----------- | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/httpmetadata.md: -------------------------------------------------------------------------------- 1 | # HTTPMetadata 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- | 8 | | `Response` | [*http.Response](https://pkg.go.dev/net/http#Response) | :heavy_check_mark: | Raw HTTP response; suitable for custom response parsing | 9 | | `Request` | [*http.Request](https://pkg.go.dev/net/http#Request) | :heavy_check_mark: | Raw HTTP request; suitable for debugging | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/ledgerinforesponse.md: -------------------------------------------------------------------------------- 1 | # LedgerInfoResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | --------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------- | 8 | | `Data` | [*components.LedgerInfo](../../models/components/ledgerinfo.md) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/ledgerstorage.md: -------------------------------------------------------------------------------- 1 | # LedgerStorage 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `Driver` | *string* | :heavy_check_mark: | N/A | 9 | | `Ledgers` | []*string* | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/mapping.md: -------------------------------------------------------------------------------- 1 | # Mapping 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 8 | | `Contracts` | [][components.Contract](../../models/components/contract.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/mappingresponse.md: -------------------------------------------------------------------------------- 1 | # MappingResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------- | 8 | | `Data` | [*components.Mapping](../../models/components/mapping.md) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/runtime.md: -------------------------------------------------------------------------------- 1 | # Runtime 2 | 3 | The numscript runtime used to execute the script. Uses "machine" by default, unless the "--experimental-numscript-interpreter" feature flag is passed. 4 | 5 | 6 | ## Values 7 | 8 | | Name | Value | 9 | | -------------------------------- | -------------------------------- | 10 | | `RuntimeExperimentalInterpreter` | experimental-interpreter | 11 | | `RuntimeMachine` | machine | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `ClientID` | **string* | :heavy_minus_sign: | N/A | 9 | | `ClientSecret` | **string* | :heavy_minus_sign: | N/A | 10 | | `TokenURL` | **string* | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/state.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ----------- | ----------- | 8 | | `StateToDo` | TO DO | 9 | | `StateDone` | DONE | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/stats.md: -------------------------------------------------------------------------------- 1 | # Stats 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `Accounts` | *int64* | :heavy_check_mark: | N/A | 9 | | `Transactions` | *int64* | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/statsresponse.md: -------------------------------------------------------------------------------- 1 | # StatsResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ---------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------- | 8 | | `Data` | [components.Stats](../../models/components/stats.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/storage.md: -------------------------------------------------------------------------------- 1 | # Storage 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------- | 8 | | `Migrations` | [][components.MigrationInfo](../../models/components/migrationinfo.md) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/transactionresponse.md: -------------------------------------------------------------------------------- 1 | # TransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------- | 8 | | `Data` | [components.Transaction](../../models/components/transaction.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/transactions.md: -------------------------------------------------------------------------------- 1 | # Transactions 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | 8 | | `Transactions` | [][components.TransactionData](../../models/components/transactiondata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/transactionsresponse.md: -------------------------------------------------------------------------------- 1 | # TransactionsResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `Data` | [][components.Transaction](../../models/components/transaction.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/type.md: -------------------------------------------------------------------------------- 1 | # Type 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | -------------------- | -------------------- | 8 | | `TypeNewTransaction` | NEW_TRANSACTION | 9 | | `TypeSetMetadata` | SET_METADATA | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2accountresponse.md: -------------------------------------------------------------------------------- 1 | # V2AccountResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | 8 | | `Data` | [components.V2Account](../../models/components/v2account.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2aggregatebalancesresponse.md: -------------------------------------------------------------------------------- 1 | # V2AggregateBalancesResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | ------------------------------------------------------ | 8 | | `Data` | map[string][*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | {
"USD": 100,
"EUR": 12
} | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2bulkelement.md: -------------------------------------------------------------------------------- 1 | # V2BulkElement 2 | 3 | 4 | ## Supported Types 5 | 6 | ### V2BulkElementCreateTransaction 7 | 8 | ```go 9 | v2BulkElement := components.CreateV2BulkElementCreateTransaction(components.V2BulkElementCreateTransaction{/* values here */}) 10 | ``` 11 | 12 | ### V2BulkElementAddMetadata 13 | 14 | ```go 15 | v2BulkElement := components.CreateV2BulkElementAddMetadata(components.V2BulkElementAddMetadata{/* values here */}) 16 | ``` 17 | 18 | ### V2BulkElementRevertTransaction 19 | 20 | ```go 21 | v2BulkElement := components.CreateV2BulkElementRevertTransaction(components.V2BulkElementRevertTransaction{/* values here */}) 22 | ``` 23 | 24 | ### V2BulkElementDeleteMetadata 25 | 26 | ```go 27 | v2BulkElement := components.CreateV2BulkElementDeleteMetadata(components.V2BulkElementDeleteMetadata{/* values here */}) 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2bulkelementresultaddmetadata.md: -------------------------------------------------------------------------------- 1 | # V2BulkElementResultAddMetadata 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `ResponseType` | *string* | :heavy_check_mark: | N/A | 9 | | `LogID` | *int64* | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2bulkelementresultdeletemetadata.md: -------------------------------------------------------------------------------- 1 | # V2BulkElementResultDeleteMetadata 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `ResponseType` | *string* | :heavy_check_mark: | N/A | 9 | | `LogID` | *int64* | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2bulkelementresulterror.md: -------------------------------------------------------------------------------- 1 | # V2BulkElementResultError 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `ResponseType` | *string* | :heavy_check_mark: | N/A | 9 | | `LogID` | *int64* | :heavy_check_mark: | N/A | 10 | | `ErrorCode` | *string* | :heavy_check_mark: | N/A | 11 | | `ErrorDescription` | *string* | :heavy_check_mark: | N/A | 12 | | `ErrorDetails` | **string* | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2bulkelementreverttransactiondata.md: -------------------------------------------------------------------------------- 1 | # V2BulkElementRevertTransactionData 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | 8 | | `ID` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | 9 | | `Force` | **bool* | :heavy_minus_sign: | N/A | 10 | | `AtEffectiveDate` | **bool* | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2configinforesponse.md: -------------------------------------------------------------------------------- 1 | # V2ConfigInfoResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `Server` | *string* | :heavy_check_mark: | N/A | 9 | | `Version` | *string* | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2createledgerrequest.md: -------------------------------------------------------------------------------- 1 | # V2CreateLedgerRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Bucket` | **string* | :heavy_minus_sign: | N/A | | 9 | | `Metadata` | map[string]*string* | :heavy_minus_sign: | N/A | {
"admin": "true"
} | 10 | | `Features` | map[string]*string* | :heavy_minus_sign: | N/A | | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2createtransactionresponse.md: -------------------------------------------------------------------------------- 1 | # V2CreateTransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | 8 | | `Data` | [components.V2Transaction](../../models/components/v2transaction.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2getledgerresponse.md: -------------------------------------------------------------------------------- 1 | # V2GetLedgerResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | 8 | | `Data` | [components.V2Ledger](../../models/components/v2ledger.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2gettransactionresponse.md: -------------------------------------------------------------------------------- 1 | # V2GetTransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | 8 | | `Data` | [components.V2Transaction](../../models/components/v2transaction.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2ledgerinforesponse.md: -------------------------------------------------------------------------------- 1 | # V2LedgerInfoResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | 8 | | `Data` | [*components.V2LedgerInfo](../../models/components/v2ledgerinfo.md) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2ledgerinfostorage.md: -------------------------------------------------------------------------------- 1 | # V2LedgerInfoStorage 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- | 8 | | `Migrations` | [][components.V2MigrationInfo](../../models/components/v2migrationinfo.md) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2logtype.md: -------------------------------------------------------------------------------- 1 | # V2LogType 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ------------------------------ | ------------------------------ | 8 | | `V2LogTypeNewTransaction` | NEW_TRANSACTION | 9 | | `V2LogTypeSetMetadata` | SET_METADATA | 10 | | `V2LogTypeRevertedTransaction` | REVERTED_TRANSACTION | 11 | | `V2LogTypeDeleteMetadata` | DELETE_METADATA | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2migrationinfostate.md: -------------------------------------------------------------------------------- 1 | # V2MigrationInfoState 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ------------------------------ | ------------------------------ | 8 | | `V2MigrationInfoStateToDo` | TO DO | 9 | | `V2MigrationInfoStateDone` | DONE | 10 | | `V2MigrationInfoStateProgress` | PROGRESS | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2reverttransactionresponse.md: -------------------------------------------------------------------------------- 1 | # V2RevertTransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | 8 | | `Data` | [components.V2Transaction](../../models/components/v2transaction.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2stats.md: -------------------------------------------------------------------------------- 1 | # V2Stats 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | 8 | | `Accounts` | *int64* | :heavy_check_mark: | N/A | 9 | | `Transactions` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2statsresponse.md: -------------------------------------------------------------------------------- 1 | # V2StatsResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | -------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------- | 8 | | `Data` | [components.V2Stats](../../models/components/v2stats.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2targetid.md: -------------------------------------------------------------------------------- 1 | # V2TargetID 2 | 3 | 4 | ## Supported Types 5 | 6 | ### 7 | 8 | ```go 9 | v2TargetID := components.CreateV2TargetIDStr(string{/* values here */}) 10 | ``` 11 | 12 | ### 13 | 14 | ```go 15 | v2TargetID := components.CreateV2TargetIDBigint(*big.Int{/* values here */}) 16 | ``` 17 | 18 | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2targettype.md: -------------------------------------------------------------------------------- 1 | # V2TargetType 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ------------------------- | ------------------------- | 8 | | `V2TargetTypeTransaction` | TRANSACTION | 9 | | `V2TargetTypeAccount` | ACCOUNT | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/v2volume.md: -------------------------------------------------------------------------------- 1 | # V2Volume 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | 8 | | `Input` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | 9 | | `Output` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | 10 | | `Balance` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/components/volume.md: -------------------------------------------------------------------------------- 1 | # Volume 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | 8 | | `Input` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | 9 | | `Output` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | N/A | 10 | | `Balance` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_minus_sign: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/addmetadataontransactionresponse.md: -------------------------------------------------------------------------------- 1 | # AddMetadataOnTransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/addmetadatatoaccountresponse.md: -------------------------------------------------------------------------------- 1 | # AddMetadataToAccountResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/getledgerinforequest.md: -------------------------------------------------------------------------------- 1 | # GetLedgerInfoRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/getmappingrequest.md: -------------------------------------------------------------------------------- 1 | # GetMappingRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/gettransactionrequest.md: -------------------------------------------------------------------------------- 1 | # GetTransactionRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | 9 | | `Txid` | [*big.Int](https://pkg.go.dev/math/big#Int) | :heavy_check_mark: | Transaction ID. | 1234 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/metadata.md: -------------------------------------------------------------------------------- 1 | # Metadata 2 | 3 | Filter transactions by metadata key value pairs. Nested objects can be used as seen in the example below. 4 | 5 | 6 | ## Fields 7 | 8 | | Field | Type | Required | Description | 9 | | ----------- | ----------- | ----------- | ----------- | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/option.md: -------------------------------------------------------------------------------- 1 | ## Options 2 | 3 | ### WithServerURL 4 | 5 | WithServerURL allows providing an alternative server URL. 6 | 7 | ```go 8 | operations.WithServerURL("http://api.example.com") 9 | ``` 10 | 11 | ## WithTemplatedServerURL 12 | 13 | WithTemplatedServerURL allows providing an alternative server URL with templated parameters. 14 | 15 | ```go 16 | operations.WithTemplatedServerURL("http://{host}:{port}", map[string]string{ 17 | "host": "api.example.com", 18 | "port": "8080", 19 | }) 20 | ``` 21 | 22 | ### WithRetries 23 | 24 | WithRetries allows customizing the default retry configuration. Only usable with methods that mention they support retries. 25 | 26 | ```go 27 | operations.WithRetries(retry.Config{ 28 | Strategy: "backoff", 29 | Backoff: retry.BackoffStrategy{ 30 | InitialInterval: 500 * time.Millisecond, 31 | MaxInterval: 60 * time.Second, 32 | Exponent: 1.5, 33 | MaxElapsedTime: 5 * time.Minute, 34 | }, 35 | RetryConnectionErrors: true, 36 | }) 37 | ``` -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/order.md: -------------------------------------------------------------------------------- 1 | # Order 2 | 3 | 4 | ## Values 5 | 6 | | Name | Value | 7 | | ---------------- | ---------------- | 8 | | `OrderEffective` | effective | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/readstatsrequest.md: -------------------------------------------------------------------------------- 1 | # ReadStatsRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `Ledger` | *string* | :heavy_check_mark: | name of the ledger | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2addmetadataontransactionresponse.md: -------------------------------------------------------------------------------- 1 | # V2AddMetadataOnTransactionResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2addmetadatatoaccountresponse.md: -------------------------------------------------------------------------------- 1 | # V2AddMetadataToAccountResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2createledgerresponse.md: -------------------------------------------------------------------------------- 1 | # V2CreateLedgerResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2deleteaccountmetadatarequest.md: -------------------------------------------------------------------------------- 1 | # V2DeleteAccountMetadataRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ---------------------- | ---------------------- | ---------------------- | ---------------------- | ---------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | 9 | | `Address` | *string* | :heavy_check_mark: | Account address | | 10 | | `Key` | *string* | :heavy_check_mark: | The key to remove. | foo | 11 | | `IdempotencyKey` | **string* | :heavy_minus_sign: | Use an idempotency key | | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2deleteaccountmetadataresponse.md: -------------------------------------------------------------------------------- 1 | # V2DeleteAccountMetadataResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2deleteledgermetadatarequest.md: -------------------------------------------------------------------------------- 1 | # V2DeleteLedgerMetadataRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | 9 | | `Key` | *string* | :heavy_check_mark: | Key to remove. | foo | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2deleteledgermetadataresponse.md: -------------------------------------------------------------------------------- 1 | # V2DeleteLedgerMetadataResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2deletetransactionmetadataresponse.md: -------------------------------------------------------------------------------- 1 | # V2DeleteTransactionMetadataResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2exportlogsrequest.md: -------------------------------------------------------------------------------- 1 | # V2ExportLogsRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2exportlogsresponse.md: -------------------------------------------------------------------------------- 1 | # V2ExportLogsResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2getledgerinforequest.md: -------------------------------------------------------------------------------- 1 | # V2GetLedgerInfoRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2getledgerrequest.md: -------------------------------------------------------------------------------- 1 | # V2GetLedgerRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2importlogsrequest.md: -------------------------------------------------------------------------------- 1 | # V2ImportLogsRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | --------------------- | --------------------- | --------------------- | --------------------- | --------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | 9 | | `V2ImportLogsRequest` | *any* | :heavy_check_mark: | N/A | | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2importlogsresponse.md: -------------------------------------------------------------------------------- 1 | # V2ImportLogsResponse 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | 7 | | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | 8 | | `HTTPMeta` | [components.HTTPMetadata](../../models/components/httpmetadata.md) | :heavy_check_mark: | N/A | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2readstatsrequest.md: -------------------------------------------------------------------------------- 1 | # V2ReadStatsRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------ | ------------------ | ------------------ | ------------------ | ------------------ | 8 | | `Ledger` | *string* | :heavy_check_mark: | name of the ledger | ledger001 | -------------------------------------------------------------------------------- /pkg/client/docs/models/operations/v2updateledgermetadatarequest.md: -------------------------------------------------------------------------------- 1 | # V2UpdateLedgerMetadataRequest 2 | 3 | 4 | ## Fields 5 | 6 | | Field | Type | Required | Description | Example | 7 | | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | 8 | | `Ledger` | *string* | :heavy_check_mark: | Name of the ledger. | ledger001 | 9 | | `RequestBody` | map[string]*string* | :heavy_check_mark: | N/A | {
"admin": "true"
} | -------------------------------------------------------------------------------- /pkg/client/docs/sdks/formance/README.md: -------------------------------------------------------------------------------- 1 | # Formance SDK 2 | 3 | ## Overview 4 | 5 | ### Available Operations 6 | -------------------------------------------------------------------------------- /pkg/client/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/formancehq/ledger/pkg/client 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 7 | golang.org/x/sync v0.8.0 8 | ) 9 | -------------------------------------------------------------------------------- /pkg/client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw= 2 | github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= 3 | golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= 4 | golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 5 | -------------------------------------------------------------------------------- /pkg/client/internal/hooks/registration.go: -------------------------------------------------------------------------------- 1 | package hooks 2 | 3 | /* 4 | * This file is only ever generated once on the first generation and then is free to be modified. 5 | * Any hooks you wish to add should be registered in the initHooks function. Feel free to define 6 | * your hooks in this file or in separate files in the hooks package. 7 | * 8 | * Hooks are registered per SDK instance, and are valid for the lifetime of the SDK instance. 9 | */ 10 | 11 | func initHooks(h *Hooks) { 12 | // exampleHook := &ExampleHook{} 13 | 14 | // h.registerSDKInitHook(exampleHook) 15 | // h.registerBeforeRequestHook(exampleHook) 16 | // h.registerAfterErrorHook(exampleHook) 17 | // h.registerAfterSuccessHook(exampleHook) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/client/internal/utils/contenttype.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package utils 4 | 5 | import ( 6 | "fmt" 7 | "mime" 8 | "strings" 9 | ) 10 | 11 | func MatchContentType(contentType string, pattern string) bool { 12 | if contentType == "" { 13 | contentType = "application/octet-stream" 14 | } 15 | 16 | if contentType == pattern || pattern == "*" || pattern == "*/*" { 17 | return true 18 | } 19 | 20 | mediaType, _, err := mime.ParseMediaType(contentType) 21 | if err != nil { 22 | return false 23 | } 24 | 25 | if mediaType == pattern { 26 | return true 27 | } 28 | 29 | parts := strings.Split(mediaType, "/") 30 | if len(parts) == 2 { 31 | if fmt.Sprintf("%s/*", parts[0]) == pattern || fmt.Sprintf("*/%s", parts[1]) == pattern { 32 | return true 33 | } 34 | } 35 | 36 | return false 37 | } 38 | -------------------------------------------------------------------------------- /pkg/client/internal/utils/env.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package utils 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | // GetEnv returns the value of the environment variable named by the key or the defaultValue if the environment variable is not set. 10 | func GetEnv(name, defaultValue string) string { 11 | value := os.Getenv(name) 12 | if value == "" { 13 | return defaultValue 14 | } 15 | return value 16 | } 17 | -------------------------------------------------------------------------------- /pkg/client/models/components/account.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Account struct { 6 | Address string `json:"address"` 7 | Type *string `json:"type,omitempty"` 8 | Metadata map[string]any `json:"metadata,omitempty"` 9 | } 10 | 11 | func (o *Account) GetAddress() string { 12 | if o == nil { 13 | return "" 14 | } 15 | return o.Address 16 | } 17 | 18 | func (o *Account) GetType() *string { 19 | if o == nil { 20 | return nil 21 | } 22 | return o.Type 23 | } 24 | 25 | func (o *Account) GetMetadata() map[string]any { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.Metadata 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/accountresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type AccountResponse struct { 6 | Data AccountWithVolumesAndBalances `json:"data"` 7 | } 8 | 9 | func (o *AccountResponse) GetData() AccountWithVolumesAndBalances { 10 | if o == nil { 11 | return AccountWithVolumesAndBalances{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/aggregatebalancesresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type AggregateBalancesResponse struct { 6 | Data map[string]int64 `json:"data"` 7 | } 8 | 9 | func (o *AggregateBalancesResponse) GetData() map[string]int64 { 10 | if o == nil { 11 | return map[string]int64{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/config.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Config struct { 6 | Storage LedgerStorage `json:"storage"` 7 | } 8 | 9 | func (o *Config) GetStorage() LedgerStorage { 10 | if o == nil { 11 | return LedgerStorage{} 12 | } 13 | return o.Storage 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/configinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type ConfigInfo struct { 6 | Config Config `json:"config"` 7 | Server string `json:"server"` 8 | Version string `json:"version"` 9 | } 10 | 11 | func (o *ConfigInfo) GetConfig() Config { 12 | if o == nil { 13 | return Config{} 14 | } 15 | return o.Config 16 | } 17 | 18 | func (o *ConfigInfo) GetServer() string { 19 | if o == nil { 20 | return "" 21 | } 22 | return o.Server 23 | } 24 | 25 | func (o *ConfigInfo) GetVersion() string { 26 | if o == nil { 27 | return "" 28 | } 29 | return o.Version 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/configinforesponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type ConfigInfoResponse struct { 6 | Data ConfigInfo `json:"data"` 7 | } 8 | 9 | func (o *ConfigInfoResponse) GetData() ConfigInfo { 10 | if o == nil { 11 | return ConfigInfo{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/contract.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Expr struct { 6 | } 7 | 8 | type Contract struct { 9 | Account *string `json:"account,omitempty"` 10 | Expr Expr `json:"expr"` 11 | } 12 | 13 | func (o *Contract) GetAccount() *string { 14 | if o == nil { 15 | return nil 16 | } 17 | return o.Account 18 | } 19 | 20 | func (o *Contract) GetExpr() Expr { 21 | if o == nil { 22 | return Expr{} 23 | } 24 | return o.Expr 25 | } 26 | -------------------------------------------------------------------------------- /pkg/client/models/components/errorresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type ErrorResponse struct { 6 | ErrorCode ErrorsEnum `json:"errorCode"` 7 | ErrorMessage string `json:"errorMessage"` 8 | Details *string `json:"details,omitempty"` 9 | } 10 | 11 | func (o *ErrorResponse) GetErrorCode() ErrorsEnum { 12 | if o == nil { 13 | return ErrorsEnum("") 14 | } 15 | return o.ErrorCode 16 | } 17 | 18 | func (o *ErrorResponse) GetErrorMessage() string { 19 | if o == nil { 20 | return "" 21 | } 22 | return o.ErrorMessage 23 | } 24 | 25 | func (o *ErrorResponse) GetDetails() *string { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.Details 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/httpmetadata.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | import ( 6 | "net/http" 7 | ) 8 | 9 | type HTTPMetadata struct { 10 | // Raw HTTP response; suitable for custom response parsing 11 | Response *http.Response `json:"-"` 12 | // Raw HTTP request; suitable for debugging 13 | Request *http.Request `json:"-"` 14 | } 15 | 16 | func (o *HTTPMetadata) GetResponse() *http.Response { 17 | if o == nil { 18 | return nil 19 | } 20 | return o.Response 21 | } 22 | 23 | func (o *HTTPMetadata) GetRequest() *http.Request { 24 | if o == nil { 25 | return nil 26 | } 27 | return o.Request 28 | } 29 | -------------------------------------------------------------------------------- /pkg/client/models/components/ledgerinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Storage struct { 6 | Migrations []MigrationInfo `json:"migrations,omitempty"` 7 | } 8 | 9 | func (o *Storage) GetMigrations() []MigrationInfo { 10 | if o == nil { 11 | return nil 12 | } 13 | return o.Migrations 14 | } 15 | 16 | type LedgerInfo struct { 17 | Name *string `json:"name,omitempty"` 18 | Storage *Storage `json:"storage,omitempty"` 19 | } 20 | 21 | func (o *LedgerInfo) GetName() *string { 22 | if o == nil { 23 | return nil 24 | } 25 | return o.Name 26 | } 27 | 28 | func (o *LedgerInfo) GetStorage() *Storage { 29 | if o == nil { 30 | return nil 31 | } 32 | return o.Storage 33 | } 34 | -------------------------------------------------------------------------------- /pkg/client/models/components/ledgerinforesponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type LedgerInfoResponse struct { 6 | Data *LedgerInfo `json:"data,omitempty"` 7 | } 8 | 9 | func (o *LedgerInfoResponse) GetData() *LedgerInfo { 10 | if o == nil { 11 | return nil 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/ledgerstorage.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type LedgerStorage struct { 6 | Driver string `json:"driver"` 7 | Ledgers []string `json:"ledgers"` 8 | } 9 | 10 | func (o *LedgerStorage) GetDriver() string { 11 | if o == nil { 12 | return "" 13 | } 14 | return o.Driver 15 | } 16 | 17 | func (o *LedgerStorage) GetLedgers() []string { 18 | if o == nil { 19 | return []string{} 20 | } 21 | return o.Ledgers 22 | } 23 | -------------------------------------------------------------------------------- /pkg/client/models/components/mapping.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Mapping struct { 6 | Contracts []Contract `json:"contracts"` 7 | } 8 | 9 | func (o *Mapping) GetContracts() []Contract { 10 | if o == nil { 11 | return []Contract{} 12 | } 13 | return o.Contracts 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/mappingresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type MappingResponse struct { 6 | Data *Mapping `json:"data,omitempty"` 7 | } 8 | 9 | func (o *MappingResponse) GetData() *Mapping { 10 | if o == nil { 11 | return nil 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/script.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Script struct { 6 | Plain string `json:"plain"` 7 | Vars map[string]any `json:"vars,omitempty"` 8 | // Reference to attach to the generated transaction 9 | Reference *string `json:"reference,omitempty"` 10 | Metadata map[string]any `json:"metadata,omitempty"` 11 | } 12 | 13 | func (o *Script) GetPlain() string { 14 | if o == nil { 15 | return "" 16 | } 17 | return o.Plain 18 | } 19 | 20 | func (o *Script) GetVars() map[string]any { 21 | if o == nil { 22 | return nil 23 | } 24 | return o.Vars 25 | } 26 | 27 | func (o *Script) GetReference() *string { 28 | if o == nil { 29 | return nil 30 | } 31 | return o.Reference 32 | } 33 | 34 | func (o *Script) GetMetadata() map[string]any { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.Metadata 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/components/scriptresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type ScriptResponse struct { 6 | ErrorCode *ErrorsEnum `json:"errorCode,omitempty"` 7 | ErrorMessage *string `json:"errorMessage,omitempty"` 8 | Details *string `json:"details,omitempty"` 9 | Transaction *Transaction `json:"transaction,omitempty"` 10 | } 11 | 12 | func (o *ScriptResponse) GetErrorCode() *ErrorsEnum { 13 | if o == nil { 14 | return nil 15 | } 16 | return o.ErrorCode 17 | } 18 | 19 | func (o *ScriptResponse) GetErrorMessage() *string { 20 | if o == nil { 21 | return nil 22 | } 23 | return o.ErrorMessage 24 | } 25 | 26 | func (o *ScriptResponse) GetDetails() *string { 27 | if o == nil { 28 | return nil 29 | } 30 | return o.Details 31 | } 32 | 33 | func (o *ScriptResponse) GetTransaction() *Transaction { 34 | if o == nil { 35 | return nil 36 | } 37 | return o.Transaction 38 | } 39 | -------------------------------------------------------------------------------- /pkg/client/models/components/stats.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Stats struct { 6 | Accounts int64 `json:"accounts"` 7 | Transactions int64 `json:"transactions"` 8 | } 9 | 10 | func (o *Stats) GetAccounts() int64 { 11 | if o == nil { 12 | return 0 13 | } 14 | return o.Accounts 15 | } 16 | 17 | func (o *Stats) GetTransactions() int64 { 18 | if o == nil { 19 | return 0 20 | } 21 | return o.Transactions 22 | } 23 | -------------------------------------------------------------------------------- /pkg/client/models/components/statsresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type StatsResponse struct { 6 | Data Stats `json:"data"` 7 | } 8 | 9 | func (o *StatsResponse) GetData() Stats { 10 | if o == nil { 11 | return Stats{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/transactionresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type TransactionResponse struct { 6 | Data Transaction `json:"data"` 7 | } 8 | 9 | func (o *TransactionResponse) GetData() Transaction { 10 | if o == nil { 11 | return Transaction{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/transactions.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type Transactions struct { 6 | Transactions []TransactionData `json:"transactions"` 7 | } 8 | 9 | func (o *Transactions) GetTransactions() []TransactionData { 10 | if o == nil { 11 | return []TransactionData{} 12 | } 13 | return o.Transactions 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/transactionsresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type TransactionsResponse struct { 6 | Data []Transaction `json:"data"` 7 | } 8 | 9 | func (o *TransactionsResponse) GetData() []Transaction { 10 | if o == nil { 11 | return []Transaction{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2account.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2Account struct { 6 | Address string `json:"address"` 7 | Metadata map[string]string `json:"metadata"` 8 | Volumes map[string]V2Volume `json:"volumes,omitempty"` 9 | EffectiveVolumes map[string]V2Volume `json:"effectiveVolumes,omitempty"` 10 | } 11 | 12 | func (o *V2Account) GetAddress() string { 13 | if o == nil { 14 | return "" 15 | } 16 | return o.Address 17 | } 18 | 19 | func (o *V2Account) GetMetadata() map[string]string { 20 | if o == nil { 21 | return map[string]string{} 22 | } 23 | return o.Metadata 24 | } 25 | 26 | func (o *V2Account) GetVolumes() map[string]V2Volume { 27 | if o == nil { 28 | return nil 29 | } 30 | return o.Volumes 31 | } 32 | 33 | func (o *V2Account) GetEffectiveVolumes() map[string]V2Volume { 34 | if o == nil { 35 | return nil 36 | } 37 | return o.EffectiveVolumes 38 | } 39 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2accountresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2AccountResponse struct { 6 | Data V2Account `json:"data"` 7 | } 8 | 9 | func (o *V2AccountResponse) GetData() V2Account { 10 | if o == nil { 11 | return V2Account{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2aggregatebalancesresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/internal/utils" 7 | "math/big" 8 | ) 9 | 10 | type V2AggregateBalancesResponse struct { 11 | Data map[string]*big.Int `json:"data"` 12 | } 13 | 14 | func (v V2AggregateBalancesResponse) MarshalJSON() ([]byte, error) { 15 | return utils.MarshalJSON(v, "", false) 16 | } 17 | 18 | func (v *V2AggregateBalancesResponse) UnmarshalJSON(data []byte) error { 19 | if err := utils.UnmarshalJSON(data, &v, "", false, false); err != nil { 20 | return err 21 | } 22 | return nil 23 | } 24 | 25 | func (o *V2AggregateBalancesResponse) GetData() map[string]*big.Int { 26 | if o == nil { 27 | return map[string]*big.Int{} 28 | } 29 | return o.Data 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2bulkelementcreatetransaction.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2BulkElementCreateTransaction struct { 6 | Action string `json:"action"` 7 | Ik *string `json:"ik,omitempty"` 8 | Data *V2PostTransaction `json:"data,omitempty"` 9 | } 10 | 11 | func (o *V2BulkElementCreateTransaction) GetAction() string { 12 | if o == nil { 13 | return "" 14 | } 15 | return o.Action 16 | } 17 | 18 | func (o *V2BulkElementCreateTransaction) GetIk() *string { 19 | if o == nil { 20 | return nil 21 | } 22 | return o.Ik 23 | } 24 | 25 | func (o *V2BulkElementCreateTransaction) GetData() *V2PostTransaction { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.Data 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2bulkresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2BulkResponse struct { 6 | Data []V2BulkElementResult `json:"data,omitempty"` 7 | ErrorCode *V2ErrorsEnum `json:"errorCode,omitempty"` 8 | ErrorMessage *string `json:"errorMessage,omitempty"` 9 | } 10 | 11 | func (o *V2BulkResponse) GetData() []V2BulkElementResult { 12 | if o == nil { 13 | return nil 14 | } 15 | return o.Data 16 | } 17 | 18 | func (o *V2BulkResponse) GetErrorCode() *V2ErrorsEnum { 19 | if o == nil { 20 | return nil 21 | } 22 | return o.ErrorCode 23 | } 24 | 25 | func (o *V2BulkResponse) GetErrorMessage() *string { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.ErrorMessage 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2configinforesponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2ConfigInfoResponse struct { 6 | Server string `json:"server"` 7 | Version string `json:"version"` 8 | } 9 | 10 | func (o *V2ConfigInfoResponse) GetServer() string { 11 | if o == nil { 12 | return "" 13 | } 14 | return o.Server 15 | } 16 | 17 | func (o *V2ConfigInfoResponse) GetVersion() string { 18 | if o == nil { 19 | return "" 20 | } 21 | return o.Version 22 | } 23 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2createledgerrequest.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2CreateLedgerRequest struct { 6 | Bucket *string `json:"bucket,omitempty"` 7 | Metadata map[string]string `json:"metadata,omitempty"` 8 | Features map[string]string `json:"features,omitempty"` 9 | } 10 | 11 | func (o *V2CreateLedgerRequest) GetBucket() *string { 12 | if o == nil { 13 | return nil 14 | } 15 | return o.Bucket 16 | } 17 | 18 | func (o *V2CreateLedgerRequest) GetMetadata() map[string]string { 19 | if o == nil { 20 | return nil 21 | } 22 | return o.Metadata 23 | } 24 | 25 | func (o *V2CreateLedgerRequest) GetFeatures() map[string]string { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.Features 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2createtransactionresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2CreateTransactionResponse struct { 6 | Data V2Transaction `json:"data"` 7 | } 8 | 9 | func (o *V2CreateTransactionResponse) GetData() V2Transaction { 10 | if o == nil { 11 | return V2Transaction{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2errorresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2ErrorResponse struct { 6 | ErrorCode V2ErrorsEnum `json:"errorCode"` 7 | ErrorMessage string `json:"errorMessage"` 8 | Details *string `json:"details,omitempty"` 9 | } 10 | 11 | func (o *V2ErrorResponse) GetErrorCode() V2ErrorsEnum { 12 | if o == nil { 13 | return V2ErrorsEnum("") 14 | } 15 | return o.ErrorCode 16 | } 17 | 18 | func (o *V2ErrorResponse) GetErrorMessage() string { 19 | if o == nil { 20 | return "" 21 | } 22 | return o.ErrorMessage 23 | } 24 | 25 | func (o *V2ErrorResponse) GetDetails() *string { 26 | if o == nil { 27 | return nil 28 | } 29 | return o.Details 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2getledgerresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2GetLedgerResponse struct { 6 | Data V2Ledger `json:"data"` 7 | } 8 | 9 | func (o *V2GetLedgerResponse) GetData() V2Ledger { 10 | if o == nil { 11 | return V2Ledger{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2gettransactionresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2GetTransactionResponse struct { 6 | Data V2Transaction `json:"data"` 7 | } 8 | 9 | func (o *V2GetTransactionResponse) GetData() V2Transaction { 10 | if o == nil { 11 | return V2Transaction{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2ledgerinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2LedgerInfoStorage struct { 6 | Migrations []V2MigrationInfo `json:"migrations,omitempty"` 7 | } 8 | 9 | func (o *V2LedgerInfoStorage) GetMigrations() []V2MigrationInfo { 10 | if o == nil { 11 | return nil 12 | } 13 | return o.Migrations 14 | } 15 | 16 | type V2LedgerInfo struct { 17 | Name *string `json:"name,omitempty"` 18 | Storage *V2LedgerInfoStorage `json:"storage,omitempty"` 19 | } 20 | 21 | func (o *V2LedgerInfo) GetName() *string { 22 | if o == nil { 23 | return nil 24 | } 25 | return o.Name 26 | } 27 | 28 | func (o *V2LedgerInfo) GetStorage() *V2LedgerInfoStorage { 29 | if o == nil { 30 | return nil 31 | } 32 | return o.Storage 33 | } 34 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2ledgerinforesponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2LedgerInfoResponse struct { 6 | Data *V2LedgerInfo `json:"data,omitempty"` 7 | } 8 | 9 | func (o *V2LedgerInfoResponse) GetData() *V2LedgerInfo { 10 | if o == nil { 11 | return nil 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2reverttransactionresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2RevertTransactionResponse struct { 6 | Data V2Transaction `json:"data"` 7 | } 8 | 9 | func (o *V2RevertTransactionResponse) GetData() V2Transaction { 10 | if o == nil { 11 | return V2Transaction{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2stats.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/internal/utils" 7 | "math/big" 8 | ) 9 | 10 | type V2Stats struct { 11 | Accounts int64 `json:"accounts"` 12 | Transactions *big.Int `json:"transactions"` 13 | } 14 | 15 | func (v V2Stats) MarshalJSON() ([]byte, error) { 16 | return utils.MarshalJSON(v, "", false) 17 | } 18 | 19 | func (v *V2Stats) UnmarshalJSON(data []byte) error { 20 | if err := utils.UnmarshalJSON(data, &v, "", false, false); err != nil { 21 | return err 22 | } 23 | return nil 24 | } 25 | 26 | func (o *V2Stats) GetAccounts() int64 { 27 | if o == nil { 28 | return 0 29 | } 30 | return o.Accounts 31 | } 32 | 33 | func (o *V2Stats) GetTransactions() *big.Int { 34 | if o == nil { 35 | return big.NewInt(0) 36 | } 37 | return o.Transactions 38 | } 39 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2statsresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | type V2StatsResponse struct { 6 | Data V2Stats `json:"data"` 7 | } 8 | 9 | func (o *V2StatsResponse) GetData() V2Stats { 10 | if o == nil { 11 | return V2Stats{} 12 | } 13 | return o.Data 14 | } 15 | -------------------------------------------------------------------------------- /pkg/client/models/components/v2targettype.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package components 4 | 5 | import ( 6 | "encoding/json" 7 | "fmt" 8 | ) 9 | 10 | type V2TargetType string 11 | 12 | const ( 13 | V2TargetTypeTransaction V2TargetType = "TRANSACTION" 14 | V2TargetTypeAccount V2TargetType = "ACCOUNT" 15 | ) 16 | 17 | func (e V2TargetType) ToPointer() *V2TargetType { 18 | return &e 19 | } 20 | func (e *V2TargetType) UnmarshalJSON(data []byte) error { 21 | var v string 22 | if err := json.Unmarshal(data, &v); err != nil { 23 | return err 24 | } 25 | switch v { 26 | case "TRANSACTION": 27 | fallthrough 28 | case "ACCOUNT": 29 | *e = V2TargetType(v) 30 | return nil 31 | default: 32 | return fmt.Errorf("invalid value for V2TargetType: %v", v) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pkg/client/models/operations/getinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type GetInfoResponse struct { 10 | HTTPMeta components.HTTPMetadata `json:"-"` 11 | // OK 12 | ConfigInfoResponse *components.ConfigInfoResponse 13 | } 14 | 15 | func (o *GetInfoResponse) GetHTTPMeta() components.HTTPMetadata { 16 | if o == nil { 17 | return components.HTTPMetadata{} 18 | } 19 | return o.HTTPMeta 20 | } 21 | 22 | func (o *GetInfoResponse) GetConfigInfoResponse() *components.ConfigInfoResponse { 23 | if o == nil { 24 | return nil 25 | } 26 | return o.ConfigInfoResponse 27 | } 28 | -------------------------------------------------------------------------------- /pkg/client/models/operations/getledgerinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type GetLedgerInfoRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *GetLedgerInfoRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type GetLedgerInfoResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | LedgerInfoResponse *components.LedgerInfoResponse 25 | } 26 | 27 | func (o *GetLedgerInfoResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *GetLedgerInfoResponse) GetLedgerInfoResponse() *components.LedgerInfoResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.LedgerInfoResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/getmapping.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type GetMappingRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *GetMappingRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type GetMappingResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | MappingResponse *components.MappingResponse 25 | } 26 | 27 | func (o *GetMappingResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *GetMappingResponse) GetMappingResponse() *components.MappingResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.MappingResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/getmetrics.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type GetMetricsResponse struct { 10 | HTTPMeta components.HTTPMetadata `json:"-"` 11 | // OK 12 | Object map[string]any 13 | } 14 | 15 | func (o *GetMetricsResponse) GetHTTPMeta() components.HTTPMetadata { 16 | if o == nil { 17 | return components.HTTPMetadata{} 18 | } 19 | return o.HTTPMeta 20 | } 21 | 22 | func (o *GetMetricsResponse) GetObject() map[string]any { 23 | if o == nil { 24 | return nil 25 | } 26 | return o.Object 27 | } 28 | -------------------------------------------------------------------------------- /pkg/client/models/operations/readstats.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type ReadStatsRequest struct { 10 | // name of the ledger 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *ReadStatsRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type ReadStatsResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | StatsResponse *components.StatsResponse 25 | } 26 | 27 | func (o *ReadStatsResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *ReadStatsResponse) GetStatsResponse() *components.StatsResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.StatsResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2deleteledgermetadata.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2DeleteLedgerMetadataRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | // Key to remove. 13 | Key string `pathParam:"style=simple,explode=false,name=key"` 14 | } 15 | 16 | func (o *V2DeleteLedgerMetadataRequest) GetLedger() string { 17 | if o == nil { 18 | return "" 19 | } 20 | return o.Ledger 21 | } 22 | 23 | func (o *V2DeleteLedgerMetadataRequest) GetKey() string { 24 | if o == nil { 25 | return "" 26 | } 27 | return o.Key 28 | } 29 | 30 | type V2DeleteLedgerMetadataResponse struct { 31 | HTTPMeta components.HTTPMetadata `json:"-"` 32 | } 33 | 34 | func (o *V2DeleteLedgerMetadataResponse) GetHTTPMeta() components.HTTPMetadata { 35 | if o == nil { 36 | return components.HTTPMetadata{} 37 | } 38 | return o.HTTPMeta 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2exportlogs.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2ExportLogsRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *V2ExportLogsRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type V2ExportLogsResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | } 24 | 25 | func (o *V2ExportLogsResponse) GetHTTPMeta() components.HTTPMetadata { 26 | if o == nil { 27 | return components.HTTPMetadata{} 28 | } 29 | return o.HTTPMeta 30 | } 31 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2getinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2GetInfoResponse struct { 10 | HTTPMeta components.HTTPMetadata `json:"-"` 11 | // OK 12 | V2ConfigInfoResponse *components.V2ConfigInfoResponse 13 | // Error 14 | V2ErrorResponse *components.V2ErrorResponse 15 | } 16 | 17 | func (o *V2GetInfoResponse) GetHTTPMeta() components.HTTPMetadata { 18 | if o == nil { 19 | return components.HTTPMetadata{} 20 | } 21 | return o.HTTPMeta 22 | } 23 | 24 | func (o *V2GetInfoResponse) GetV2ConfigInfoResponse() *components.V2ConfigInfoResponse { 25 | if o == nil { 26 | return nil 27 | } 28 | return o.V2ConfigInfoResponse 29 | } 30 | 31 | func (o *V2GetInfoResponse) GetV2ErrorResponse() *components.V2ErrorResponse { 32 | if o == nil { 33 | return nil 34 | } 35 | return o.V2ErrorResponse 36 | } 37 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2getledger.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2GetLedgerRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *V2GetLedgerRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type V2GetLedgerResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | V2GetLedgerResponse *components.V2GetLedgerResponse 25 | } 26 | 27 | func (o *V2GetLedgerResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *V2GetLedgerResponse) GetV2GetLedgerResponse() *components.V2GetLedgerResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.V2GetLedgerResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2getledgerinfo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2GetLedgerInfoRequest struct { 10 | // Name of the ledger. 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *V2GetLedgerInfoRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type V2GetLedgerInfoResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | V2LedgerInfoResponse *components.V2LedgerInfoResponse 25 | } 26 | 27 | func (o *V2GetLedgerInfoResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *V2GetLedgerInfoResponse) GetV2LedgerInfoResponse() *components.V2LedgerInfoResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.V2LedgerInfoResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/operations/v2readstats.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package operations 4 | 5 | import ( 6 | "github.com/formancehq/ledger/pkg/client/models/components" 7 | ) 8 | 9 | type V2ReadStatsRequest struct { 10 | // name of the ledger 11 | Ledger string `pathParam:"style=simple,explode=false,name=ledger"` 12 | } 13 | 14 | func (o *V2ReadStatsRequest) GetLedger() string { 15 | if o == nil { 16 | return "" 17 | } 18 | return o.Ledger 19 | } 20 | 21 | type V2ReadStatsResponse struct { 22 | HTTPMeta components.HTTPMetadata `json:"-"` 23 | // OK 24 | V2StatsResponse *components.V2StatsResponse 25 | } 26 | 27 | func (o *V2ReadStatsResponse) GetHTTPMeta() components.HTTPMetadata { 28 | if o == nil { 29 | return components.HTTPMetadata{} 30 | } 31 | return o.HTTPMeta 32 | } 33 | 34 | func (o *V2ReadStatsResponse) GetV2StatsResponse() *components.V2StatsResponse { 35 | if o == nil { 36 | return nil 37 | } 38 | return o.V2StatsResponse 39 | } 40 | -------------------------------------------------------------------------------- /pkg/client/models/sdkerrors/errorresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package sdkerrors 4 | 5 | import ( 6 | "encoding/json" 7 | "github.com/formancehq/ledger/pkg/client/models/components" 8 | ) 9 | 10 | type ErrorResponse struct { 11 | ErrorCode components.ErrorsEnum `json:"errorCode"` 12 | ErrorMessage string `json:"errorMessage"` 13 | Details *string `json:"details,omitempty"` 14 | } 15 | 16 | var _ error = &ErrorResponse{} 17 | 18 | func (e *ErrorResponse) Error() string { 19 | data, _ := json.Marshal(e) 20 | return string(data) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/client/models/sdkerrors/sdkerror.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package sdkerrors 4 | 5 | import ( 6 | "fmt" 7 | "net/http" 8 | ) 9 | 10 | type SDKError struct { 11 | Message string 12 | StatusCode int 13 | Body string 14 | RawResponse *http.Response 15 | } 16 | 17 | var _ error = &SDKError{} 18 | 19 | func NewSDKError(message string, statusCode int, body string, httpRes *http.Response) *SDKError { 20 | return &SDKError{ 21 | Message: message, 22 | StatusCode: statusCode, 23 | Body: body, 24 | RawResponse: httpRes, 25 | } 26 | } 27 | 28 | func (e *SDKError) Error() string { 29 | body := "" 30 | if len(e.Body) > 0 { 31 | body = fmt.Sprintf("\n%s", e.Body) 32 | } 33 | 34 | return fmt.Sprintf("%s: Status %d%s", e.Message, e.StatusCode, body) 35 | } 36 | -------------------------------------------------------------------------------- /pkg/client/models/sdkerrors/v2errorresponse.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package sdkerrors 4 | 5 | import ( 6 | "encoding/json" 7 | "github.com/formancehq/ledger/pkg/client/models/components" 8 | ) 9 | 10 | type V2ErrorResponse struct { 11 | ErrorCode components.V2ErrorsEnum `json:"errorCode"` 12 | ErrorMessage string `json:"errorMessage"` 13 | Details *string `json:"details,omitempty"` 14 | } 15 | 16 | var _ error = &V2ErrorResponse{} 17 | 18 | func (e *V2ErrorResponse) Error() string { 19 | data, _ := json.Marshal(e) 20 | return string(data) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/client/types/bigint.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package types 4 | 5 | import ( 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // MustNewBigIntFromString returns an instance of big.Int from a string 11 | // The string is assumed to be base 10 and if it is not a valid big.Int 12 | // then the function panics. 13 | // Avoid using this function in production code. 14 | func MustNewBigIntFromString(s string) *big.Int { 15 | i, ok := new(big.Int).SetString(s, 10) 16 | if !ok { 17 | panic(fmt.Errorf("failed to parse string as big.Int")) 18 | } 19 | 20 | return i 21 | } 22 | -------------------------------------------------------------------------------- /pkg/client/types/datetime.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "time" 6 | 7 | // MustTimeFromString returns a time.Time from a string formatted as "2006-01-02T15:04:05Z07:00" or panics. 8 | // Avoid using this function in production code. 9 | func MustTimeFromString(str string) time.Time { 10 | t, err := time.Parse(time.RFC3339, str) 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | return t 16 | } 17 | 18 | // MustNewTimeFromString returns an instance of time.Time from a string formatted as "2006-01-02T15:04:05Z07:00" or panics. 19 | // Avoid using this function in production code. 20 | func MustNewTimeFromString(str string) *time.Time { 21 | t := MustTimeFromString(str) 22 | return &t 23 | } 24 | -------------------------------------------------------------------------------- /pkg/client/types/decimal.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package types 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/ericlagergren/decimal" 9 | ) 10 | 11 | // MustNewDecimalFromString returns an instance of Decimal from a string 12 | // Avoid using this function in production code. 13 | func MustNewDecimalFromString(s string) *decimal.Big { 14 | d, ok := new(decimal.Big).SetString(s) 15 | if !ok { 16 | panic(fmt.Errorf("failed to parse string as decimal.Big")) 17 | } 18 | 19 | return d 20 | } 21 | -------------------------------------------------------------------------------- /pkg/client/types/pointers.go: -------------------------------------------------------------------------------- 1 | // Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. 2 | 3 | package types 4 | 5 | func String(s string) *string { return &s } 6 | func Bool(b bool) *bool { return &b } 7 | func Int(i int) *int { return &i } 8 | func Int64(i int64) *int64 { return &i } 9 | func Float32(f float32) *float32 { return &f } 10 | func Float64(f float64) *float64 { return &f } 11 | func Pointer[T any](v T) *T { return &v } 12 | -------------------------------------------------------------------------------- /pkg/events/events.go: -------------------------------------------------------------------------------- 1 | package events 2 | 3 | const ( 4 | EventVersion = "v2" 5 | EventApp = "ledger" 6 | 7 | EventTypeCommittedTransactions = "COMMITTED_TRANSACTIONS" 8 | EventTypeSavedMetadata = "SAVED_METADATA" 9 | EventTypeRevertedTransaction = "REVERTED_TRANSACTION" 10 | EventTypeDeletedMetadata = "DELETED_METADATA" 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/testserver/client.go: -------------------------------------------------------------------------------- 1 | package testserver 2 | 3 | import ( 4 | "github.com/formancehq/go-libs/v3/testing/deferred" 5 | "github.com/formancehq/go-libs/v3/testing/testservice" 6 | ledgerclient "github.com/formancehq/ledger/pkg/client" 7 | ) 8 | 9 | func Client(srv *testservice.Service) *ledgerclient.Formance { 10 | return ledgerclient.New( 11 | ledgerclient.WithServerURL(testservice.GetServerURL(srv).String()), 12 | ) 13 | } 14 | 15 | func DeferClient(srv *deferred.Deferred[*testservice.Service]) *deferred.Deferred[*ledgerclient.Formance] { 16 | return deferred.Map(srv, Client) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/testserver/worker.go: -------------------------------------------------------------------------------- 1 | package testserver 2 | 3 | import ( 4 | "context" 5 | "github.com/formancehq/go-libs/v3/testing/testservice" 6 | "github.com/formancehq/ledger/cmd" 7 | "strconv" 8 | ) 9 | 10 | func LogsHashBlockMaxSizeInstrumentation(size int) testservice.InstrumentationFunc { 11 | return func(ctx context.Context, runConfiguration *testservice.RunConfiguration) error { 12 | runConfiguration.AppendArgs("--"+cmd.WorkerAsyncBlockHasherMaxBlockSizeFlag, strconv.Itoa(size)) 13 | return nil 14 | } 15 | } 16 | 17 | func LogsHashBlockCRONSpecInstrumentation(spec string) testservice.InstrumentationFunc { 18 | return func(ctx context.Context, runConfiguration *testservice.RunConfiguration) error { 19 | runConfiguration.AppendArgs("--"+cmd.WorkerAsyncBlockHasherScheduleFlag, spec) 20 | return nil 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scratch.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/formancehq/base:scratch 2 | COPY ledger /usr/bin/ledger 3 | ENV OTEL_SERVICE_NAME ledger 4 | ENTRYPOINT ["/usr/bin/ledger"] 5 | CMD ["serve"] 6 | -------------------------------------------------------------------------------- /test/migrations/README.md: -------------------------------------------------------------------------------- 1 | # Migrations test 2 | 3 | This package allow to test the migration of an existing database regarding current code. 4 | 5 | The test can be run using the following command : 6 | ```shell 7 | go test . \ 8 | -databases.source 9 | ``` 10 | 11 | The test will start a new postgres server, copy the database inside, then apply migrations. 12 | 13 | Additionally, you can add the flag : 14 | ```shell 15 | go test . \ 16 | -databases.source \ 17 | -databases.destination 18 | ``` 19 | 20 | In this case, the destination database will be used and no local postgres server will be started. 21 | -------------------------------------------------------------------------------- /test/performance/.gitignore: -------------------------------------------------------------------------------- 1 | report 2 | -------------------------------------------------------------------------------- /test/performance/justfile: -------------------------------------------------------------------------------- 1 | mod reads 'pkg/read/justfile' 2 | mod writes 'pkg/write/justfile' -------------------------------------------------------------------------------- /test/performance/pkg/env/env.go: -------------------------------------------------------------------------------- 1 | //go:build it 2 | 3 | package env 4 | 5 | import ( 6 | "context" 7 | ledgerclient "github.com/formancehq/ledger/pkg/client" 8 | "testing" 9 | ) 10 | 11 | type Env interface { 12 | Client() *ledgerclient.Formance 13 | Stop(ctx context.Context) error 14 | } 15 | 16 | type EnvFactory interface { 17 | Create(ctx context.Context, b *testing.B) Env 18 | } 19 | 20 | var FallbackEnvFactory EnvFactory = nil 21 | -------------------------------------------------------------------------------- /test/performance/pkg/read/examples/config.yml: -------------------------------------------------------------------------------- 1 | queries: 2 | - name: list accounts 3 | operation: list-accounts 4 | expand: 5 | - volumes 6 | - effectiveVolumes 7 | - name: list volumes fees for all organizations 8 | operation: list-volumes 9 | filter: 10 | $match: 11 | account: "organization::fees" 12 | - name: list volumes for psp 0 13 | operation: list-volumes 14 | filter: 15 | $match: 16 | account: "::psp:0" 17 | - name: list volumes for users 18 | operation: list-volumes 19 | filter: 20 | $match: 21 | account: "::users:" -------------------------------------------------------------------------------- /test/performance/pkg/read/justfile: -------------------------------------------------------------------------------- 1 | set dotenv-load 2 | set positional-arguments 3 | 4 | tmpdir := `mktemp -d` 5 | 6 | run ledger config ledgerURL bench='.' benchtime='1s' count='1': 7 | go test -run ^$ -tags it,local \ 8 | -timeout 600m \ 9 | -bench={{bench}} \ 10 | -count={{count}} \ 11 | -test.benchtime {{benchtime}} ./... \ 12 | -ledger {{ledger}} \ 13 | -ledger.url {{ledgerURL}} \ 14 | -config {{config}} -------------------------------------------------------------------------------- /test/performance/pkg/write/charts/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /test/performance/pkg/write/charts/index.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import 'chartjs-to-image'; 3 | import {exportDatabaseStats, exportLatencyGraph, exportTPSGraph} from "./src/graphs"; 4 | 5 | const main = async () => { 6 | let buffer = fs.readFileSync('../report/writes/report.json', 'utf-8'); 7 | let reports = JSON.parse(buffer); 8 | await exportTPSGraph({ 9 | output: '../report/writes/tps.png', 10 | }, reports); 11 | 12 | await exportDatabaseStats('../report/writes/database_connections.png', reports); 13 | 14 | const ps: (keyof MetricsTime)[] = ['P99', 'P95', 'P75', 'Avg'] 15 | for (let p of ps) { 16 | await exportLatencyGraph({ 17 | output: '../report/writes/' + p.toLowerCase() + '.png' 18 | }, p, reports); 19 | } 20 | } 21 | 22 | main(); 23 | 24 | -------------------------------------------------------------------------------- /test/performance/pkg/write/charts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "charts", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "npx tsc" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "dependencies": { 13 | "@types/node": "^22.7.4", 14 | "@types/promise-fs": "^2.1.5", 15 | "chart.js": "^4.4.4", 16 | "chart.js-image": "^6.1.3", 17 | "chartjs-plugin-annotation": "^3.0.1", 18 | "chartjs-to-image": "^1.2.2", 19 | "install": "^0.13.0", 20 | "npm": "^10.9.0" 21 | }, 22 | "devDependencies": { 23 | "typescript": "^5.6.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/performance/pkg/write/charts/src/colors.ts: -------------------------------------------------------------------------------- 1 | export const CHART_COLORS = { 2 | red: 'rgb(255, 99, 132)', 3 | orange: 'rgb(255, 159, 64)', 4 | yellow: 'rgb(255, 205, 86)', 5 | green: 'rgb(75, 192, 192)', 6 | blue: 'rgb(54, 162, 235)', 7 | purple: 'rgb(153, 102, 255)', 8 | grey: 'rgb(201, 203, 207)' 9 | }; 10 | 11 | export const NAMED_COLORS = [ 12 | CHART_COLORS.red, 13 | CHART_COLORS.orange, 14 | CHART_COLORS.yellow, 15 | CHART_COLORS.green, 16 | CHART_COLORS.blue, 17 | CHART_COLORS.purple, 18 | CHART_COLORS.grey, 19 | ]; -------------------------------------------------------------------------------- /test/performance/pkg/write/example_scripts/example1.js: -------------------------------------------------------------------------------- 1 | const plain = `vars { 2 | account $order 3 | account $seller 4 | } 5 | send [USD/2 100] ( 6 | source = @world 7 | destination = $order 8 | ) 9 | send [USD/2 1] ( 10 | source = $order 11 | destination = @fees 12 | ) 13 | send [USD/2 99] ( 14 | source = $order 15 | destination = $seller 16 | )` 17 | 18 | function next(iteration) { 19 | return [ 20 | { 21 | action: 'CREATE_TRANSACTION', 22 | data: { 23 | script: { 24 | plain, 25 | vars: { 26 | order: `orders:${uuid()}`, 27 | seller: `sellers:${iteration % 5}` 28 | } 29 | } 30 | } 31 | } 32 | ] 33 | } 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/performance/pkg/write/scripts/any_bounded_to_any.js: -------------------------------------------------------------------------------- 1 | function next() { 2 | return [ 3 | { 4 | action: 'CREATE_TRANSACTION', 5 | data: { 6 | script: { 7 | plain: `vars { 8 | account $source 9 | account $destination 10 | } 11 | send [USD/2 100] ( 12 | source = $source allowing overdraft up to [USD/2 100] 13 | destination = $destination 14 | )`, 15 | vars: { 16 | destination: "dst:" + uuid(), 17 | source: "src:" + uuid() 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /test/performance/pkg/write/scripts/any_to_bank.js: -------------------------------------------------------------------------------- 1 | function next() { 2 | return [ 3 | { 4 | action: 'CREATE_TRANSACTION', 5 | data: { 6 | script: { 7 | plain: `vars { 8 | account $source 9 | } 10 | send [USD/2 100] ( 11 | source = $source allowing unbounded overdraft 12 | destination = @bank 13 | )`, 14 | vars: { 15 | source: "src:" + uuid() 16 | } 17 | } 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /test/performance/pkg/write/scripts/any_unbounded_to_any.js: -------------------------------------------------------------------------------- 1 | function next() { 2 | return [ 3 | { 4 | action: 'CREATE_TRANSACTION', 5 | data: { 6 | script: { 7 | plain: `vars { 8 | account $source 9 | account $destination 10 | } 11 | send [USD/2 100] ( 12 | source = $source allowing unbounded overdraft 13 | destination = $destination 14 | )`, 15 | vars: { 16 | destination: "dst:" + uuid(), 17 | source: "src:" + uuid() 18 | } 19 | } 20 | } 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /test/performance/pkg/write/scripts/world_to_any.js: -------------------------------------------------------------------------------- 1 | function next() { 2 | return [ 3 | { 4 | action: 'CREATE_TRANSACTION', 5 | data: { 6 | script: { 7 | plain: `vars { 8 | account $destination 9 | } 10 | send [USD/2 100] ( 11 | source = @world 12 | destination = $destination 13 | )`, 14 | vars: { 15 | destination: "dst:" + uuid() 16 | } 17 | } 18 | } 19 | } 20 | ] 21 | } 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/performance/pkg/write/scripts/world_to_bank.js: -------------------------------------------------------------------------------- 1 | function next() { 2 | return [ 3 | { 4 | action: 'CREATE_TRANSACTION', 5 | data: { 6 | script: { 7 | plain: `send [USD/2 100] ( 8 | source = @world 9 | destination = @bank 10 | )`, 11 | vars: {} 12 | } 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /tools/generator/Earthfile: -------------------------------------------------------------------------------- 1 | VERSION 0.8 2 | PROJECT FormanceHQ/ledger 3 | 4 | IMPORT github.com/formancehq/earthly:tags/v0.19.1 AS core 5 | 6 | FROM core+base-image 7 | 8 | CACHE --sharing=shared --id go-mod-cache /go/pkg/mod 9 | CACHE --sharing=shared --id go-cache /root/.cache/go-build 10 | 11 | sources: 12 | FROM core+builder-image 13 | COPY (../..+sources/*) /src 14 | WORKDIR /src/tools/generator 15 | COPY --dir cmd examples . 16 | COPY go.* *.go . 17 | SAVE ARTIFACT /src 18 | 19 | compile: 20 | FROM +sources 21 | CACHE --id go-mod-cache /go/pkg/mod 22 | CACHE --id go-cache /root/.cache/go-build 23 | RUN go build -o main 24 | SAVE ARTIFACT main 25 | 26 | build-image: 27 | FROM core+final-image 28 | ENTRYPOINT ["/bin/ledger-generator"] 29 | COPY --pass-args (+compile/main) /bin/ledger-generator 30 | COPY examples /examples 31 | ARG REPOSITORY=ghcr.io 32 | ARG tag=latest 33 | DO --pass-args core+SAVE_IMAGE --COMPONENT=ledger-generator --REPOSITORY=${REPOSITORY} --TAG=$tag -------------------------------------------------------------------------------- /tools/generator/examples/example1.js: -------------------------------------------------------------------------------- 1 | const plain = `vars { 2 | account $order 3 | account $seller 4 | } 5 | send [USD/2 100] ( 6 | source = @world 7 | destination = $order 8 | ) 9 | send [USD/2 1] ( 10 | source = $order 11 | destination = @fees 12 | ) 13 | send [USD/2 99] ( 14 | source = $order 15 | destination = $seller 16 | )` 17 | 18 | function next(iteration) { 19 | return [{ 20 | action: 'CREATE_TRANSACTION', 21 | data: { 22 | script: { 23 | plain, 24 | vars: { 25 | order: `orders:${uuid()}`, 26 | seller: `sellers:${iteration % 5}` 27 | } 28 | } 29 | } 30 | }] 31 | } -------------------------------------------------------------------------------- /tools/generator/examples_test.go: -------------------------------------------------------------------------------- 1 | //go:build it 2 | 3 | package main_test 4 | 5 | import ( 6 | "embed" 7 | "github.com/formancehq/ledger/pkg/generate" 8 | "github.com/stretchr/testify/require" 9 | "path/filepath" 10 | "testing" 11 | ) 12 | 13 | //go:embed examples 14 | var examples embed.FS 15 | 16 | func TestGenerator(t *testing.T) { 17 | dirEntries, err := examples.ReadDir("examples") 18 | require.NoError(t, err) 19 | 20 | for _, entry := range dirEntries { 21 | example, err := examples.ReadFile(filepath.Join("examples", entry.Name())) 22 | require.NoError(t, err) 23 | 24 | generator, err := generate.NewGenerator(string(example)) 25 | require.NoError(t, err) 26 | 27 | _, err = generator.Next(1) 28 | require.NoError(t, err) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tools/generator/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/formancehq/ledger/tools/generator/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /tools/provisioner/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.24-alpine AS compiler 2 | WORKDIR /src 3 | COPY go.* . 4 | RUN --mount=type=cache,target=$GOPATH go mod download 5 | COPY main.go . 6 | COPY cmd /src/cmd 7 | COPY pkg /src/pkg 8 | RUN --mount=type=cache,target=$GOPATH go build -o provisioner 9 | 10 | FROM alpine:3.21 11 | LABEL org.opencontainers.image.source=https://github.com/formancehq/ledger 12 | COPY --from=compiler /src/provisioner /bin/provisioner 13 | ENTRYPOINT ["/bin/provisioner"] 14 | CMD ["--help"] -------------------------------------------------------------------------------- /tools/provisioner/justfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env just --justfile 2 | 3 | set positional-arguments 4 | 5 | push-image version='latest': 6 | docker buildx build . \ 7 | -t ghcr.io/formancehq/ledger-provisioner:{{ version }} \ 8 | --push \ 9 | --platform linux/amd64,linux/arm64 10 | -------------------------------------------------------------------------------- /tools/provisioner/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/formancehq/ledger/tools/provisioner/cmd" 4 | 5 | func main() { 6 | cmd.Execute() 7 | } 8 | -------------------------------------------------------------------------------- /tools/provisioner/pkg/config.go: -------------------------------------------------------------------------------- 1 | package provisionner 2 | 3 | type LedgerConfig struct { 4 | Bucket string `yaml:"bucket"` 5 | Features map[string]string `yaml:"features"` 6 | Metadata map[string]string `yaml:"metadata"` 7 | } 8 | 9 | type Config struct { 10 | Ledgers map[string]LedgerConfig `yaml:"ledgers"` 11 | } 12 | 13 | func newState() State { 14 | return State{ 15 | Ledgers: make(map[string]LedgerConfig), 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tools/provisioner/pkg/state.go: -------------------------------------------------------------------------------- 1 | package provisionner 2 | 3 | type State struct { 4 | Ledgers map[string]LedgerConfig 5 | } 6 | --------------------------------------------------------------------------------