From bf85ca062c8562f55e5d91682133cafc64737752 Mon Sep 17 00:00:00 2001 From: Stephan D Date: Thu, 4 Dec 2025 14:40:21 +0100 Subject: [PATCH] restucturization of recipients payment methods --- .gitignore | 1 + .woodpecker/bump_version.yml | 33 ------ .woodpecker/chain_gateway.yml | 8 +- api/billing/fees/go.mod | 4 +- api/billing/fees/go.sum | 8 +- api/chain/gateway/client/fake.go | 83 -------------- api/fx/ingestor/go.mod | 4 +- api/fx/ingestor/go.sum | 8 +- api/fx/oracle/go.mod | 4 +- api/fx/oracle/go.sum | 8 +- api/fx/storage/go.mod | 2 +- api/fx/storage/go.sum | 4 +- .../gateway => gateway/chain}/.air.toml | 4 +- .../gateway => gateway/chain}/.gitignore | 0 .../chain}/client/client.go | 52 ++++----- .../chain}/client/config.go | 0 api/gateway/chain/client/fake.go | 83 ++++++++++++++ .../gateway => gateway/chain}/config.yml | 2 +- .../gateway => gateway/chain}/entrypoint.sh | 0 .../gateway => gateway/chain}/env/.gitignore | 0 api/{chain/gateway => gateway/chain}/go.mod | 2 +- api/{chain/gateway => gateway/chain}/go.sum | 0 .../chain}/internal/appversion/version.go | 0 .../chain}/internal/keymanager/config.go | 0 .../chain}/internal/keymanager/keymanager.go | 0 .../internal/keymanager/vault/manager.go | 2 +- .../internal/server/internal/serverimp.go | 12 +-- .../chain}/internal/server/server.go | 2 +- .../service/gateway/commands/registry.go | 22 ++-- .../gateway/commands/transfer/convert_fees.go | 8 +- .../service/gateway/commands/transfer/deps.go | 4 +- .../gateway/commands/transfer/destination.go | 6 +- .../commands/transfer/destination_address.go | 2 +- .../service/gateway/commands/transfer/fee.go | 32 +++--- .../service/gateway/commands/transfer/get.go | 16 +-- .../service/gateway/commands/transfer/list.go | 16 +-- .../gateway/commands/transfer/proto.go | 22 ++-- .../gateway/commands/transfer/submit.go | 48 ++++----- .../gateway/commands/wallet/balance.go | 26 ++--- .../service/gateway/commands/wallet/create.go | 40 +++---- .../service/gateway/commands/wallet/deps.go | 6 +- .../service/gateway/commands/wallet/get.go | 16 +-- .../service/gateway/commands/wallet/list.go | 16 +-- .../commands/wallet/onchain_balance.go | 2 +- .../service/gateway/commands/wallet/proto.go | 16 +-- .../internal/service/gateway/executor.go | 6 +- .../internal/service/gateway/metrics.go | 0 .../internal/service/gateway/options.go | 4 +- .../internal/service/gateway/service.go | 34 +++--- .../internal/service/gateway/service_test.go | 42 ++++---- .../service/gateway/shared/helpers.go | 60 +++++------ .../service/gateway/transfer_execution.go | 4 +- api/{chain/gateway => gateway/chain}/main.go | 4 +- .../chain}/storage/model/deposit.go | 0 .../chain}/storage/model/transfer.go | 0 .../chain}/storage/model/wallet.go | 0 .../chain}/storage/mongo/repository.go | 4 +- .../chain}/storage/mongo/store/deposits.go | 4 +- .../chain}/storage/mongo/store/transfers.go | 4 +- .../chain}/storage/mongo/store/wallets.go | 4 +- .../chain}/storage/storage.go | 2 +- api/ledger/client/fake.go | 16 +++ api/ledger/internal/service/ledger/queries.go | 4 +- api/notification/.gitignore | 1 + api/payments/orchestrator/go.mod | 8 +- api/payments/orchestrator/go.sum | 8 +- .../internal/server/internal/serverimp.go | 2 +- .../internal/service/orchestrator/convert.go | 10 +- .../service/orchestrator/execution.go | 44 ++++---- .../internal/service/orchestrator/helpers.go | 12 +-- .../internal/service/orchestrator/options.go | 2 +- .../service/orchestrator/service_test.go | 14 +-- .../orchestrator/storage/model/payment.go | 28 ++--- api/pkg/.gitignore | 4 +- api/pkg/model/crypto_address.go | 27 +++++ api/pkg/model/payment.go | 20 ++-- api/proto/common/gateway/v1/gateway.proto | 97 +++++++++++++++++ .../chain/v1/chain.proto} | 4 +- .../orchestrator/v1/orchestrator.proto | 2 +- api/server/.gitignore | 1 + api/server/go.mod | 4 +- api/server/interface/api/srequest/signup.go | 21 +++- api/server/interface/api/sresponse/wallet.go | 10 +- .../internal/server/accountapiimp/service.go | 24 ++--- .../internal/server/accountapiimp/signup.go | 4 +- .../accountapiimp/signup_integration_test.go | 5 + .../internal/server/walletapiimp/balance.go | 4 +- .../internal/server/walletapiimp/list.go | 4 +- .../internal/server/walletapiimp/service.go | 8 +- ci/prod/compose/chain_gateway.dockerfile | 18 ++-- ci/prod/compose/chain_gateway.yml | 2 +- ci/scripts/proto/generate.sh | 6 +- .../pshared/lib/data/dto/payment/card.dart | 20 ++++ .../lib/data/dto/payment/crypto_address.dart | 20 ++++ .../pshared/lib/data/dto/payment/iban.dart | 22 ++++ .../pshared/lib/data/dto/payment/method.dart | 33 ++++++ .../lib/data/dto/payment/russian_bank.dart | 28 +++++ .../pshared/lib/data/dto/payment/wallet.dart | 16 +++ .../lib/data/dto/recipient/recipient.dart | 39 +++++++ .../pshared/lib/data/mapper/payment/card.dart | 19 ++++ .../data/mapper/payment/crypto_address.dart | 19 ++++ .../pshared/lib/data/mapper/payment/iban.dart | 21 ++++ .../lib/data/mapper/payment/method.dart | 81 ++++++++++++++ .../lib/data/mapper/payment/russian_bank.dart | 27 +++++ .../pshared/lib/data/mapper/payment/type.dart | 34 ++++++ .../lib/data/mapper/payment/wallet.dart | 13 +++ .../lib/data/mapper/recipient/recipient.dart | 85 +++++++++++++++ .../payment/methods/crypto_address.dart | 18 ++++ .../lib/models/payment/payment_method.dart | 46 ++++++++ frontend/pshared/lib/models/payment/type.dart | 1 + .../lib/models/recipient/recipient.dart | 8 ++ .../lib/models/recipient/recipient_model.dart | 64 +++++++++++ .../lib/pages/address_book/form/page.dart | 5 +- .../page/recipient/payment_row.dart | 7 +- .../single/adress_book/long_list/item.dart | 5 + .../payment_methods/add/crypto_address.dart | 101 ++++++++++++++++++ .../pweb/lib/pages/payment_methods/form.dart | 7 ++ .../pweb/lib/pages/payment_methods/icon.dart | 2 + .../pweb/lib/providers/page_selector.dart | 1 + frontend/pweb/lib/utils/payment/label.dart | 1 + 120 files changed, 1415 insertions(+), 538 deletions(-) delete mode 100644 .woodpecker/bump_version.yml delete mode 100644 api/chain/gateway/client/fake.go rename api/{chain/gateway => gateway/chain}/.air.toml (55%) rename api/{chain/gateway => gateway/chain}/.gitignore (100%) rename api/{chain/gateway => gateway/chain}/client/client.go (52%) rename api/{chain/gateway => gateway/chain}/client/config.go (100%) create mode 100644 api/gateway/chain/client/fake.go rename api/{chain/gateway => gateway/chain}/config.yml (97%) rename api/{chain/gateway => gateway/chain}/entrypoint.sh (100%) rename api/{chain/gateway => gateway/chain}/env/.gitignore (100%) rename api/{chain/gateway => gateway/chain}/go.mod (98%) rename api/{chain/gateway => gateway/chain}/go.sum (100%) rename api/{chain/gateway => gateway/chain}/internal/appversion/version.go (100%) rename api/{chain/gateway => gateway/chain}/internal/keymanager/config.go (100%) rename api/{chain/gateway => gateway/chain}/internal/keymanager/keymanager.go (100%) rename api/{chain/gateway => gateway/chain}/internal/keymanager/vault/manager.go (99%) rename api/{chain/gateway => gateway/chain}/internal/server/internal/serverimp.go (95%) rename api/{chain/gateway => gateway/chain}/internal/server/server.go (83%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/registry.go (54%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/convert_fees.go (80%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/deps.go (82%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/destination.go (87%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/destination_address.go (92%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/fee.go (80%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/get.go (53%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/list.go (70%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/proto.go (62%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/transfer/submit.go (59%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/balance.go (59%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/create.go (55%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/deps.go (70%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/get.go (55%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/list.go (70%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/onchain_balance.go (98%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/commands/wallet/proto.go (69%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/executor.go (98%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/metrics.go (100%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/options.go (93%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/service.go (71%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/service_test.go (91%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/shared/helpers.go (60%) rename api/{chain/gateway => gateway/chain}/internal/service/gateway/transfer_execution.go (96%) rename api/{chain/gateway => gateway/chain}/main.go (74%) rename api/{chain/gateway => gateway/chain}/storage/model/deposit.go (100%) rename api/{chain/gateway => gateway/chain}/storage/model/transfer.go (100%) rename api/{chain/gateway => gateway/chain}/storage/model/wallet.go (100%) rename api/{chain/gateway => gateway/chain}/storage/mongo/repository.go (95%) rename api/{chain/gateway => gateway/chain}/storage/mongo/store/deposits.go (97%) rename api/{chain/gateway => gateway/chain}/storage/mongo/store/transfers.go (98%) rename api/{chain/gateway => gateway/chain}/storage/mongo/store/wallets.go (98%) rename api/{chain/gateway => gateway/chain}/storage/storage.go (97%) create mode 100644 api/pkg/model/crypto_address.go create mode 100644 api/proto/common/gateway/v1/gateway.proto rename api/proto/{chain/gateway/v1/gateway.proto => gateway/chain/v1/chain.proto} (97%) create mode 100644 frontend/pshared/lib/data/dto/payment/card.dart create mode 100644 frontend/pshared/lib/data/dto/payment/crypto_address.dart create mode 100644 frontend/pshared/lib/data/dto/payment/iban.dart create mode 100644 frontend/pshared/lib/data/dto/payment/method.dart create mode 100644 frontend/pshared/lib/data/dto/payment/russian_bank.dart create mode 100644 frontend/pshared/lib/data/dto/payment/wallet.dart create mode 100644 frontend/pshared/lib/data/dto/recipient/recipient.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/card.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/crypto_address.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/iban.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/method.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/russian_bank.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/type.dart create mode 100644 frontend/pshared/lib/data/mapper/payment/wallet.dart create mode 100644 frontend/pshared/lib/data/mapper/recipient/recipient.dart create mode 100644 frontend/pshared/lib/models/payment/methods/crypto_address.dart create mode 100644 frontend/pshared/lib/models/payment/payment_method.dart create mode 100644 frontend/pshared/lib/models/recipient/recipient_model.dart create mode 100644 frontend/pweb/lib/pages/payment_methods/add/crypto_address.dart diff --git a/.gitignore b/.gitignore index c42cd81..e663d96 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ pubspec.lock analysis_options.yaml devtools_options.yaml untranslated.txt +generate_protos.sh update_dep.sh .vscode/ \ No newline at end of file diff --git a/.woodpecker/bump_version.yml b/.woodpecker/bump_version.yml deleted file mode 100644 index 9c13308..0000000 --- a/.woodpecker/bump_version.yml +++ /dev/null @@ -1,33 +0,0 @@ -depends_on: - - bff - - billing_fees - - chain_gateway - - db - - frontend - - fx_ingestor - - fx_oracle - - ledger - - nats - - notification - - payments_orchestrator - -when: - event: push - branch: main - -steps: - - name: bump-version - image: alpine:latest - environment: - GIT_AUTHOR_NAME: woodpecker - GIT_AUTHOR_EMAIL: ci@sendico.io - GIT_COMMITTER_NAME: woodpecker - GIT_COMMITTER_EMAIL: ci@sendico.io - commands: - - set -euo pipefail - - apk add --no-cache git - # make sure git knows who commits - - git config user.name "$GIT_AUTHOR_NAME" - - git config user.email "$GIT_AUTHOR_EMAIL" - # run your script (must do commit + push) - - sh ci/scripts/common/bump_version.sh diff --git a/.woodpecker/chain_gateway.yml b/.woodpecker/chain_gateway.yml index 447c455..4eb98ed 100644 --- a/.woodpecker/chain_gateway.yml +++ b/.woodpecker/chain_gateway.yml @@ -1,11 +1,11 @@ matrix: include: - - CHAIN_GATEWAY_IMAGE_PATH: chain/gateway + - CHAIN_GATEWAY_IMAGE_PATH: gateway/chain CHAIN_GATEWAY_DOCKERFILE: ci/prod/compose/chain_gateway.dockerfile CHAIN_GATEWAY_MONGO_SECRET_PATH: sendico/db - CHAIN_GATEWAY_RPC_SECRET_PATH: sendico/chain/gateway - CHAIN_GATEWAY_WALLET_SECRET_PATH: sendico/chain/gateway/wallet - CHAIN_GATEWAY_VAULT_SECRET_PATH: sendico/chain/gateway/vault + CHAIN_GATEWAY_RPC_SECRET_PATH: sendico/gateway/chain + CHAIN_GATEWAY_WALLET_SECRET_PATH: sendico/gateway/chain/wallet + CHAIN_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/chain/vault CHAIN_GATEWAY_ENV: prod when: diff --git a/api/billing/fees/go.mod b/api/billing/fees/go.mod index 93f1087..a72b51c 100644 --- a/api/billing/fees/go.mod +++ b/api/billing/fees/go.mod @@ -25,7 +25,7 @@ require ( github.com/go-chi/chi/v5 v5.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -49,6 +49,6 @@ require ( golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/protobuf v1.36.10 ) diff --git a/api/billing/fees/go.sum b/api/billing/fees/go.sum index e512ba3..d63f35a 100644 --- a/api/billing/fees/go.sum +++ b/api/billing/fees/go.sum @@ -59,8 +59,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= diff --git a/api/chain/gateway/client/fake.go b/api/chain/gateway/client/fake.go deleted file mode 100644 index 8974b51..0000000 --- a/api/chain/gateway/client/fake.go +++ /dev/null @@ -1,83 +0,0 @@ -package client - -import ( - "context" - - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" -) - -// Fake implements Client for tests. -type Fake struct { - CreateManagedWalletFn func(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) - GetManagedWalletFn func(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) (*gatewayv1.GetManagedWalletResponse, error) - ListManagedWalletsFn func(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) - GetWalletBalanceFn func(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) - SubmitTransferFn func(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) - GetTransferFn func(ctx context.Context, req *gatewayv1.GetTransferRequest) (*gatewayv1.GetTransferResponse, error) - ListTransfersFn func(ctx context.Context, req *gatewayv1.ListTransfersRequest) (*gatewayv1.ListTransfersResponse, error) - EstimateTransferFeeFn func(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) (*gatewayv1.EstimateTransferFeeResponse, error) - CloseFn func() error -} - -func (f *Fake) CreateManagedWallet(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) { - if f.CreateManagedWalletFn != nil { - return f.CreateManagedWalletFn(ctx, req) - } - return &gatewayv1.CreateManagedWalletResponse{}, nil -} - -func (f *Fake) GetManagedWallet(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) (*gatewayv1.GetManagedWalletResponse, error) { - if f.GetManagedWalletFn != nil { - return f.GetManagedWalletFn(ctx, req) - } - return &gatewayv1.GetManagedWalletResponse{}, nil -} - -func (f *Fake) ListManagedWallets(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) { - if f.ListManagedWalletsFn != nil { - return f.ListManagedWalletsFn(ctx, req) - } - return &gatewayv1.ListManagedWalletsResponse{}, nil -} - -func (f *Fake) GetWalletBalance(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) { - if f.GetWalletBalanceFn != nil { - return f.GetWalletBalanceFn(ctx, req) - } - return &gatewayv1.GetWalletBalanceResponse{}, nil -} - -func (f *Fake) SubmitTransfer(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) { - if f.SubmitTransferFn != nil { - return f.SubmitTransferFn(ctx, req) - } - return &gatewayv1.SubmitTransferResponse{}, nil -} - -func (f *Fake) GetTransfer(ctx context.Context, req *gatewayv1.GetTransferRequest) (*gatewayv1.GetTransferResponse, error) { - if f.GetTransferFn != nil { - return f.GetTransferFn(ctx, req) - } - return &gatewayv1.GetTransferResponse{}, nil -} - -func (f *Fake) ListTransfers(ctx context.Context, req *gatewayv1.ListTransfersRequest) (*gatewayv1.ListTransfersResponse, error) { - if f.ListTransfersFn != nil { - return f.ListTransfersFn(ctx, req) - } - return &gatewayv1.ListTransfersResponse{}, nil -} - -func (f *Fake) EstimateTransferFee(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) (*gatewayv1.EstimateTransferFeeResponse, error) { - if f.EstimateTransferFeeFn != nil { - return f.EstimateTransferFeeFn(ctx, req) - } - return &gatewayv1.EstimateTransferFeeResponse{}, nil -} - -func (f *Fake) Close() error { - if f.CloseFn != nil { - return f.CloseFn() - } - return nil -} diff --git a/api/fx/ingestor/go.mod b/api/fx/ingestor/go.mod index a194950..0de7c77 100644 --- a/api/fx/ingestor/go.mod +++ b/api/fx/ingestor/go.mod @@ -25,7 +25,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -49,7 +49,7 @@ require ( golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect ) diff --git a/api/fx/ingestor/go.sum b/api/fx/ingestor/go.sum index e512ba3..d63f35a 100644 --- a/api/fx/ingestor/go.sum +++ b/api/fx/ingestor/go.sum @@ -59,8 +59,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= diff --git a/api/fx/oracle/go.mod b/api/fx/oracle/go.mod index a67e286..5089e0a 100644 --- a/api/fx/oracle/go.mod +++ b/api/fx/oracle/go.mod @@ -27,7 +27,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-chi/chi/v5 v5.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -50,5 +50,5 @@ require ( golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect ) diff --git a/api/fx/oracle/go.sum b/api/fx/oracle/go.sum index e512ba3..d63f35a 100644 --- a/api/fx/oracle/go.sum +++ b/api/fx/oracle/go.sum @@ -59,8 +59,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -212,8 +212,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= diff --git a/api/fx/storage/go.mod b/api/fx/storage/go.mod index c091906..536b0a3 100644 --- a/api/fx/storage/go.mod +++ b/api/fx/storage/go.mod @@ -17,7 +17,7 @@ require ( github.com/casbin/mongodb-adapter/v3 v3.7.0 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect diff --git a/api/fx/storage/go.sum b/api/fx/storage/go.sum index d4c97bf..2334065 100644 --- a/api/fx/storage/go.sum +++ b/api/fx/storage/go.sum @@ -51,8 +51,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54 h1:mFWunSatvkQQDhpdyuFAYwyAan3hzCuma+Pz8sqvOfg= github.com/lufia/plan9stats v0.0.0-20250827001030-24949be3fa54/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/api/chain/gateway/.air.toml b/api/gateway/chain/.air.toml similarity index 55% rename from api/chain/gateway/.air.toml rename to api/gateway/chain/.air.toml index cebf273..5a417ef 100644 --- a/api/chain/gateway/.air.toml +++ b/api/gateway/chain/.air.toml @@ -4,11 +4,11 @@ root = "./../.." tmp_dir = "tmp" [build] -cmd = "go build -o app -ldflags \"-X 'github.com/tech/sendico/chain/gateway/internal/appversion.BuildUser=$(whoami)' -X 'github.com/tech/sendico/chain/gateway/internal/appversion.Version=$APP_V' -X 'github.com/tech/sendico/chain/gateway/internal/appversion.Branch=$BUILD_BRANCH' -X 'github.com/tech/sendico/chain/gateway/internal/appversion.Revision=$GIT_REV' -X 'github.com/tech/sendico/chain/gateway/internal/appversion.BuildDate=$(date)'\"" +cmd = "go build -o app -ldflags \"-X 'github.com/tech/sendico/gateway/chain/internal/appversion.BuildUser=$(whoami)' -X 'github.com/tech/sendico/gateway/chain/internal/appversion.Version=$APP_V' -X 'github.com/tech/sendico/gateway/chain/internal/appversion.Branch=$BUILD_BRANCH' -X 'github.com/tech/sendico/gateway/chain/internal/appversion.Revision=$GIT_REV' -X 'github.com/tech/sendico/gateway/chain/internal/appversion.BuildDate=$(date)'\"" bin = "./app" full_bin = "./app --debug --config.file=config.yml" include_ext = ["go", "yaml", "yml"] -exclude_dir = ["chain/gateway/tmp", "pkg/.git", "chain/gateway/env"] +exclude_dir = ["gateway/chain/tmp", "pkg/.git", "gateway/chain/env"] exclude_regex = ["_test\\.go"] exclude_unchanged = true follow_symlink = true diff --git a/api/chain/gateway/.gitignore b/api/gateway/chain/.gitignore similarity index 100% rename from api/chain/gateway/.gitignore rename to api/gateway/chain/.gitignore diff --git a/api/chain/gateway/client/client.go b/api/gateway/chain/client/client.go similarity index 52% rename from api/chain/gateway/client/client.go rename to api/gateway/chain/client/client.go index b54b044..49149da 100644 --- a/api/chain/gateway/client/client.go +++ b/api/gateway/chain/client/client.go @@ -8,7 +8,7 @@ import ( "time" "github.com/tech/sendico/pkg/merrors" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -16,26 +16,26 @@ import ( // Client exposes typed helpers around the chain gateway gRPC API. type Client interface { - CreateManagedWallet(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) - GetManagedWallet(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) (*gatewayv1.GetManagedWalletResponse, error) - ListManagedWallets(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) - GetWalletBalance(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) - SubmitTransfer(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) - GetTransfer(ctx context.Context, req *gatewayv1.GetTransferRequest) (*gatewayv1.GetTransferResponse, error) - ListTransfers(ctx context.Context, req *gatewayv1.ListTransfersRequest) (*gatewayv1.ListTransfersResponse, error) - EstimateTransferFee(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) (*gatewayv1.EstimateTransferFeeResponse, error) + CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) + GetManagedWallet(ctx context.Context, req *chainv1.GetManagedWalletRequest) (*chainv1.GetManagedWalletResponse, error) + ListManagedWallets(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) + GetWalletBalance(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) + SubmitTransfer(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) + GetTransfer(ctx context.Context, req *chainv1.GetTransferRequest) (*chainv1.GetTransferResponse, error) + ListTransfers(ctx context.Context, req *chainv1.ListTransfersRequest) (*chainv1.ListTransfersResponse, error) + EstimateTransferFee(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) (*chainv1.EstimateTransferFeeResponse, error) Close() error } type grpcGatewayClient interface { - CreateManagedWallet(ctx context.Context, in *gatewayv1.CreateManagedWalletRequest, opts ...grpc.CallOption) (*gatewayv1.CreateManagedWalletResponse, error) - GetManagedWallet(ctx context.Context, in *gatewayv1.GetManagedWalletRequest, opts ...grpc.CallOption) (*gatewayv1.GetManagedWalletResponse, error) - ListManagedWallets(ctx context.Context, in *gatewayv1.ListManagedWalletsRequest, opts ...grpc.CallOption) (*gatewayv1.ListManagedWalletsResponse, error) - GetWalletBalance(ctx context.Context, in *gatewayv1.GetWalletBalanceRequest, opts ...grpc.CallOption) (*gatewayv1.GetWalletBalanceResponse, error) - SubmitTransfer(ctx context.Context, in *gatewayv1.SubmitTransferRequest, opts ...grpc.CallOption) (*gatewayv1.SubmitTransferResponse, error) - GetTransfer(ctx context.Context, in *gatewayv1.GetTransferRequest, opts ...grpc.CallOption) (*gatewayv1.GetTransferResponse, error) - ListTransfers(ctx context.Context, in *gatewayv1.ListTransfersRequest, opts ...grpc.CallOption) (*gatewayv1.ListTransfersResponse, error) - EstimateTransferFee(ctx context.Context, in *gatewayv1.EstimateTransferFeeRequest, opts ...grpc.CallOption) (*gatewayv1.EstimateTransferFeeResponse, error) + CreateManagedWallet(ctx context.Context, in *chainv1.CreateManagedWalletRequest, opts ...grpc.CallOption) (*chainv1.CreateManagedWalletResponse, error) + GetManagedWallet(ctx context.Context, in *chainv1.GetManagedWalletRequest, opts ...grpc.CallOption) (*chainv1.GetManagedWalletResponse, error) + ListManagedWallets(ctx context.Context, in *chainv1.ListManagedWalletsRequest, opts ...grpc.CallOption) (*chainv1.ListManagedWalletsResponse, error) + GetWalletBalance(ctx context.Context, in *chainv1.GetWalletBalanceRequest, opts ...grpc.CallOption) (*chainv1.GetWalletBalanceResponse, error) + SubmitTransfer(ctx context.Context, in *chainv1.SubmitTransferRequest, opts ...grpc.CallOption) (*chainv1.SubmitTransferResponse, error) + GetTransfer(ctx context.Context, in *chainv1.GetTransferRequest, opts ...grpc.CallOption) (*chainv1.GetTransferResponse, error) + ListTransfers(ctx context.Context, in *chainv1.ListTransfersRequest, opts ...grpc.CallOption) (*chainv1.ListTransfersResponse, error) + EstimateTransferFee(ctx context.Context, in *chainv1.EstimateTransferFeeRequest, opts ...grpc.CallOption) (*chainv1.EstimateTransferFeeResponse, error) } type chainGatewayClient struct { @@ -71,7 +71,7 @@ func New(ctx context.Context, cfg Config, opts ...grpc.DialOption) (Client, erro return &chainGatewayClient{ cfg: cfg, conn: conn, - client: gatewayv1.NewChainGatewayServiceClient(conn), + client: chainv1.NewChainGatewayServiceClient(conn), }, nil } @@ -91,49 +91,49 @@ func (c *chainGatewayClient) Close() error { return nil } -func (c *chainGatewayClient) CreateManagedWallet(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) { +func (c *chainGatewayClient) CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.CreateManagedWallet(ctx, req) } -func (c *chainGatewayClient) GetManagedWallet(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) (*gatewayv1.GetManagedWalletResponse, error) { +func (c *chainGatewayClient) GetManagedWallet(ctx context.Context, req *chainv1.GetManagedWalletRequest) (*chainv1.GetManagedWalletResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.GetManagedWallet(ctx, req) } -func (c *chainGatewayClient) ListManagedWallets(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) { +func (c *chainGatewayClient) ListManagedWallets(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.ListManagedWallets(ctx, req) } -func (c *chainGatewayClient) GetWalletBalance(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) { +func (c *chainGatewayClient) GetWalletBalance(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.GetWalletBalance(ctx, req) } -func (c *chainGatewayClient) SubmitTransfer(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) { +func (c *chainGatewayClient) SubmitTransfer(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.SubmitTransfer(ctx, req) } -func (c *chainGatewayClient) GetTransfer(ctx context.Context, req *gatewayv1.GetTransferRequest) (*gatewayv1.GetTransferResponse, error) { +func (c *chainGatewayClient) GetTransfer(ctx context.Context, req *chainv1.GetTransferRequest) (*chainv1.GetTransferResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.GetTransfer(ctx, req) } -func (c *chainGatewayClient) ListTransfers(ctx context.Context, req *gatewayv1.ListTransfersRequest) (*gatewayv1.ListTransfersResponse, error) { +func (c *chainGatewayClient) ListTransfers(ctx context.Context, req *chainv1.ListTransfersRequest) (*chainv1.ListTransfersResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.ListTransfers(ctx, req) } -func (c *chainGatewayClient) EstimateTransferFee(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) (*gatewayv1.EstimateTransferFeeResponse, error) { +func (c *chainGatewayClient) EstimateTransferFee(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) (*chainv1.EstimateTransferFeeResponse, error) { ctx, cancel := c.callContext(ctx) defer cancel() return c.client.EstimateTransferFee(ctx, req) diff --git a/api/chain/gateway/client/config.go b/api/gateway/chain/client/config.go similarity index 100% rename from api/chain/gateway/client/config.go rename to api/gateway/chain/client/config.go diff --git a/api/gateway/chain/client/fake.go b/api/gateway/chain/client/fake.go new file mode 100644 index 0000000..59e57d0 --- /dev/null +++ b/api/gateway/chain/client/fake.go @@ -0,0 +1,83 @@ +package client + +import ( + "context" + + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" +) + +// Fake implements Client for tests. +type Fake struct { + CreateManagedWalletFn func(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) + GetManagedWalletFn func(ctx context.Context, req *chainv1.GetManagedWalletRequest) (*chainv1.GetManagedWalletResponse, error) + ListManagedWalletsFn func(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) + GetWalletBalanceFn func(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) + SubmitTransferFn func(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) + GetTransferFn func(ctx context.Context, req *chainv1.GetTransferRequest) (*chainv1.GetTransferResponse, error) + ListTransfersFn func(ctx context.Context, req *chainv1.ListTransfersRequest) (*chainv1.ListTransfersResponse, error) + EstimateTransferFeeFn func(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) (*chainv1.EstimateTransferFeeResponse, error) + CloseFn func() error +} + +func (f *Fake) CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) { + if f.CreateManagedWalletFn != nil { + return f.CreateManagedWalletFn(ctx, req) + } + return &chainv1.CreateManagedWalletResponse{}, nil +} + +func (f *Fake) GetManagedWallet(ctx context.Context, req *chainv1.GetManagedWalletRequest) (*chainv1.GetManagedWalletResponse, error) { + if f.GetManagedWalletFn != nil { + return f.GetManagedWalletFn(ctx, req) + } + return &chainv1.GetManagedWalletResponse{}, nil +} + +func (f *Fake) ListManagedWallets(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) { + if f.ListManagedWalletsFn != nil { + return f.ListManagedWalletsFn(ctx, req) + } + return &chainv1.ListManagedWalletsResponse{}, nil +} + +func (f *Fake) GetWalletBalance(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) { + if f.GetWalletBalanceFn != nil { + return f.GetWalletBalanceFn(ctx, req) + } + return &chainv1.GetWalletBalanceResponse{}, nil +} + +func (f *Fake) SubmitTransfer(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) { + if f.SubmitTransferFn != nil { + return f.SubmitTransferFn(ctx, req) + } + return &chainv1.SubmitTransferResponse{}, nil +} + +func (f *Fake) GetTransfer(ctx context.Context, req *chainv1.GetTransferRequest) (*chainv1.GetTransferResponse, error) { + if f.GetTransferFn != nil { + return f.GetTransferFn(ctx, req) + } + return &chainv1.GetTransferResponse{}, nil +} + +func (f *Fake) ListTransfers(ctx context.Context, req *chainv1.ListTransfersRequest) (*chainv1.ListTransfersResponse, error) { + if f.ListTransfersFn != nil { + return f.ListTransfersFn(ctx, req) + } + return &chainv1.ListTransfersResponse{}, nil +} + +func (f *Fake) EstimateTransferFee(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) (*chainv1.EstimateTransferFeeResponse, error) { + if f.EstimateTransferFeeFn != nil { + return f.EstimateTransferFeeFn(ctx, req) + } + return &chainv1.EstimateTransferFeeResponse{}, nil +} + +func (f *Fake) Close() error { + if f.CloseFn != nil { + return f.CloseFn() + } + return nil +} diff --git a/api/chain/gateway/config.yml b/api/gateway/chain/config.yml similarity index 97% rename from api/chain/gateway/config.yml rename to api/gateway/chain/config.yml index 05dada2..b6aa8e9 100644 --- a/api/chain/gateway/config.yml +++ b/api/gateway/chain/config.yml @@ -54,4 +54,4 @@ key_management: token_env: VAULT_TOKEN namespace: "" mount_path: kv - key_prefix: chain/gateway/wallets + key_prefix: gateway/chain/wallets diff --git a/api/chain/gateway/entrypoint.sh b/api/gateway/chain/entrypoint.sh similarity index 100% rename from api/chain/gateway/entrypoint.sh rename to api/gateway/chain/entrypoint.sh diff --git a/api/chain/gateway/env/.gitignore b/api/gateway/chain/env/.gitignore similarity index 100% rename from api/chain/gateway/env/.gitignore rename to api/gateway/chain/env/.gitignore diff --git a/api/chain/gateway/go.mod b/api/gateway/chain/go.mod similarity index 98% rename from api/chain/gateway/go.mod rename to api/gateway/chain/go.mod index 8d9fb97..c308e4a 100644 --- a/api/chain/gateway/go.mod +++ b/api/gateway/chain/go.mod @@ -1,4 +1,4 @@ -module github.com/tech/sendico/chain/gateway +module github.com/tech/sendico/gateway/chain go 1.25.3 diff --git a/api/chain/gateway/go.sum b/api/gateway/chain/go.sum similarity index 100% rename from api/chain/gateway/go.sum rename to api/gateway/chain/go.sum diff --git a/api/chain/gateway/internal/appversion/version.go b/api/gateway/chain/internal/appversion/version.go similarity index 100% rename from api/chain/gateway/internal/appversion/version.go rename to api/gateway/chain/internal/appversion/version.go diff --git a/api/chain/gateway/internal/keymanager/config.go b/api/gateway/chain/internal/keymanager/config.go similarity index 100% rename from api/chain/gateway/internal/keymanager/config.go rename to api/gateway/chain/internal/keymanager/config.go diff --git a/api/chain/gateway/internal/keymanager/keymanager.go b/api/gateway/chain/internal/keymanager/keymanager.go similarity index 100% rename from api/chain/gateway/internal/keymanager/keymanager.go rename to api/gateway/chain/internal/keymanager/keymanager.go diff --git a/api/chain/gateway/internal/keymanager/vault/manager.go b/api/gateway/chain/internal/keymanager/vault/manager.go similarity index 99% rename from api/chain/gateway/internal/keymanager/vault/manager.go rename to api/gateway/chain/internal/keymanager/vault/manager.go index 9e7db59..ff5b626 100644 --- a/api/chain/gateway/internal/keymanager/vault/manager.go +++ b/api/gateway/chain/internal/keymanager/vault/manager.go @@ -16,7 +16,7 @@ import ( "github.com/hashicorp/vault/api" "go.uber.org/zap" - "github.com/tech/sendico/chain/gateway/internal/keymanager" + "github.com/tech/sendico/gateway/chain/internal/keymanager" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" ) diff --git a/api/chain/gateway/internal/server/internal/serverimp.go b/api/gateway/chain/internal/server/internal/serverimp.go similarity index 95% rename from api/chain/gateway/internal/server/internal/serverimp.go rename to api/gateway/chain/internal/server/internal/serverimp.go index ec187a6..b4f7c31 100644 --- a/api/chain/gateway/internal/server/internal/serverimp.go +++ b/api/gateway/chain/internal/server/internal/serverimp.go @@ -7,12 +7,12 @@ import ( "time" "github.com/mitchellh/mapstructure" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - vaultmanager "github.com/tech/sendico/chain/gateway/internal/keymanager/vault" - gatewayservice "github.com/tech/sendico/chain/gateway/internal/service/gateway" - gatewayshared "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage" - gatewaymongo "github.com/tech/sendico/chain/gateway/storage/mongo" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + vaultmanager "github.com/tech/sendico/gateway/chain/internal/keymanager/vault" + gatewayservice "github.com/tech/sendico/gateway/chain/internal/service/gateway" + gatewayshared "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage" + gatewaymongo "github.com/tech/sendico/gateway/chain/storage/mongo" "github.com/tech/sendico/pkg/api/routers" "github.com/tech/sendico/pkg/db" "github.com/tech/sendico/pkg/merrors" diff --git a/api/chain/gateway/internal/server/server.go b/api/gateway/chain/internal/server/server.go similarity index 83% rename from api/chain/gateway/internal/server/server.go rename to api/gateway/chain/internal/server/server.go index c058db1..3f4a112 100644 --- a/api/chain/gateway/internal/server/server.go +++ b/api/gateway/chain/internal/server/server.go @@ -1,7 +1,7 @@ package server import ( - serverimp "github.com/tech/sendico/chain/gateway/internal/server/internal" + serverimp "github.com/tech/sendico/gateway/chain/internal/server/internal" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/server" ) diff --git a/api/chain/gateway/internal/service/gateway/commands/registry.go b/api/gateway/chain/internal/service/gateway/commands/registry.go similarity index 54% rename from api/chain/gateway/internal/service/gateway/commands/registry.go rename to api/gateway/chain/internal/service/gateway/commands/registry.go index bea855a..dec967c 100644 --- a/api/chain/gateway/internal/service/gateway/commands/registry.go +++ b/api/gateway/chain/internal/service/gateway/commands/registry.go @@ -3,10 +3,10 @@ package commands import ( "context" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/commands/transfer" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/commands/wallet" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/transfer" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/wallet" "github.com/tech/sendico/pkg/api/routers/gsresponse" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" ) type Unary[TReq any, TResp any] interface { @@ -14,15 +14,15 @@ type Unary[TReq any, TResp any] interface { } type Registry struct { - CreateManagedWallet Unary[gatewayv1.CreateManagedWalletRequest, gatewayv1.CreateManagedWalletResponse] - GetManagedWallet Unary[gatewayv1.GetManagedWalletRequest, gatewayv1.GetManagedWalletResponse] - ListManagedWallets Unary[gatewayv1.ListManagedWalletsRequest, gatewayv1.ListManagedWalletsResponse] - GetWalletBalance Unary[gatewayv1.GetWalletBalanceRequest, gatewayv1.GetWalletBalanceResponse] + CreateManagedWallet Unary[chainv1.CreateManagedWalletRequest, chainv1.CreateManagedWalletResponse] + GetManagedWallet Unary[chainv1.GetManagedWalletRequest, chainv1.GetManagedWalletResponse] + ListManagedWallets Unary[chainv1.ListManagedWalletsRequest, chainv1.ListManagedWalletsResponse] + GetWalletBalance Unary[chainv1.GetWalletBalanceRequest, chainv1.GetWalletBalanceResponse] - SubmitTransfer Unary[gatewayv1.SubmitTransferRequest, gatewayv1.SubmitTransferResponse] - GetTransfer Unary[gatewayv1.GetTransferRequest, gatewayv1.GetTransferResponse] - ListTransfers Unary[gatewayv1.ListTransfersRequest, gatewayv1.ListTransfersResponse] - EstimateTransfer Unary[gatewayv1.EstimateTransferFeeRequest, gatewayv1.EstimateTransferFeeResponse] + SubmitTransfer Unary[chainv1.SubmitTransferRequest, chainv1.SubmitTransferResponse] + GetTransfer Unary[chainv1.GetTransferRequest, chainv1.GetTransferResponse] + ListTransfers Unary[chainv1.ListTransfersRequest, chainv1.ListTransfersResponse] + EstimateTransfer Unary[chainv1.EstimateTransferFeeRequest, chainv1.EstimateTransferFeeResponse] } type RegistryDeps struct { diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/convert_fees.go b/api/gateway/chain/internal/service/gateway/commands/transfer/convert_fees.go similarity index 80% rename from api/chain/gateway/internal/service/gateway/commands/transfer/convert_fees.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/convert_fees.go index b41db01..24d564f 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/convert_fees.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/convert_fees.go @@ -4,13 +4,13 @@ import ( "strings" "github.com/shopspring/decimal" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" ) -func convertFees(fees []*gatewayv1.ServiceFeeBreakdown, currency string) ([]model.ServiceFee, decimal.Decimal, error) { +func convertFees(fees []*chainv1.ServiceFeeBreakdown, currency string) ([]model.ServiceFee, decimal.Decimal, error) { result := make([]model.ServiceFee, 0, len(fees)) sum := decimal.NewFromInt(0) for _, fee := range fees { diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/deps.go b/api/gateway/chain/internal/service/gateway/commands/transfer/deps.go similarity index 82% rename from api/chain/gateway/internal/service/gateway/commands/transfer/deps.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/deps.go index fb18e83..e5621a7 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/deps.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/deps.go @@ -3,8 +3,8 @@ package transfer import ( "context" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage" clockpkg "github.com/tech/sendico/pkg/clock" "github.com/tech/sendico/pkg/mlogger" ) diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/destination.go b/api/gateway/chain/internal/service/gateway/commands/transfer/destination.go similarity index 87% rename from api/chain/gateway/internal/service/gateway/commands/transfer/destination.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/destination.go index ad3f2d8..05c07a0 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/destination.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/destination.go @@ -4,13 +4,13 @@ import ( "context" "strings" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) -func resolveDestination(ctx context.Context, deps Deps, dest *gatewayv1.TransferDestination, source *model.ManagedWallet) (model.TransferDestination, error) { +func resolveDestination(ctx context.Context, deps Deps, dest *chainv1.TransferDestination, source *model.ManagedWallet) (model.TransferDestination, error) { if dest == nil { return model.TransferDestination{}, merrors.InvalidArgument("destination is required") } diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/destination_address.go b/api/gateway/chain/internal/service/gateway/commands/transfer/destination_address.go similarity index 92% rename from api/chain/gateway/internal/service/gateway/commands/transfer/destination_address.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/destination_address.go index 785bddf..8efd4e7 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/destination_address.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/destination_address.go @@ -4,7 +4,7 @@ import ( "context" "strings" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" ) diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/fee.go b/api/gateway/chain/internal/service/gateway/commands/transfer/fee.go similarity index 80% rename from api/chain/gateway/internal/service/gateway/commands/transfer/fee.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/fee.go index 846ef58..a433659 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/fee.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/fee.go @@ -12,14 +12,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/shopspring/decimal" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -31,67 +31,67 @@ func NewEstimateTransfer(deps Deps) *estimateTransferFeeCommand { return &estimateTransferFeeCommand{deps: deps} } -func (c *estimateTransferFeeCommand) Execute(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) gsresponse.Responder[gatewayv1.EstimateTransferFeeResponse] { +func (c *estimateTransferFeeCommand) Execute(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) gsresponse.Responder[chainv1.EstimateTransferFeeResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("request is required")) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("request is required")) } sourceWalletRef := strings.TrimSpace(req.GetSourceWalletRef()) if sourceWalletRef == "" { c.deps.Logger.Warn("source wallet ref missing") - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("source_wallet_ref is required")) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("source_wallet_ref is required")) } amount := req.GetAmount() if amount == nil || strings.TrimSpace(amount.GetAmount()) == "" || strings.TrimSpace(amount.GetCurrency()) == "" { c.deps.Logger.Warn("amount missing or incomplete") - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount is required")) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount is required")) } sourceWallet, err := c.deps.Storage.Wallets().Get(ctx, sourceWalletRef) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("source wallet not found", zap.String("source_wallet_ref", sourceWalletRef)) - return gsresponse.NotFound[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("storage get wallet failed", zap.Error(err), zap.String("source_wallet_ref", sourceWalletRef)) - return gsresponse.Auto[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } networkKey := strings.ToLower(strings.TrimSpace(sourceWallet.Network)) networkCfg, ok := c.deps.Networks[networkKey] if !ok { c.deps.Logger.Warn("unsupported chain", zap.String("network", networkKey)) - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain for wallet")) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain for wallet")) } dest, err := resolveDestination(ctx, c.deps, req.GetDestination(), sourceWallet) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("destination not found", zap.String("destination_wallet_ref", req.GetDestination().GetManagedWalletRef())) - return gsresponse.NotFound[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("invalid destination", zap.Error(err)) - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } destinationAddress, err := destinationAddress(ctx, c.deps, dest) if err != nil { c.deps.Logger.Warn("failed to resolve destination address", zap.Error(err)) - return gsresponse.InvalidArgument[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.InvalidArgument[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } feeMoney, err := estimateNetworkFee(ctx, c.deps.Logger, networkCfg, sourceWallet, destinationAddress, amount) if err != nil { c.deps.Logger.Warn("fee estimation failed", zap.Error(err)) - return gsresponse.Auto[gatewayv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.EstimateTransferFeeResponse](c.deps.Logger, mservice.ChainGateway, err) } - resp := &gatewayv1.EstimateTransferFeeResponse{ + resp := &chainv1.EstimateTransferFeeResponse{ NetworkFee: feeMoney, EstimationContext: "erc20_transfer", } diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/get.go b/api/gateway/chain/internal/service/gateway/commands/transfer/get.go similarity index 53% rename from api/chain/gateway/internal/service/gateway/commands/transfer/get.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/get.go index 42bdaa0..da47451 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/get.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/get.go @@ -8,7 +8,7 @@ import ( "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -20,28 +20,28 @@ func NewGetTransfer(deps Deps) *getTransferCommand { return &getTransferCommand{deps: deps} } -func (c *getTransferCommand) Execute(ctx context.Context, req *gatewayv1.GetTransferRequest) gsresponse.Responder[gatewayv1.GetTransferResponse] { +func (c *getTransferCommand) Execute(ctx context.Context, req *chainv1.GetTransferRequest) gsresponse.Responder[chainv1.GetTransferResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) + return gsresponse.InvalidArgument[chainv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) } transferRef := strings.TrimSpace(req.GetTransferRef()) if transferRef == "" { c.deps.Logger.Warn("transfer_ref missing") - return gsresponse.InvalidArgument[gatewayv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("transfer_ref is required")) + return gsresponse.InvalidArgument[chainv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("transfer_ref is required")) } transfer, err := c.deps.Storage.Transfers().Get(ctx, transferRef) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("not found", zap.String("transfer_ref", transferRef)) - return gsresponse.NotFound[gatewayv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("storage get failed", zap.Error(err), zap.String("transfer_ref", transferRef)) - return gsresponse.Auto[gatewayv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.GetTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } - return gsresponse.Success(&gatewayv1.GetTransferResponse{Transfer: toProtoTransfer(transfer)}) + return gsresponse.Success(&chainv1.GetTransferResponse{Transfer: toProtoTransfer(transfer)}) } diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/list.go b/api/gateway/chain/internal/service/gateway/commands/transfer/list.go similarity index 70% rename from api/chain/gateway/internal/service/gateway/commands/transfer/list.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/list.go index 18598a2..f88be23 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/list.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/list.go @@ -4,12 +4,12 @@ import ( "context" "strings" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -21,10 +21,10 @@ func NewListTransfers(deps Deps) *listTransfersCommand { return &listTransfersCommand{deps: deps} } -func (c *listTransfersCommand) Execute(ctx context.Context, req *gatewayv1.ListTransfersRequest) gsresponse.Responder[gatewayv1.ListTransfersResponse] { +func (c *listTransfersCommand) Execute(ctx context.Context, req *chainv1.ListTransfersRequest) gsresponse.Responder[chainv1.ListTransfersResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.ListTransfersResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.ListTransfersResponse](c.deps.Logger, mservice.ChainGateway, err) } filter := model.TransferFilter{} if req != nil { @@ -42,15 +42,15 @@ func (c *listTransfersCommand) Execute(ctx context.Context, req *gatewayv1.ListT result, err := c.deps.Storage.Transfers().List(ctx, filter) if err != nil { c.deps.Logger.Warn("storage list failed", zap.Error(err)) - return gsresponse.Auto[gatewayv1.ListTransfersResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.ListTransfersResponse](c.deps.Logger, mservice.ChainGateway, err) } - protoTransfers := make([]*gatewayv1.Transfer, 0, len(result.Items)) + protoTransfers := make([]*chainv1.Transfer, 0, len(result.Items)) for _, transfer := range result.Items { protoTransfers = append(protoTransfers, toProtoTransfer(transfer)) } - resp := &gatewayv1.ListTransfersResponse{ + resp := &chainv1.ListTransfersResponse{ Transfers: protoTransfers, Page: &paginationv1.CursorPageResponse{NextCursor: result.NextCursor}, } diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/proto.go b/api/gateway/chain/internal/service/gateway/commands/transfer/proto.go similarity index 62% rename from api/chain/gateway/internal/service/gateway/commands/transfer/proto.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/proto.go index dc6b3c2..ac63997 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/proto.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/proto.go @@ -1,40 +1,40 @@ package transfer import ( - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "google.golang.org/protobuf/types/known/timestamppb" ) -func toProtoTransfer(transfer *model.Transfer) *gatewayv1.Transfer { +func toProtoTransfer(transfer *model.Transfer) *chainv1.Transfer { if transfer == nil { return nil } - destination := &gatewayv1.TransferDestination{} + destination := &chainv1.TransferDestination{} if transfer.Destination.ManagedWalletRef != "" { - destination.Destination = &gatewayv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: transfer.Destination.ManagedWalletRef} + destination.Destination = &chainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: transfer.Destination.ManagedWalletRef} } else if transfer.Destination.ExternalAddress != "" { - destination.Destination = &gatewayv1.TransferDestination_ExternalAddress{ExternalAddress: transfer.Destination.ExternalAddress} + destination.Destination = &chainv1.TransferDestination_ExternalAddress{ExternalAddress: transfer.Destination.ExternalAddress} } destination.Memo = transfer.Destination.Memo - protoFees := make([]*gatewayv1.ServiceFeeBreakdown, 0, len(transfer.Fees)) + protoFees := make([]*chainv1.ServiceFeeBreakdown, 0, len(transfer.Fees)) for _, fee := range transfer.Fees { - protoFees = append(protoFees, &gatewayv1.ServiceFeeBreakdown{ + protoFees = append(protoFees, &chainv1.ServiceFeeBreakdown{ FeeCode: fee.FeeCode, Amount: shared.CloneMoney(fee.Amount), Description: fee.Description, }) } - asset := &gatewayv1.Asset{ + asset := &chainv1.Asset{ Chain: shared.ChainEnumFromName(transfer.Network), TokenSymbol: transfer.TokenSymbol, ContractAddress: transfer.ContractAddress, } - return &gatewayv1.Transfer{ + return &chainv1.Transfer{ TransferRef: transfer.TransferRef, IdempotencyKey: transfer.IdempotencyKey, OrganizationRef: transfer.OrganizationRef, diff --git a/api/chain/gateway/internal/service/gateway/commands/transfer/submit.go b/api/gateway/chain/internal/service/gateway/commands/transfer/submit.go similarity index 59% rename from api/chain/gateway/internal/service/gateway/commands/transfer/submit.go rename to api/gateway/chain/internal/service/gateway/commands/transfer/submit.go index 4088601..e9f8151 100644 --- a/api/chain/gateway/internal/service/gateway/commands/transfer/submit.go +++ b/api/gateway/chain/internal/service/gateway/commands/transfer/submit.go @@ -6,12 +6,12 @@ import ( "strings" "github.com/shopspring/decimal" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -23,91 +23,91 @@ func NewSubmitTransfer(deps Deps) *submitTransferCommand { return &submitTransferCommand{deps: deps} } -func (c *submitTransferCommand) Execute(ctx context.Context, req *gatewayv1.SubmitTransferRequest) gsresponse.Responder[gatewayv1.SubmitTransferResponse] { +func (c *submitTransferCommand) Execute(ctx context.Context, req *chainv1.SubmitTransferRequest) gsresponse.Responder[chainv1.SubmitTransferResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) } idempotencyKey := strings.TrimSpace(req.GetIdempotencyKey()) if idempotencyKey == "" { c.deps.Logger.Warn("missing idempotency key") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("idempotency_key is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("idempotency_key is required")) } organizationRef := strings.TrimSpace(req.GetOrganizationRef()) if organizationRef == "" { c.deps.Logger.Warn("missing organization ref") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref is required")) } sourceWalletRef := strings.TrimSpace(req.GetSourceWalletRef()) if sourceWalletRef == "" { c.deps.Logger.Warn("missing source wallet ref") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("source_wallet_ref is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("source_wallet_ref is required")) } amount := req.GetAmount() if amount == nil { c.deps.Logger.Warn("missing amount") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount is required")) } amountCurrency := strings.ToUpper(strings.TrimSpace(amount.GetCurrency())) if amountCurrency == "" { c.deps.Logger.Warn("missing amount currency") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount.currency is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount.currency is required")) } amountValue := strings.TrimSpace(amount.GetAmount()) if amountValue == "" { c.deps.Logger.Warn("missing amount value") - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount.amount is required")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount.amount is required")) } sourceWallet, err := c.deps.Storage.Wallets().Get(ctx, sourceWalletRef) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("source wallet not found", zap.String("source_wallet_ref", sourceWalletRef)) - return gsresponse.NotFound[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("storage get wallet failed", zap.Error(err), zap.String("source_wallet_ref", sourceWalletRef)) - return gsresponse.Auto[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } if !strings.EqualFold(sourceWallet.OrganizationRef, organizationRef) { c.deps.Logger.Warn("organization mismatch", zap.String("wallet_org", sourceWallet.OrganizationRef), zap.String("req_org", organizationRef)) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref mismatch with wallet")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref mismatch with wallet")) } networkKey := strings.ToLower(strings.TrimSpace(sourceWallet.Network)) networkCfg, ok := c.deps.Networks[networkKey] if !ok { c.deps.Logger.Warn("unsupported chain", zap.String("network", networkKey)) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain for wallet")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain for wallet")) } destination, err := resolveDestination(ctx, c.deps, req.GetDestination(), sourceWallet) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("destination not found", zap.String("destination_wallet_ref", req.GetDestination().GetManagedWalletRef())) - return gsresponse.NotFound[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("invalid destination", zap.Error(err)) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } fees, feeSum, err := convertFees(req.GetFees(), amountCurrency) if err != nil { c.deps.Logger.Warn("fee conversion failed", zap.Error(err)) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } amountDec, err := decimal.NewFromString(amountValue) if err != nil { c.deps.Logger.Warn("invalid amount", zap.Error(err)) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("invalid amount")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("invalid amount")) } netDec := amountDec.Sub(feeSum) if netDec.IsNegative() { c.deps.Logger.Warn("fees exceed amount", zap.String("amount", amountValue), zap.String("fee_sum", feeSum.String())) - return gsresponse.InvalidArgument[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("fees exceed amount")) + return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("fees exceed amount")) } netAmount := shared.CloneMoney(amount) @@ -134,15 +134,15 @@ func (c *submitTransferCommand) Execute(ctx context.Context, req *gatewayv1.Subm if err != nil { if errors.Is(err, merrors.ErrDataConflict) { c.deps.Logger.Debug("transfer already exists", zap.String("transfer_ref", transfer.TransferRef), zap.String("idempotency_key", idempotencyKey)) - return gsresponse.Success(&gatewayv1.SubmitTransferResponse{Transfer: toProtoTransfer(saved)}) + return gsresponse.Success(&chainv1.SubmitTransferResponse{Transfer: toProtoTransfer(saved)}) } c.deps.Logger.Warn("storage create failed", zap.Error(err), zap.String("transfer_ref", transfer.TransferRef)) - return gsresponse.Auto[gatewayv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, err) } if c.deps.LaunchExecution != nil { c.deps.LaunchExecution(saved.TransferRef, sourceWalletRef, networkCfg) } - return gsresponse.Success(&gatewayv1.SubmitTransferResponse{Transfer: toProtoTransfer(saved)}) + return gsresponse.Success(&chainv1.SubmitTransferResponse{Transfer: toProtoTransfer(saved)}) } diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/balance.go b/api/gateway/chain/internal/service/gateway/commands/wallet/balance.go similarity index 59% rename from api/chain/gateway/internal/service/gateway/commands/wallet/balance.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/balance.go index 40a7ecd..48e9037 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/balance.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/balance.go @@ -8,8 +8,8 @@ import ( "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -22,28 +22,28 @@ func NewGetWalletBalance(deps Deps) *getWalletBalanceCommand { return &getWalletBalanceCommand{deps: deps} } -func (c *getWalletBalanceCommand) Execute(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) gsresponse.Responder[gatewayv1.GetWalletBalanceResponse] { +func (c *getWalletBalanceCommand) Execute(ctx context.Context, req *chainv1.GetWalletBalanceRequest) gsresponse.Responder[chainv1.GetWalletBalanceResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) + return gsresponse.InvalidArgument[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) } walletRef := strings.TrimSpace(req.GetWalletRef()) if walletRef == "" { c.deps.Logger.Warn("wallet_ref missing") - return gsresponse.InvalidArgument[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("wallet_ref is required")) + return gsresponse.InvalidArgument[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("wallet_ref is required")) } wallet, err := c.deps.Storage.Wallets().Get(ctx, walletRef) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("not found", zap.String("wallet_ref", walletRef)) - return gsresponse.NotFound[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("storage get failed", zap.Error(err), zap.String("wallet_ref", walletRef)) - return gsresponse.Auto[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) } balance, chainErr := onChainWalletBalance(ctx, c.deps, wallet) @@ -53,22 +53,22 @@ func (c *getWalletBalanceCommand) Execute(ctx context.Context, req *gatewayv1.Ge if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("stored balance not found", zap.String("wallet_ref", walletRef)) - return gsresponse.NotFound[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) } - return gsresponse.Auto[gatewayv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.GetWalletBalanceResponse](c.deps.Logger, mservice.ChainGateway, err) } - return gsresponse.Success(&gatewayv1.GetWalletBalanceResponse{Balance: toProtoWalletBalance(stored)}) + return gsresponse.Success(&chainv1.GetWalletBalanceResponse{Balance: toProtoWalletBalance(stored)}) } - return gsresponse.Success(&gatewayv1.GetWalletBalanceResponse{Balance: onChainBalanceToProto(balance)}) + return gsresponse.Success(&chainv1.GetWalletBalanceResponse{Balance: onChainBalanceToProto(balance)}) } -func onChainBalanceToProto(balance *moneyv1.Money) *gatewayv1.WalletBalance { +func onChainBalanceToProto(balance *moneyv1.Money) *chainv1.WalletBalance { if balance == nil { return nil } zero := &moneyv1.Money{Currency: balance.Currency, Amount: "0"} - return &gatewayv1.WalletBalance{ + return &chainv1.WalletBalance{ Available: balance, PendingInbound: zero, PendingOutbound: zero, diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/create.go b/api/gateway/chain/internal/service/gateway/commands/wallet/create.go similarity index 55% rename from api/chain/gateway/internal/service/gateway/commands/wallet/create.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/create.go index 3d0651e..90ce29b 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/create.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/create.go @@ -5,12 +5,12 @@ import ( "errors" "strings" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -22,77 +22,77 @@ func NewCreateManagedWallet(deps Deps) *createManagedWalletCommand { return &createManagedWalletCommand{deps: deps} } -func (c *createManagedWalletCommand) Execute(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) gsresponse.Responder[gatewayv1.CreateManagedWalletResponse] { +func (c *createManagedWalletCommand) Execute(ctx context.Context, req *chainv1.CreateManagedWalletRequest) gsresponse.Responder[chainv1.CreateManagedWalletResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) } idempotencyKey := strings.TrimSpace(req.GetIdempotencyKey()) if idempotencyKey == "" { c.deps.Logger.Warn("missing idempotency key") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("idempotency_key is required")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("idempotency_key is required")) } organizationRef := strings.TrimSpace(req.GetOrganizationRef()) if organizationRef == "" { c.deps.Logger.Warn("missing organization ref") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref is required")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("organization_ref is required")) } ownerRef := strings.TrimSpace(req.GetOwnerRef()) if ownerRef == "" { c.deps.Logger.Warn("missing owner ref") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("owner_ref is required")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("owner_ref is required")) } asset := req.GetAsset() if asset == nil { c.deps.Logger.Warn("missing asset") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("asset is required")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("asset is required")) } chainKey, _ := shared.ChainKeyFromEnum(asset.GetChain()) if chainKey == "" { c.deps.Logger.Warn("unsupported chain", zap.Any("chain", asset.GetChain())) - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain")) } networkCfg, ok := c.deps.Networks[chainKey] if !ok { c.deps.Logger.Warn("unsupported chain in config", zap.String("chain", chainKey)) - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported chain")) } tokenSymbol := strings.ToUpper(strings.TrimSpace(asset.GetTokenSymbol())) if tokenSymbol == "" { c.deps.Logger.Warn("missing token symbol") - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("asset.token_symbol is required")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("asset.token_symbol is required")) } contractAddress := strings.ToLower(strings.TrimSpace(asset.GetContractAddress())) if contractAddress == "" { contractAddress = shared.ResolveContractAddress(networkCfg.TokenConfigs, tokenSymbol) if contractAddress == "" { c.deps.Logger.Warn("unsupported token", zap.String("token", tokenSymbol), zap.String("chain", chainKey)) - return gsresponse.InvalidArgument[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported token for chain")) + return gsresponse.InvalidArgument[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("unsupported token for chain")) } } walletRef := shared.GenerateWalletRef() if c.deps.KeyManager == nil { c.deps.Logger.Warn("key manager missing") - return gsresponse.Internal[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.Internal("key manager not configured")) + return gsresponse.Internal[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.Internal("key manager not configured")) } keyInfo, err := c.deps.KeyManager.CreateManagedWalletKey(ctx, walletRef, chainKey) if err != nil { c.deps.Logger.Warn("key manager error", zap.Error(err)) - return gsresponse.Auto[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } if keyInfo == nil || strings.TrimSpace(keyInfo.Address) == "" { c.deps.Logger.Warn("key manager returned empty address") - return gsresponse.Internal[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.Internal("key manager returned empty address")) + return gsresponse.Internal[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.Internal("key manager returned empty address")) } wallet := &model.ManagedWallet{ @@ -113,11 +113,11 @@ func (c *createManagedWalletCommand) Execute(ctx context.Context, req *gatewayv1 if err != nil { if errors.Is(err, merrors.ErrDataConflict) { c.deps.Logger.Debug("wallet already exists", zap.String("wallet_ref", walletRef), zap.String("idempotency_key", idempotencyKey)) - return gsresponse.Success(&gatewayv1.CreateManagedWalletResponse{Wallet: toProtoManagedWallet(created)}) + return gsresponse.Success(&chainv1.CreateManagedWalletResponse{Wallet: toProtoManagedWallet(created)}) } c.deps.Logger.Warn("storage create failed", zap.Error(err), zap.String("wallet_ref", walletRef)) - return gsresponse.Auto[gatewayv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.CreateManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } - return gsresponse.Success(&gatewayv1.CreateManagedWalletResponse{Wallet: toProtoManagedWallet(created)}) + return gsresponse.Success(&chainv1.CreateManagedWalletResponse{Wallet: toProtoManagedWallet(created)}) } diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/deps.go b/api/gateway/chain/internal/service/gateway/commands/wallet/deps.go similarity index 70% rename from api/chain/gateway/internal/service/gateway/commands/wallet/deps.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/deps.go index 7fa72e1..2508990 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/deps.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/deps.go @@ -3,9 +3,9 @@ package wallet import ( "context" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage" "github.com/tech/sendico/pkg/mlogger" ) diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/get.go b/api/gateway/chain/internal/service/gateway/commands/wallet/get.go similarity index 55% rename from api/chain/gateway/internal/service/gateway/commands/wallet/get.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/get.go index 44e1b7c..c4d9106 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/get.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/get.go @@ -8,7 +8,7 @@ import ( "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -20,28 +20,28 @@ func NewGetManagedWallet(deps Deps) *getManagedWalletCommand { return &getManagedWalletCommand{deps: deps} } -func (c *getManagedWalletCommand) Execute(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) gsresponse.Responder[gatewayv1.GetManagedWalletResponse] { +func (c *getManagedWalletCommand) Execute(ctx context.Context, req *chainv1.GetManagedWalletRequest) gsresponse.Responder[chainv1.GetManagedWalletResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } if req == nil { c.deps.Logger.Warn("nil request") - return gsresponse.InvalidArgument[gatewayv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) + return gsresponse.InvalidArgument[chainv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("nil request")) } walletRef := strings.TrimSpace(req.GetWalletRef()) if walletRef == "" { c.deps.Logger.Warn("wallet_ref missing") - return gsresponse.InvalidArgument[gatewayv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("wallet_ref is required")) + return gsresponse.InvalidArgument[chainv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("wallet_ref is required")) } wallet, err := c.deps.Storage.Wallets().Get(ctx, walletRef) if err != nil { if errors.Is(err, merrors.ErrNoData) { c.deps.Logger.Warn("not found", zap.String("wallet_ref", walletRef)) - return gsresponse.NotFound[gatewayv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.NotFound[chainv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } c.deps.Logger.Warn("storage get failed", zap.Error(err), zap.String("wallet_ref", walletRef)) - return gsresponse.Auto[gatewayv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.GetManagedWalletResponse](c.deps.Logger, mservice.ChainGateway, err) } - return gsresponse.Success(&gatewayv1.GetManagedWalletResponse{Wallet: toProtoManagedWallet(wallet)}) + return gsresponse.Success(&chainv1.GetManagedWalletResponse{Wallet: toProtoManagedWallet(wallet)}) } diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/list.go b/api/gateway/chain/internal/service/gateway/commands/wallet/list.go similarity index 70% rename from api/chain/gateway/internal/service/gateway/commands/wallet/list.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/list.go index 44fa364..04ceca8 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/list.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/list.go @@ -4,12 +4,12 @@ import ( "context" "strings" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.uber.org/zap" ) @@ -21,10 +21,10 @@ func NewListManagedWallets(deps Deps) *listManagedWalletsCommand { return &listManagedWalletsCommand{deps: deps} } -func (c *listManagedWalletsCommand) Execute(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) gsresponse.Responder[gatewayv1.ListManagedWalletsResponse] { +func (c *listManagedWalletsCommand) Execute(ctx context.Context, req *chainv1.ListManagedWalletsRequest) gsresponse.Responder[chainv1.ListManagedWalletsResponse] { if err := c.deps.EnsureRepository(ctx); err != nil { c.deps.Logger.Warn("repository unavailable", zap.Error(err)) - return gsresponse.Unavailable[gatewayv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Unavailable[chainv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err) } filter := model.ManagedWalletFilter{} if req != nil { @@ -43,15 +43,15 @@ func (c *listManagedWalletsCommand) Execute(ctx context.Context, req *gatewayv1. result, err := c.deps.Storage.Wallets().List(ctx, filter) if err != nil { c.deps.Logger.Warn("storage list failed", zap.Error(err)) - return gsresponse.Auto[gatewayv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err) + return gsresponse.Auto[chainv1.ListManagedWalletsResponse](c.deps.Logger, mservice.ChainGateway, err) } - protoWallets := make([]*gatewayv1.ManagedWallet, 0, len(result.Items)) + protoWallets := make([]*chainv1.ManagedWallet, 0, len(result.Items)) for _, wallet := range result.Items { protoWallets = append(protoWallets, toProtoManagedWallet(wallet)) } - resp := &gatewayv1.ListManagedWalletsResponse{ + resp := &chainv1.ListManagedWalletsResponse{ Wallets: protoWallets, Page: &paginationv1.CursorPageResponse{NextCursor: result.NextCursor}, } diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/onchain_balance.go b/api/gateway/chain/internal/service/gateway/commands/wallet/onchain_balance.go similarity index 98% rename from api/chain/gateway/internal/service/gateway/commands/wallet/onchain_balance.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/onchain_balance.go index 76b69b6..b889793 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/onchain_balance.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/onchain_balance.go @@ -11,7 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" "github.com/shopspring/decimal" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" ) diff --git a/api/chain/gateway/internal/service/gateway/commands/wallet/proto.go b/api/gateway/chain/internal/service/gateway/commands/wallet/proto.go similarity index 69% rename from api/chain/gateway/internal/service/gateway/commands/wallet/proto.go rename to api/gateway/chain/internal/service/gateway/commands/wallet/proto.go index a45b55f..9906e2f 100644 --- a/api/chain/gateway/internal/service/gateway/commands/wallet/proto.go +++ b/api/gateway/chain/internal/service/gateway/commands/wallet/proto.go @@ -1,22 +1,22 @@ package wallet import ( - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage/model" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage/model" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "google.golang.org/protobuf/types/known/timestamppb" ) -func toProtoManagedWallet(wallet *model.ManagedWallet) *gatewayv1.ManagedWallet { +func toProtoManagedWallet(wallet *model.ManagedWallet) *chainv1.ManagedWallet { if wallet == nil { return nil } - asset := &gatewayv1.Asset{ + asset := &chainv1.Asset{ Chain: shared.ChainEnumFromName(wallet.Network), TokenSymbol: wallet.TokenSymbol, ContractAddress: wallet.ContractAddress, } - return &gatewayv1.ManagedWallet{ + return &chainv1.ManagedWallet{ WalletRef: wallet.WalletRef, OrganizationRef: wallet.OrganizationRef, OwnerRef: wallet.OwnerRef, @@ -29,11 +29,11 @@ func toProtoManagedWallet(wallet *model.ManagedWallet) *gatewayv1.ManagedWallet } } -func toProtoWalletBalance(balance *model.WalletBalance) *gatewayv1.WalletBalance { +func toProtoWalletBalance(balance *model.WalletBalance) *chainv1.WalletBalance { if balance == nil { return nil } - return &gatewayv1.WalletBalance{ + return &chainv1.WalletBalance{ Available: shared.CloneMoney(balance.Available), PendingInbound: shared.CloneMoney(balance.PendingInbound), PendingOutbound: shared.CloneMoney(balance.PendingOutbound), diff --git a/api/chain/gateway/internal/service/gateway/executor.go b/api/gateway/chain/internal/service/gateway/executor.go similarity index 98% rename from api/chain/gateway/internal/service/gateway/executor.go rename to api/gateway/chain/internal/service/gateway/executor.go index 9140236..78a37bd 100644 --- a/api/chain/gateway/internal/service/gateway/executor.go +++ b/api/gateway/chain/internal/service/gateway/executor.go @@ -14,11 +14,11 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/shopspring/decimal" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" "go.uber.org/zap" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" ) diff --git a/api/chain/gateway/internal/service/gateway/metrics.go b/api/gateway/chain/internal/service/gateway/metrics.go similarity index 100% rename from api/chain/gateway/internal/service/gateway/metrics.go rename to api/gateway/chain/internal/service/gateway/metrics.go diff --git a/api/chain/gateway/internal/service/gateway/options.go b/api/gateway/chain/internal/service/gateway/options.go similarity index 93% rename from api/chain/gateway/internal/service/gateway/options.go rename to api/gateway/chain/internal/service/gateway/options.go index ec6282b..92ea17f 100644 --- a/api/chain/gateway/internal/service/gateway/options.go +++ b/api/gateway/chain/internal/service/gateway/options.go @@ -3,8 +3,8 @@ package gateway import ( "strings" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" clockpkg "github.com/tech/sendico/pkg/clock" ) diff --git a/api/chain/gateway/internal/service/gateway/service.go b/api/gateway/chain/internal/service/gateway/service.go similarity index 71% rename from api/chain/gateway/internal/service/gateway/service.go rename to api/gateway/chain/internal/service/gateway/service.go index ea41ce2..7d1997e 100644 --- a/api/chain/gateway/internal/service/gateway/service.go +++ b/api/gateway/chain/internal/service/gateway/service.go @@ -3,19 +3,19 @@ package gateway import ( "context" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/commands" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/commands/transfer" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/commands/wallet" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/commands" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/transfer" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/commands/wallet" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage" "github.com/tech/sendico/pkg/api/routers" "github.com/tech/sendico/pkg/api/routers/gsresponse" clockpkg "github.com/tech/sendico/pkg/clock" msg "github.com/tech/sendico/pkg/messaging" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "google.golang.org/grpc" ) @@ -42,7 +42,7 @@ type Service struct { executor TransferExecutor commands commands.Registry - gatewayv1.UnimplementedChainGatewayServiceServer + chainv1.UnimplementedChainGatewayServiceServer } // NewService constructs the chain gateway service skeleton. @@ -81,39 +81,39 @@ func NewService(logger mlogger.Logger, repo storage.Repository, producer msg.Pro // Register wires the service onto the provided gRPC router. func (s *Service) Register(router routers.GRPC) error { return router.Register(func(reg grpc.ServiceRegistrar) { - gatewayv1.RegisterChainGatewayServiceServer(reg, s) + chainv1.RegisterChainGatewayServiceServer(reg, s) }) } -func (s *Service) CreateManagedWallet(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) { +func (s *Service) CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) { return executeUnary(ctx, s, "CreateManagedWallet", s.commands.CreateManagedWallet.Execute, req) } -func (s *Service) GetManagedWallet(ctx context.Context, req *gatewayv1.GetManagedWalletRequest) (*gatewayv1.GetManagedWalletResponse, error) { +func (s *Service) GetManagedWallet(ctx context.Context, req *chainv1.GetManagedWalletRequest) (*chainv1.GetManagedWalletResponse, error) { return executeUnary(ctx, s, "GetManagedWallet", s.commands.GetManagedWallet.Execute, req) } -func (s *Service) ListManagedWallets(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) { +func (s *Service) ListManagedWallets(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) { return executeUnary(ctx, s, "ListManagedWallets", s.commands.ListManagedWallets.Execute, req) } -func (s *Service) GetWalletBalance(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) { +func (s *Service) GetWalletBalance(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) { return executeUnary(ctx, s, "GetWalletBalance", s.commands.GetWalletBalance.Execute, req) } -func (s *Service) SubmitTransfer(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) { +func (s *Service) SubmitTransfer(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) { return executeUnary(ctx, s, "SubmitTransfer", s.commands.SubmitTransfer.Execute, req) } -func (s *Service) GetTransfer(ctx context.Context, req *gatewayv1.GetTransferRequest) (*gatewayv1.GetTransferResponse, error) { +func (s *Service) GetTransfer(ctx context.Context, req *chainv1.GetTransferRequest) (*chainv1.GetTransferResponse, error) { return executeUnary(ctx, s, "GetTransfer", s.commands.GetTransfer.Execute, req) } -func (s *Service) ListTransfers(ctx context.Context, req *gatewayv1.ListTransfersRequest) (*gatewayv1.ListTransfersResponse, error) { +func (s *Service) ListTransfers(ctx context.Context, req *chainv1.ListTransfersRequest) (*chainv1.ListTransfersResponse, error) { return executeUnary(ctx, s, "ListTransfers", s.commands.ListTransfers.Execute, req) } -func (s *Service) EstimateTransferFee(ctx context.Context, req *gatewayv1.EstimateTransferFeeRequest) (*gatewayv1.EstimateTransferFeeResponse, error) { +func (s *Service) EstimateTransferFee(ctx context.Context, req *chainv1.EstimateTransferFeeRequest) (*chainv1.EstimateTransferFeeResponse, error) { return executeUnary(ctx, s, "EstimateTransferFee", s.commands.EstimateTransfer.Execute, req) } diff --git a/api/chain/gateway/internal/service/gateway/service_test.go b/api/gateway/chain/internal/service/gateway/service_test.go similarity index 91% rename from api/chain/gateway/internal/service/gateway/service_test.go rename to api/gateway/chain/internal/service/gateway/service_test.go index 58b9829..df7071a 100644 --- a/api/chain/gateway/internal/service/gateway/service_test.go +++ b/api/gateway/chain/internal/service/gateway/service_test.go @@ -11,16 +11,16 @@ import ( "time" "github.com/stretchr/testify/require" - igatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + ichainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/tech/sendico/chain/gateway/internal/keymanager" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" - "github.com/tech/sendico/chain/gateway/storage" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/internal/keymanager" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/storage" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" @@ -41,12 +41,12 @@ func TestCreateManagedWallet_Idempotent(t *testing.T) { svc, repo := newTestService(t) ctx := context.Background() - req := &igatewayv1.CreateManagedWalletRequest{ + req := &ichainv1.CreateManagedWalletRequest{ IdempotencyKey: "idem-1", OrganizationRef: "org-1", OwnerRef: "owner-1", - Asset: &igatewayv1.Asset{ - Chain: igatewayv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, + Asset: &ichainv1.Asset{ + Chain: ichainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, TokenSymbol: "USDC", }, } @@ -70,12 +70,12 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) { ctx := context.Background() // create source wallet - srcResp, err := svc.CreateManagedWallet(ctx, &igatewayv1.CreateManagedWalletRequest{ + srcResp, err := svc.CreateManagedWallet(ctx, &ichainv1.CreateManagedWalletRequest{ IdempotencyKey: "idem-src", OrganizationRef: "org-1", OwnerRef: "owner-1", - Asset: &igatewayv1.Asset{ - Chain: igatewayv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, + Asset: &ichainv1.Asset{ + Chain: ichainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, TokenSymbol: "USDC", }, }) @@ -83,27 +83,27 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) { srcRef := srcResp.GetWallet().GetWalletRef() // destination wallet - dstResp, err := svc.CreateManagedWallet(ctx, &igatewayv1.CreateManagedWalletRequest{ + dstResp, err := svc.CreateManagedWallet(ctx, &ichainv1.CreateManagedWalletRequest{ IdempotencyKey: "idem-dst", OrganizationRef: "org-1", OwnerRef: "owner-2", - Asset: &igatewayv1.Asset{ - Chain: igatewayv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, + Asset: &ichainv1.Asset{ + Chain: ichainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, TokenSymbol: "USDC", }, }) require.NoError(t, err) dstRef := dstResp.GetWallet().GetWalletRef() - transferResp, err := svc.SubmitTransfer(ctx, &igatewayv1.SubmitTransferRequest{ + transferResp, err := svc.SubmitTransfer(ctx, &ichainv1.SubmitTransferRequest{ IdempotencyKey: "transfer-1", OrganizationRef: "org-1", SourceWalletRef: srcRef, - Destination: &igatewayv1.TransferDestination{ - Destination: &igatewayv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: dstRef}, + Destination: &ichainv1.TransferDestination{ + Destination: &ichainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: dstRef}, }, Amount: &moneyv1.Money{Currency: "USDC", Amount: "100"}, - Fees: []*igatewayv1.ServiceFeeBreakdown{ + Fees: []*ichainv1.ServiceFeeBreakdown{ { FeeCode: "service", Amount: &moneyv1.Money{Currency: "USDC", Amount: "5"}, @@ -119,12 +119,12 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) { require.Equal(t, model.TransferStatusPending, stored.Status) // GetTransfer - getResp, err := svc.GetTransfer(ctx, &igatewayv1.GetTransferRequest{TransferRef: stored.TransferRef}) + getResp, err := svc.GetTransfer(ctx, &ichainv1.GetTransferRequest{TransferRef: stored.TransferRef}) require.NoError(t, err) require.Equal(t, stored.TransferRef, getResp.GetTransfer().GetTransferRef()) // ListTransfers - listResp, err := svc.ListTransfers(ctx, &igatewayv1.ListTransfersRequest{ + listResp, err := svc.ListTransfers(ctx, &ichainv1.ListTransfersRequest{ SourceWalletRef: srcRef, Page: &paginationv1.CursorPageRequest{Limit: 10}, }) @@ -137,7 +137,7 @@ func TestGetWalletBalance_NotFound(t *testing.T) { svc, _ := newTestService(t) ctx := context.Background() - _, err := svc.GetWalletBalance(ctx, &igatewayv1.GetWalletBalanceRequest{WalletRef: "missing"}) + _, err := svc.GetWalletBalance(ctx, &ichainv1.GetWalletBalanceRequest{WalletRef: "missing"}) require.Error(t, err) st, _ := status.FromError(err) require.Equal(t, codes.NotFound, st.Code()) diff --git a/api/chain/gateway/internal/service/gateway/shared/helpers.go b/api/gateway/chain/internal/service/gateway/shared/helpers.go similarity index 60% rename from api/chain/gateway/internal/service/gateway/shared/helpers.go rename to api/gateway/chain/internal/service/gateway/shared/helpers.go index cc4c193..38f7b04 100644 --- a/api/chain/gateway/internal/service/gateway/shared/helpers.go +++ b/api/gateway/chain/internal/service/gateway/shared/helpers.go @@ -3,9 +3,9 @@ package shared import ( "strings" - "github.com/tech/sendico/chain/gateway/storage/model" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + "github.com/tech/sendico/gateway/chain/storage/model" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -48,74 +48,74 @@ func GenerateTransferRef() string { return primitive.NewObjectID().Hex() } -func ChainKeyFromEnum(chain gatewayv1.ChainNetwork) (string, gatewayv1.ChainNetwork) { - if name, ok := gatewayv1.ChainNetwork_name[int32(chain)]; ok { +func ChainKeyFromEnum(chain chainv1.ChainNetwork) (string, chainv1.ChainNetwork) { + if name, ok := chainv1.ChainNetwork_name[int32(chain)]; ok { key := strings.ToLower(strings.TrimPrefix(name, "CHAIN_NETWORK_")) return key, chain } - return "", gatewayv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED + return "", chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED } -func ChainEnumFromName(name string) gatewayv1.ChainNetwork { +func ChainEnumFromName(name string) chainv1.ChainNetwork { if name == "" { - return gatewayv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED + return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED } upper := strings.ToUpper(strings.ReplaceAll(strings.ReplaceAll(name, " ", "_"), "-", "_")) key := "CHAIN_NETWORK_" + upper - if val, ok := gatewayv1.ChainNetwork_value[key]; ok { - return gatewayv1.ChainNetwork(val) + if val, ok := chainv1.ChainNetwork_value[key]; ok { + return chainv1.ChainNetwork(val) } - return gatewayv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED + return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED } -func ManagedWalletStatusToProto(status model.ManagedWalletStatus) gatewayv1.ManagedWalletStatus { +func ManagedWalletStatusToProto(status model.ManagedWalletStatus) chainv1.ManagedWalletStatus { switch status { case model.ManagedWalletStatusActive: - return gatewayv1.ManagedWalletStatus_MANAGED_WALLET_ACTIVE + return chainv1.ManagedWalletStatus_MANAGED_WALLET_ACTIVE case model.ManagedWalletStatusSuspended: - return gatewayv1.ManagedWalletStatus_MANAGED_WALLET_SUSPENDED + return chainv1.ManagedWalletStatus_MANAGED_WALLET_SUSPENDED case model.ManagedWalletStatusClosed: - return gatewayv1.ManagedWalletStatus_MANAGED_WALLET_CLOSED + return chainv1.ManagedWalletStatus_MANAGED_WALLET_CLOSED default: - return gatewayv1.ManagedWalletStatus_MANAGED_WALLET_STATUS_UNSPECIFIED + return chainv1.ManagedWalletStatus_MANAGED_WALLET_STATUS_UNSPECIFIED } } -func TransferStatusToModel(status gatewayv1.TransferStatus) model.TransferStatus { +func TransferStatusToModel(status chainv1.TransferStatus) model.TransferStatus { switch status { - case gatewayv1.TransferStatus_TRANSFER_PENDING: + case chainv1.TransferStatus_TRANSFER_PENDING: return model.TransferStatusPending - case gatewayv1.TransferStatus_TRANSFER_SIGNING: + case chainv1.TransferStatus_TRANSFER_SIGNING: return model.TransferStatusSigning - case gatewayv1.TransferStatus_TRANSFER_SUBMITTED: + case chainv1.TransferStatus_TRANSFER_SUBMITTED: return model.TransferStatusSubmitted - case gatewayv1.TransferStatus_TRANSFER_CONFIRMED: + case chainv1.TransferStatus_TRANSFER_CONFIRMED: return model.TransferStatusConfirmed - case gatewayv1.TransferStatus_TRANSFER_FAILED: + case chainv1.TransferStatus_TRANSFER_FAILED: return model.TransferStatusFailed - case gatewayv1.TransferStatus_TRANSFER_CANCELLED: + case chainv1.TransferStatus_TRANSFER_CANCELLED: return model.TransferStatusCancelled default: return "" } } -func TransferStatusToProto(status model.TransferStatus) gatewayv1.TransferStatus { +func TransferStatusToProto(status model.TransferStatus) chainv1.TransferStatus { switch status { case model.TransferStatusPending: - return gatewayv1.TransferStatus_TRANSFER_PENDING + return chainv1.TransferStatus_TRANSFER_PENDING case model.TransferStatusSigning: - return gatewayv1.TransferStatus_TRANSFER_SIGNING + return chainv1.TransferStatus_TRANSFER_SIGNING case model.TransferStatusSubmitted: - return gatewayv1.TransferStatus_TRANSFER_SUBMITTED + return chainv1.TransferStatus_TRANSFER_SUBMITTED case model.TransferStatusConfirmed: - return gatewayv1.TransferStatus_TRANSFER_CONFIRMED + return chainv1.TransferStatus_TRANSFER_CONFIRMED case model.TransferStatusFailed: - return gatewayv1.TransferStatus_TRANSFER_FAILED + return chainv1.TransferStatus_TRANSFER_FAILED case model.TransferStatusCancelled: - return gatewayv1.TransferStatus_TRANSFER_CANCELLED + return chainv1.TransferStatus_TRANSFER_CANCELLED default: - return gatewayv1.TransferStatus_TRANSFER_STATUS_UNSPECIFIED + return chainv1.TransferStatus_TRANSFER_STATUS_UNSPECIFIED } } diff --git a/api/chain/gateway/internal/service/gateway/transfer_execution.go b/api/gateway/chain/internal/service/gateway/transfer_execution.go similarity index 96% rename from api/chain/gateway/internal/service/gateway/transfer_execution.go rename to api/gateway/chain/internal/service/gateway/transfer_execution.go index e160212..f581411 100644 --- a/api/chain/gateway/internal/service/gateway/transfer_execution.go +++ b/api/gateway/chain/internal/service/gateway/transfer_execution.go @@ -7,11 +7,11 @@ import ( "time" "github.com/ethereum/go-ethereum/core/types" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/merrors" "go.uber.org/zap" - "github.com/tech/sendico/chain/gateway/internal/service/gateway/shared" + "github.com/tech/sendico/gateway/chain/internal/service/gateway/shared" ) func (s *Service) launchTransferExecution(transferRef, sourceWalletRef string, network shared.Network) { diff --git a/api/chain/gateway/main.go b/api/gateway/chain/main.go similarity index 74% rename from api/chain/gateway/main.go rename to api/gateway/chain/main.go index fe8b96a..cea9801 100644 --- a/api/chain/gateway/main.go +++ b/api/gateway/chain/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/tech/sendico/chain/gateway/internal/appversion" - si "github.com/tech/sendico/chain/gateway/internal/server" + "github.com/tech/sendico/gateway/chain/internal/appversion" + si "github.com/tech/sendico/gateway/chain/internal/server" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/server" smain "github.com/tech/sendico/pkg/server/main" diff --git a/api/chain/gateway/storage/model/deposit.go b/api/gateway/chain/storage/model/deposit.go similarity index 100% rename from api/chain/gateway/storage/model/deposit.go rename to api/gateway/chain/storage/model/deposit.go diff --git a/api/chain/gateway/storage/model/transfer.go b/api/gateway/chain/storage/model/transfer.go similarity index 100% rename from api/chain/gateway/storage/model/transfer.go rename to api/gateway/chain/storage/model/transfer.go diff --git a/api/chain/gateway/storage/model/wallet.go b/api/gateway/chain/storage/model/wallet.go similarity index 100% rename from api/chain/gateway/storage/model/wallet.go rename to api/gateway/chain/storage/model/wallet.go diff --git a/api/chain/gateway/storage/mongo/repository.go b/api/gateway/chain/storage/mongo/repository.go similarity index 95% rename from api/chain/gateway/storage/mongo/repository.go rename to api/gateway/chain/storage/mongo/repository.go index 0bc4be8..659973d 100644 --- a/api/chain/gateway/storage/mongo/repository.go +++ b/api/gateway/chain/storage/mongo/repository.go @@ -4,8 +4,8 @@ import ( "context" "time" - "github.com/tech/sendico/chain/gateway/storage" - "github.com/tech/sendico/chain/gateway/storage/mongo/store" + "github.com/tech/sendico/gateway/chain/storage" + "github.com/tech/sendico/gateway/chain/storage/mongo/store" "github.com/tech/sendico/pkg/db" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" diff --git a/api/chain/gateway/storage/mongo/store/deposits.go b/api/gateway/chain/storage/mongo/store/deposits.go similarity index 97% rename from api/chain/gateway/storage/mongo/store/deposits.go rename to api/gateway/chain/storage/mongo/store/deposits.go index a3f0f5c..fe4951d 100644 --- a/api/chain/gateway/storage/mongo/store/deposits.go +++ b/api/gateway/chain/storage/mongo/store/deposits.go @@ -6,8 +6,8 @@ import ( "strings" "time" - "github.com/tech/sendico/chain/gateway/storage" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/db/repository" ri "github.com/tech/sendico/pkg/db/repository/index" "github.com/tech/sendico/pkg/merrors" diff --git a/api/chain/gateway/storage/mongo/store/transfers.go b/api/gateway/chain/storage/mongo/store/transfers.go similarity index 98% rename from api/chain/gateway/storage/mongo/store/transfers.go rename to api/gateway/chain/storage/mongo/store/transfers.go index d4d457c..5c685d2 100644 --- a/api/chain/gateway/storage/mongo/store/transfers.go +++ b/api/gateway/chain/storage/mongo/store/transfers.go @@ -6,8 +6,8 @@ import ( "strings" "time" - "github.com/tech/sendico/chain/gateway/storage" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/db/repository" "github.com/tech/sendico/pkg/db/repository/builder" ri "github.com/tech/sendico/pkg/db/repository/index" diff --git a/api/chain/gateway/storage/mongo/store/wallets.go b/api/gateway/chain/storage/mongo/store/wallets.go similarity index 98% rename from api/chain/gateway/storage/mongo/store/wallets.go rename to api/gateway/chain/storage/mongo/store/wallets.go index c3f3b07..aff58a4 100644 --- a/api/chain/gateway/storage/mongo/store/wallets.go +++ b/api/gateway/chain/storage/mongo/store/wallets.go @@ -6,8 +6,8 @@ import ( "strings" "time" - "github.com/tech/sendico/chain/gateway/storage" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage" + "github.com/tech/sendico/gateway/chain/storage/model" "github.com/tech/sendico/pkg/db/repository" "github.com/tech/sendico/pkg/db/repository/builder" ri "github.com/tech/sendico/pkg/db/repository/index" diff --git a/api/chain/gateway/storage/storage.go b/api/gateway/chain/storage/storage.go similarity index 97% rename from api/chain/gateway/storage/storage.go rename to api/gateway/chain/storage/storage.go index fc3c19a..1813b19 100644 --- a/api/chain/gateway/storage/storage.go +++ b/api/gateway/chain/storage/storage.go @@ -3,7 +3,7 @@ package storage import ( "context" - "github.com/tech/sendico/chain/gateway/storage/model" + "github.com/tech/sendico/gateway/chain/storage/model" ) type storageError string diff --git a/api/ledger/client/fake.go b/api/ledger/client/fake.go index 94ebb60..dc76879 100644 --- a/api/ledger/client/fake.go +++ b/api/ledger/client/fake.go @@ -8,6 +8,8 @@ import ( // Fake implements Client for tests. type Fake struct { + CreateAccountFn func(ctx context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) + ListAccountsFn func(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error) PostCreditWithChargesFn func(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) PostDebitWithChargesFn func(ctx context.Context, req *ledgerv1.PostDebitRequest) (*ledgerv1.PostResponse, error) TransferInternalFn func(ctx context.Context, req *ledgerv1.TransferRequest) (*ledgerv1.PostResponse, error) @@ -18,6 +20,20 @@ type Fake struct { CloseFn func() error } +func (f *Fake) CreateAccount(ctx context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) { + if f.CreateAccountFn != nil { + return f.CreateAccountFn(ctx, req) + } + return &ledgerv1.CreateAccountResponse{}, nil +} + +func (f *Fake) ListAccounts(ctx context.Context, req *ledgerv1.ListAccountsRequest) (*ledgerv1.ListAccountsResponse, error) { + if f.ListAccountsFn != nil { + return f.ListAccountsFn(ctx, req) + } + return &ledgerv1.ListAccountsResponse{}, nil +} + func (f *Fake) PostCreditWithCharges(ctx context.Context, req *ledgerv1.PostCreditRequest) (*ledgerv1.PostResponse, error) { if f.PostCreditWithChargesFn != nil { return f.PostCreditWithChargesFn(ctx, req) diff --git a/api/ledger/internal/service/ledger/queries.go b/api/ledger/internal/service/ledger/queries.go index a61ea9f..bf54255 100644 --- a/api/ledger/internal/service/ledger/queries.go +++ b/api/ledger/internal/service/ledger/queries.go @@ -249,7 +249,7 @@ func (s *Service) getStatementResponder(_ context.Context, req *ledgerv1.GetStat func parseCursor(cursor string) (int, error) { decoded, err := base64.StdEncoding.DecodeString(cursor) if err != nil { - return 0, merrors.InvalidArgumentWrap(err, "invalid cursor base64 encoding") + return 0, merrors.InvalidArgumentWrap(err, "invalid base64") } parts := strings.Split(string(decoded), ":") if len(parts) != 2 || parts[0] != "offset" { @@ -257,7 +257,7 @@ func parseCursor(cursor string) (int, error) { } offset, err := strconv.Atoi(parts[1]) if err != nil { - return 0, merrors.InvalidArgumentWrap(err, "invalid cursor offset") + return 0, merrors.InvalidArgumentWrap(err, "invalid offset") } return offset, nil } diff --git a/api/notification/.gitignore b/api/notification/.gitignore index f727408..3bd5422 100644 --- a/api/notification/.gitignore +++ b/api/notification/.gitignore @@ -1 +1,2 @@ notification +.gocache diff --git a/api/payments/orchestrator/go.mod b/api/payments/orchestrator/go.mod index 280e614..f36be07 100644 --- a/api/payments/orchestrator/go.mod +++ b/api/payments/orchestrator/go.mod @@ -6,7 +6,7 @@ replace github.com/tech/sendico/pkg => ../../pkg replace github.com/tech/sendico/billing/fees => ../../billing/fees -replace github.com/tech/sendico/chain/gateway => ../../chain/gateway +replace github.com/tech/sendico/gateway/chain => ../../gateway/chain replace github.com/tech/sendico/fx/oracle => ../../fx/oracle @@ -15,8 +15,8 @@ replace github.com/tech/sendico/ledger => ../../ledger require ( github.com/prometheus/client_golang v1.23.2 github.com/shopspring/decimal v1.4.0 - github.com/tech/sendico/chain/gateway v0.0.0-00010101000000-000000000000 github.com/tech/sendico/fx/oracle v0.0.0-00010101000000-000000000000 + github.com/tech/sendico/gateway/chain v0.0.0-00010101000000-000000000000 github.com/tech/sendico/ledger v0.0.0-00010101000000-000000000000 github.com/tech/sendico/pkg v0.1.0 go.mongodb.org/mongo-driver v1.17.6 @@ -36,7 +36,7 @@ require ( github.com/go-chi/chi/v5 v5.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -59,5 +59,5 @@ require ( golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect ) diff --git a/api/payments/orchestrator/go.sum b/api/payments/orchestrator/go.sum index 1966d2a..e9646dc 100644 --- a/api/payments/orchestrator/go.sum +++ b/api/payments/orchestrator/go.sum @@ -59,8 +59,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -215,8 +215,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846 h1:Wgl1rcDNThT+Zn47YyCXOXyX/COgMTIdhJ717F0l4xk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= diff --git a/api/payments/orchestrator/internal/server/internal/serverimp.go b/api/payments/orchestrator/internal/server/internal/serverimp.go index 6280958..439733a 100644 --- a/api/payments/orchestrator/internal/server/internal/serverimp.go +++ b/api/payments/orchestrator/internal/server/internal/serverimp.go @@ -7,7 +7,7 @@ import ( "strings" "time" - chainclient "github.com/tech/sendico/chain/gateway/client" + chainclient "github.com/tech/sendico/gateway/chain/client" oracleclient "github.com/tech/sendico/fx/oracle/client" ledgerclient "github.com/tech/sendico/ledger/client" "github.com/tech/sendico/payments/orchestrator/internal/service/orchestrator" diff --git a/api/payments/orchestrator/internal/service/orchestrator/convert.go b/api/payments/orchestrator/internal/service/orchestrator/convert.go index de026af..aca4b94 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/convert.go +++ b/api/payments/orchestrator/internal/service/orchestrator/convert.go @@ -6,9 +6,9 @@ import ( "github.com/tech/sendico/payments/orchestrator/storage/model" "github.com/tech/sendico/pkg/merrors" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1" "google.golang.org/protobuf/proto" @@ -327,11 +327,11 @@ func protoFailureFromModel(code model.PaymentFailureCode) orchestratorv1.Payment } } -func cloneAsset(asset *gatewayv1.Asset) *gatewayv1.Asset { +func cloneAsset(asset *chainv1.Asset) *chainv1.Asset { if asset == nil { return nil } - return &gatewayv1.Asset{ + return &chainv1.Asset{ Chain: asset.GetChain(), TokenSymbol: asset.GetTokenSymbol(), ContractAddress: asset.GetContractAddress(), @@ -358,11 +358,11 @@ func cloneFXQuote(quote *oraclev1.Quote) *oraclev1.Quote { return nil } -func cloneNetworkEstimate(resp *gatewayv1.EstimateTransferFeeResponse) *gatewayv1.EstimateTransferFeeResponse { +func cloneNetworkEstimate(resp *chainv1.EstimateTransferFeeResponse) *chainv1.EstimateTransferFeeResponse { if resp == nil { return nil } - if cloned, ok := proto.Clone(resp).(*gatewayv1.EstimateTransferFeeResponse); ok { + if cloned, ok := proto.Clone(resp).(*chainv1.EstimateTransferFeeResponse); ok { return cloned } return nil diff --git a/api/payments/orchestrator/internal/service/orchestrator/execution.go b/api/payments/orchestrator/internal/service/orchestrator/execution.go index f8e9203..5bf91c2 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/execution.go +++ b/api/payments/orchestrator/internal/service/orchestrator/execution.go @@ -10,7 +10,7 @@ import ( "github.com/tech/sendico/payments/orchestrator/storage/model" "github.com/tech/sendico/pkg/merrors" feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1" @@ -29,7 +29,7 @@ func (s *Service) buildPaymentQuote(ctx context.Context, orgRef string, req *orc } feeTotal := extractFeeTotal(feeQuote.GetLines(), amount.GetCurrency()) - var networkFee *gatewayv1.EstimateTransferFeeResponse + var networkFee *chainv1.EstimateTransferFeeResponse if shouldEstimateNetworkFee(intent) { networkFee, err = s.estimateNetworkFee(ctx, intent) if err != nil { @@ -90,25 +90,25 @@ func (s *Service) quoteFees(ctx context.Context, orgRef string, req *orchestrato return resp, nil } -func (s *Service) estimateNetworkFee(ctx context.Context, intent *orchestratorv1.PaymentIntent) (*gatewayv1.EstimateTransferFeeResponse, error) { +func (s *Service) estimateNetworkFee(ctx context.Context, intent *orchestratorv1.PaymentIntent) (*chainv1.EstimateTransferFeeResponse, error) { if !s.gateway.available() { return nil, nil } - req := &gatewayv1.EstimateTransferFeeRequest{ + req := &chainv1.EstimateTransferFeeRequest{ Amount: cloneMoney(intent.GetAmount()), } if src := intent.GetSource().GetManagedWallet(); src != nil { req.SourceWalletRef = strings.TrimSpace(src.GetManagedWalletRef()) } if dst := intent.GetDestination().GetManagedWallet(); dst != nil { - req.Destination = &gatewayv1.TransferDestination{ - Destination: &gatewayv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: strings.TrimSpace(dst.GetManagedWalletRef())}, + req.Destination = &chainv1.TransferDestination{ + Destination: &chainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: strings.TrimSpace(dst.GetManagedWalletRef())}, } } if dst := intent.GetDestination().GetExternalChain(); dst != nil { - req.Destination = &gatewayv1.TransferDestination{ - Destination: &gatewayv1.TransferDestination_ExternalAddress{ExternalAddress: strings.TrimSpace(dst.GetAddress())}, + req.Destination = &chainv1.TransferDestination{ + Destination: &chainv1.TransferDestination_ExternalAddress{ExternalAddress: strings.TrimSpace(dst.GetAddress())}, Memo: strings.TrimSpace(dst.GetMemo()), } req.Asset = dst.GetAsset() @@ -320,7 +320,7 @@ func (s *Service) applyFX(ctx context.Context, payment *model.Payment, quote *or return nil } -func (s *Service) submitChainTransfer(ctx context.Context, payment *model.Payment, quote *orchestratorv1.PaymentQuote) (*gatewayv1.SubmitTransferResponse, error) { +func (s *Service) submitChainTransfer(ctx context.Context, payment *model.Payment, quote *orchestratorv1.PaymentQuote) (*chainv1.SubmitTransferResponse, error) { intent := payment.Intent source := intent.Source.ManagedWallet destination := intent.Destination @@ -336,7 +336,7 @@ func (s *Service) submitChainTransfer(ctx context.Context, payment *model.Paymen return nil, merrors.InvalidArgument("chain: amount is required") } fees := feeBreakdownFromQuote(quote) - req := &gatewayv1.SubmitTransferRequest{ + req := &chainv1.SubmitTransferRequest{ IdempotencyKey: payment.IdempotencyKey, OrganizationRef: payment.OrganizationRef.Hex(), SourceWalletRef: strings.TrimSpace(source.ManagedWalletRef), @@ -437,21 +437,21 @@ func hasManagedWallet(endpoint model.PaymentEndpoint) bool { return endpoint.Type == model.EndpointTypeManagedWallet && endpoint.ManagedWallet != nil && strings.TrimSpace(endpoint.ManagedWallet.ManagedWalletRef) != "" } -func toGatewayDestination(endpoint model.PaymentEndpoint) (*gatewayv1.TransferDestination, error) { +func toGatewayDestination(endpoint model.PaymentEndpoint) (*chainv1.TransferDestination, error) { switch endpoint.Type { case model.EndpointTypeManagedWallet: if endpoint.ManagedWallet == nil || strings.TrimSpace(endpoint.ManagedWallet.ManagedWalletRef) == "" { return nil, merrors.InvalidArgument("chain: destination managed wallet is required") } - return &gatewayv1.TransferDestination{ - Destination: &gatewayv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: strings.TrimSpace(endpoint.ManagedWallet.ManagedWalletRef)}, + return &chainv1.TransferDestination{ + Destination: &chainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: strings.TrimSpace(endpoint.ManagedWallet.ManagedWalletRef)}, }, nil case model.EndpointTypeExternalChain: if endpoint.ExternalChain == nil || strings.TrimSpace(endpoint.ExternalChain.Address) == "" { return nil, merrors.InvalidArgument("chain: external address is required") } - return &gatewayv1.TransferDestination{ - Destination: &gatewayv1.TransferDestination_ExternalAddress{ExternalAddress: strings.TrimSpace(endpoint.ExternalChain.Address)}, + return &chainv1.TransferDestination{ + Destination: &chainv1.TransferDestination_ExternalAddress{ExternalAddress: strings.TrimSpace(endpoint.ExternalChain.Address)}, Memo: strings.TrimSpace(endpoint.ExternalChain.Memo), }, nil default: @@ -459,7 +459,7 @@ func toGatewayDestination(endpoint model.PaymentEndpoint) (*gatewayv1.TransferDe } } -func applyTransferStatus(event *gatewayv1.TransferStatusChangedEvent, payment *model.Payment) { +func applyTransferStatus(event *chainv1.TransferStatusChangedEvent, payment *model.Payment) { if payment.Execution == nil { payment.Execution = &model.ExecutionRefs{} } @@ -473,21 +473,21 @@ func applyTransferStatus(event *gatewayv1.TransferStatusChangedEvent, payment *m reason = strings.TrimSpace(transfer.GetFailureReason()) } switch transfer.GetStatus() { - case gatewayv1.TransferStatus_TRANSFER_CONFIRMED: + case chainv1.TransferStatus_TRANSFER_CONFIRMED: payment.State = model.PaymentStateSettled payment.FailureCode = model.PaymentFailureCodeUnspecified payment.FailureReason = "" - case gatewayv1.TransferStatus_TRANSFER_FAILED: + case chainv1.TransferStatus_TRANSFER_FAILED: payment.State = model.PaymentStateFailed payment.FailureCode = model.PaymentFailureCodeChain payment.FailureReason = reason - case gatewayv1.TransferStatus_TRANSFER_CANCELLED: + case chainv1.TransferStatus_TRANSFER_CANCELLED: payment.State = model.PaymentStateCancelled payment.FailureCode = model.PaymentFailureCodePolicy payment.FailureReason = reason - case gatewayv1.TransferStatus_TRANSFER_SIGNING, - gatewayv1.TransferStatus_TRANSFER_PENDING, - gatewayv1.TransferStatus_TRANSFER_SUBMITTED: + case chainv1.TransferStatus_TRANSFER_SIGNING, + chainv1.TransferStatus_TRANSFER_PENDING, + chainv1.TransferStatus_TRANSFER_SUBMITTED: payment.State = model.PaymentStateSubmitted default: // retain previous state diff --git a/api/payments/orchestrator/internal/service/orchestrator/helpers.go b/api/payments/orchestrator/internal/service/orchestrator/helpers.go index 49f9c66..41a8240 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/helpers.go +++ b/api/payments/orchestrator/internal/service/orchestrator/helpers.go @@ -12,9 +12,9 @@ import ( "google.golang.org/protobuf/proto" feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" ) func cloneMoney(input *moneyv1.Money) *moneyv1.Money { @@ -108,7 +108,7 @@ func extractFeeTotal(lines []*feesv1.DerivedPostingLine, currency string) *money } } -func computeAggregates(base, fee *moneyv1.Money, network *gatewayv1.EstimateTransferFeeResponse) (*moneyv1.Money, *moneyv1.Money) { +func computeAggregates(base, fee *moneyv1.Money, network *chainv1.EstimateTransferFeeResponse) (*moneyv1.Money, *moneyv1.Money) { if base == nil { return nil, nil } @@ -219,12 +219,12 @@ func ledgerLineTypeFromAccounting(lineType accountingv1.PostingLineType) ledgerv } } -func feeBreakdownFromQuote(quote *orchestratorv1.PaymentQuote) []*gatewayv1.ServiceFeeBreakdown { +func feeBreakdownFromQuote(quote *orchestratorv1.PaymentQuote) []*chainv1.ServiceFeeBreakdown { if quote == nil { return nil } lines := quote.GetFeeLines() - breakdown := make([]*gatewayv1.ServiceFeeBreakdown, 0, len(lines)+1) + breakdown := make([]*chainv1.ServiceFeeBreakdown, 0, len(lines)+1) for _, line := range lines { if line == nil { continue @@ -241,7 +241,7 @@ func feeBreakdownFromQuote(quote *orchestratorv1.PaymentQuote) []*gatewayv1.Serv code = line.GetLineType().String() } desc := strings.TrimSpace(line.GetMeta()["description"]) - breakdown = append(breakdown, &gatewayv1.ServiceFeeBreakdown{ + breakdown = append(breakdown, &chainv1.ServiceFeeBreakdown{ FeeCode: code, Amount: amount, Description: desc, @@ -250,7 +250,7 @@ func feeBreakdownFromQuote(quote *orchestratorv1.PaymentQuote) []*gatewayv1.Serv if quote.GetNetworkFee() != nil && quote.GetNetworkFee().GetNetworkFee() != nil { networkAmount := cloneMoney(quote.GetNetworkFee().GetNetworkFee()) if networkAmount != nil { - breakdown = append(breakdown, &gatewayv1.ServiceFeeBreakdown{ + breakdown = append(breakdown, &chainv1.ServiceFeeBreakdown{ FeeCode: "network_fee", Amount: networkAmount, Description: strings.TrimSpace(quote.GetNetworkFee().GetEstimationContext()), diff --git a/api/payments/orchestrator/internal/service/orchestrator/options.go b/api/payments/orchestrator/internal/service/orchestrator/options.go index 63120af..de0d5f3 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/options.go +++ b/api/payments/orchestrator/internal/service/orchestrator/options.go @@ -3,7 +3,7 @@ package orchestrator import ( "time" - chainclient "github.com/tech/sendico/chain/gateway/client" + chainclient "github.com/tech/sendico/gateway/chain/client" oracleclient "github.com/tech/sendico/fx/oracle/client" ledgerclient "github.com/tech/sendico/ledger/client" clockpkg "github.com/tech/sendico/pkg/clock" diff --git a/api/payments/orchestrator/internal/service/orchestrator/service_test.go b/api/payments/orchestrator/internal/service/orchestrator/service_test.go index 7a61ada..4935a95 100644 --- a/api/payments/orchestrator/internal/service/orchestrator/service_test.go +++ b/api/payments/orchestrator/internal/service/orchestrator/service_test.go @@ -7,14 +7,14 @@ import ( "testing" "time" - chainclient "github.com/tech/sendico/chain/gateway/client" + chainclient "github.com/tech/sendico/gateway/chain/client" ledgerclient "github.com/tech/sendico/ledger/client" "github.com/tech/sendico/payments/orchestrator/storage" "github.com/tech/sendico/payments/orchestrator/storage/model" "github.com/tech/sendico/pkg/api/routers/gsresponse" mo "github.com/tech/sendico/pkg/model" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" ledgerv1 "github.com/tech/sendico/pkg/proto/ledger/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1" @@ -88,7 +88,7 @@ func TestExecutePayment_ChainFailure(t *testing.T) { clock: testClock{now: time.Now()}, storage: repo, gateway: gatewayDependency{client: &chainclient.Fake{ - SubmitTransferFn: func(ctx context.Context, req *gatewayv1.SubmitTransferRequest) (*gatewayv1.SubmitTransferResponse, error) { + SubmitTransferFn: func(ctx context.Context, req *chainv1.SubmitTransferRequest) (*chainv1.SubmitTransferResponse, error) { return nil, errors.New("chain failure") }, }}, @@ -147,10 +147,10 @@ func TestProcessTransferUpdateHandler_Settled(t *testing.T) { } req := &orchestratorv1.ProcessTransferUpdateRequest{ - Event: &gatewayv1.TransferStatusChangedEvent{ - Transfer: &gatewayv1.Transfer{ + Event: &chainv1.TransferStatusChangedEvent{ + Transfer: &chainv1.Transfer{ TransferRef: "transfer-1", - Status: gatewayv1.TransferStatus_TRANSFER_CONFIRMED, + Status: chainv1.TransferStatus_TRANSFER_CONFIRMED, }, }, } @@ -190,7 +190,7 @@ func TestProcessDepositObservedHandler_MatchesPayment(t *testing.T) { } req := &orchestratorv1.ProcessDepositObservedRequest{ - Event: &gatewayv1.WalletDepositObservedEvent{ + Event: &chainv1.WalletDepositObservedEvent{ WalletRef: "wallet-dst", Amount: &moneyv1.Money{Currency: "USD", Amount: "40"}, }, diff --git a/api/payments/orchestrator/storage/model/payment.go b/api/payments/orchestrator/storage/model/payment.go index 7ca9205..78cf083 100644 --- a/api/payments/orchestrator/storage/model/payment.go +++ b/api/payments/orchestrator/storage/model/payment.go @@ -7,9 +7,9 @@ import ( "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" ) @@ -67,15 +67,15 @@ type LedgerEndpoint struct { // ManagedWalletEndpoint describes managed wallet routing. type ManagedWalletEndpoint struct { - ManagedWalletRef string `bson:"managedWalletRef" json:"managedWalletRef"` - Asset *gatewayv1.Asset `bson:"asset,omitempty" json:"asset,omitempty"` + ManagedWalletRef string `bson:"managedWalletRef" json:"managedWalletRef"` + Asset *chainv1.Asset `bson:"asset,omitempty" json:"asset,omitempty"` } // ExternalChainEndpoint describes an external address. type ExternalChainEndpoint struct { - Asset *gatewayv1.Asset `bson:"asset,omitempty" json:"asset,omitempty"` - Address string `bson:"address" json:"address"` - Memo string `bson:"memo,omitempty" json:"memo,omitempty"` + Asset *chainv1.Asset `bson:"asset,omitempty" json:"asset,omitempty"` + Address string `bson:"address" json:"address"` + Memo string `bson:"memo,omitempty" json:"memo,omitempty"` } // PaymentEndpoint is a polymorphic payment destination/source. @@ -111,14 +111,14 @@ type PaymentIntent struct { // PaymentQuoteSnapshot stores the latest quote info. type PaymentQuoteSnapshot struct { - DebitAmount *moneyv1.Money `bson:"debitAmount,omitempty" json:"debitAmount,omitempty"` - ExpectedSettlementAmount *moneyv1.Money `bson:"expectedSettlementAmount,omitempty" json:"expectedSettlementAmount,omitempty"` - ExpectedFeeTotal *moneyv1.Money `bson:"expectedFeeTotal,omitempty" json:"expectedFeeTotal,omitempty"` - FeeLines []*feesv1.DerivedPostingLine `bson:"feeLines,omitempty" json:"feeLines,omitempty"` - FeeRules []*feesv1.AppliedRule `bson:"feeRules,omitempty" json:"feeRules,omitempty"` - FXQuote *oraclev1.Quote `bson:"fxQuote,omitempty" json:"fxQuote,omitempty"` - NetworkFee *gatewayv1.EstimateTransferFeeResponse `bson:"networkFee,omitempty" json:"networkFee,omitempty"` - FeeQuoteToken string `bson:"feeQuoteToken,omitempty" json:"feeQuoteToken,omitempty"` + DebitAmount *moneyv1.Money `bson:"debitAmount,omitempty" json:"debitAmount,omitempty"` + ExpectedSettlementAmount *moneyv1.Money `bson:"expectedSettlementAmount,omitempty" json:"expectedSettlementAmount,omitempty"` + ExpectedFeeTotal *moneyv1.Money `bson:"expectedFeeTotal,omitempty" json:"expectedFeeTotal,omitempty"` + FeeLines []*feesv1.DerivedPostingLine `bson:"feeLines,omitempty" json:"feeLines,omitempty"` + FeeRules []*feesv1.AppliedRule `bson:"feeRules,omitempty" json:"feeRules,omitempty"` + FXQuote *oraclev1.Quote `bson:"fxQuote,omitempty" json:"fxQuote,omitempty"` + NetworkFee *chainv1.EstimateTransferFeeResponse `bson:"networkFee,omitempty" json:"networkFee,omitempty"` + FeeQuoteToken string `bson:"feeQuoteToken,omitempty" json:"feeQuoteToken,omitempty"` } // ExecutionRefs links to downstream systems. diff --git a/api/pkg/.gitignore b/api/pkg/.gitignore index c8abcaa..49364e5 100644 --- a/api/pkg/.gitignore +++ b/api/pkg/.gitignore @@ -1,6 +1,8 @@ proto/billing proto/common proto/chain +proto/gateway proto/ledger proto/oracle -proto/payments \ No newline at end of file +proto/payments +.gocache \ No newline at end of file diff --git a/api/pkg/model/crypto_address.go b/api/pkg/model/crypto_address.go new file mode 100644 index 0000000..764abb8 --- /dev/null +++ b/api/pkg/model/crypto_address.go @@ -0,0 +1,27 @@ +package model + +import ( + "fmt" + + "github.com/tech/sendico/pkg/merrors" + "go.mongodb.org/mongo-driver/bson" +) + +type CryptoAddressPaymentData struct { + Address string `bson:"address" json:"address"` + Network string `bson:"network" json:"network"` + DestinationTag *string `bson:"destinationTag,omitempty" json:"destinationTag,omitempty"` +} + +func (m *PaymentMethod) AsCryptoAddress() (*CryptoAddressPaymentData, error) { + if m.Type != PaymentTypeCryptoAddress { + return nil, merrors.InvalidArgument(fmt.Sprintf("payment method type is %s, not cryptoAddress", m.Type), "type") + } + + var d CryptoAddressPaymentData + if err := bson.Unmarshal(m.Data, &d); err != nil { + return nil, err + } + + return &d, nil +} diff --git a/api/pkg/model/payment.go b/api/pkg/model/payment.go index 67a345a..aa65c91 100644 --- a/api/pkg/model/payment.go +++ b/api/pkg/model/payment.go @@ -16,20 +16,23 @@ const ( PaymentTypeCard PaymentTypeBankAccount PaymentTypeWallet + PaymentTypeCryptoAddress ) var paymentTypeToString = map[PaymentType]string{ - PaymentTypeIban: "iban", - PaymentTypeCard: "card", - PaymentTypeBankAccount: "bankAccount", - PaymentTypeWallet: "wallet", + PaymentTypeIban: "iban", + PaymentTypeCard: "card", + PaymentTypeBankAccount: "bankAccount", + PaymentTypeWallet: "wallet", + PaymentTypeCryptoAddress: "cryptoAddress", } var paymentTypeFromString = map[string]PaymentType{ - "iban": PaymentTypeIban, - "card": PaymentTypeCard, - "bankAccount": PaymentTypeBankAccount, - "wallet": PaymentTypeWallet, + "iban": PaymentTypeIban, + "card": PaymentTypeCard, + "bankAccount": PaymentTypeBankAccount, + "wallet": PaymentTypeWallet, + "cryptoAddress": PaymentTypeCryptoAddress, } func (t PaymentType) String() string { @@ -61,6 +64,5 @@ type PaymentMethod struct { RecipientRef primitive.ObjectID `bson:"recipientRef" json:"recipientRef"` Type PaymentType `bson:"type" json:"type"` - IsActive bool `bson:"isActive" json:"isActive"` Data bson.Raw `bson:"data" json:"data"` } diff --git a/api/proto/common/gateway/v1/gateway.proto b/api/proto/common/gateway/v1/gateway.proto new file mode 100644 index 0000000..3fdaf55 --- /dev/null +++ b/api/proto/common/gateway/v1/gateway.proto @@ -0,0 +1,97 @@ +syntax = "proto3"; +package common.gateway.v1; +option go_package = "github.com/tech/sendico/pkg/proto/common/gateway/v1;gatewayv1"; + +enum Operation { + OPERATION_UNSPECIFIED = 0; + OPERATION_AUTHORIZE = 1; + OPERATION_CAPTURE = 2; + OPERATION_REFUND = 3; + OPERATION_VOID = 4; + OPERATION_PAYOUT = 5; + OPERATION_TOKENIZE = 6; + OPERATION_VERIFY = 7; // zero-amount verification + OPERATION_GET_BALANCE = 8; + OPERATION_CREATE_ACCOUNT = 9; +} + +enum PaymentMethodType { + PM_UNSPECIFIED = 0; + PM_CARD = 1; + PM_SEPA = 2; + PM_ACH = 3; + PM_PIX = 4; + PM_WALLET = 5; + PM_CRYPTO = 6; + PM_LOCAL_BANK = 7; // generic local rails, refine later if needed +} + +// Limits in minor units, e.g. cents +message AmountLimits { + int64 min_minor = 1; + int64 max_minor = 2; +} + +// Capabilities of a particular operation (e.g. "authorize") +message OperationCapabilities { + // If false or absent in the map -> operation not supported + bool supported = 1; + bool partial_allowed = 2; // partial capture/refund + bool supports_3ds = 3; // relevant mostly for AUTHORIZE/VERIFY + bool synchronous = 4; // true = immediate result, false = async/poll +} + +// Per-method matrix entry +message MethodCapability { + PaymentMethodType method = 1; + + // ISO 4217 currency codes, e.g. "EUR", "USD" + repeated string currencies = 2; + + // ISO 3166-1 alpha-2 country codes where this method is available + repeated string countries = 3; + + // Can the gateway tokenize this method (card token, wallet token, etc.) + bool tokenization_supported = 4; + + // Optional per-method limits; if unset, use global amount_limits + AmountLimits amount_limits = 5; +} + +// Payout capabilities of this gateway +message PayoutCapabilities { + bool enabled = 1; + repeated string currencies = 2; + repeated string countries = 3; + AmountLimits amount_limits = 4; +} + +// High-level capability descriptor for a gateway +message GatewayCapabilities { + // For each operation, describe what exactly it can do. + // Map key uses the Operation enum name (e.g. "OPERATION_AUTHORIZE"). + map operations = 1; + + // For each payment method, list where and how it works + repeated MethodCapability methods = 2; + + // Global amount limits (fallback if per-method limits not set) + AmountLimits amount_limits = 3; + + // Payout-related capabilities (if any) + PayoutCapabilities payouts = 4; + + // Free-form metadata / escape hatch + map extra = 10; +} + +// A specific gateway instance or config variant (e.g. stripe_eu_prod) +message GatewayDescriptor { + string id = 1; // "stripe_eu", "adyen_br", "local_bank_pl" + string provider = 2; // "stripe", "adyen", "local_bank" + string label = 3; // human-readable name + string version = 4; // config or integration version + string environment = 5; // "prod", "sandbox", "test" + + GatewayCapabilities capabilities = 6; +} diff --git a/api/proto/chain/gateway/v1/gateway.proto b/api/proto/gateway/chain/v1/chain.proto similarity index 97% rename from api/proto/chain/gateway/v1/gateway.proto rename to api/proto/gateway/chain/v1/chain.proto index df21870..8ecc390 100644 --- a/api/proto/chain/gateway/v1/gateway.proto +++ b/api/proto/gateway/chain/v1/chain.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package chain.gateway.v1; -option go_package = "github.com/tech/sendico/pkg/proto/chain/gateway/v1;gatewayv1"; +option go_package = "github.com/tech/sendico/pkg/proto/gateway/chain/v1;chainv1"; import "google/protobuf/timestamp.proto"; import "common/money/v1/money.proto"; @@ -198,7 +198,7 @@ message WalletDepositObservedEvent { message TransferStatusChangedEvent { Transfer transfer = 1; - string reason = 2; + string reason = 2; } service ChainGatewayService { diff --git a/api/proto/payments/orchestrator/v1/orchestrator.proto b/api/proto/payments/orchestrator/v1/orchestrator.proto index 9f93167..b4635e3 100644 --- a/api/proto/payments/orchestrator/v1/orchestrator.proto +++ b/api/proto/payments/orchestrator/v1/orchestrator.proto @@ -10,7 +10,7 @@ import "common/fx/v1/fx.proto"; import "common/trace/v1/trace.proto"; import "common/pagination/v1/cursor.proto"; import "billing/fees/v1/fees.proto"; -import "chain/gateway/v1/gateway.proto"; +import "gateway/chain/v1/chain.proto"; import "oracle/v1/oracle.proto"; enum PaymentKind { diff --git a/api/server/.gitignore b/api/server/.gitignore index 020e40b..a5b14dd 100644 --- a/api/server/.gitignore +++ b/api/server/.gitignore @@ -1,3 +1,4 @@ /app /server /storage +.gocache \ No newline at end of file diff --git a/api/server/go.mod b/api/server/go.mod index af8a84d..0852be1 100644 --- a/api/server/go.mod +++ b/api/server/go.mod @@ -6,7 +6,7 @@ replace github.com/tech/sendico/pkg => ../pkg replace github.com/tech/sendico/ledger => ../ledger -replace github.com/tech/sendico/chain/gateway => ../chain/gateway +replace github.com/tech/sendico/gateway/chain => ../gateway/chain require ( github.com/aws/aws-sdk-go-v2 v1.40.0 @@ -20,7 +20,7 @@ require ( github.com/google/uuid v1.6.0 github.com/mitchellh/mapstructure v1.5.0 github.com/stretchr/testify v1.11.1 - github.com/tech/sendico/chain/gateway v0.1.0 + github.com/tech/sendico/gateway/chain v0.1.0 github.com/tech/sendico/ledger v0.0.0-00010101000000-000000000000 github.com/tech/sendico/pkg v0.1.0 github.com/testcontainers/testcontainers-go v0.33.0 diff --git a/api/server/interface/api/srequest/signup.go b/api/server/interface/api/srequest/signup.go index 208666d..c1b7137 100644 --- a/api/server/interface/api/srequest/signup.go +++ b/api/server/interface/api/srequest/signup.go @@ -1,6 +1,11 @@ package srequest -import "github.com/tech/sendico/pkg/model" +import ( + "bytes" + "encoding/json" + + "github.com/tech/sendico/pkg/model" +) type Signup struct { Account model.AccountData `json:"account"` @@ -8,3 +13,17 @@ type Signup struct { OrganizationTimeZone string `json:"organizationTimeZone"` OwnerRole model.Describable `json:"ownerRole"` } + +// UnmarshalJSON enforces strict parsing to catch malformed or unexpected fields. +func (s *Signup) UnmarshalJSON(data []byte) error { + type alias Signup + var payload alias + + dec := json.NewDecoder(bytes.NewReader(data)) + dec.DisallowUnknownFields() + if err := dec.Decode(&payload); err != nil { + return err + } + *s = Signup(payload) + return nil +} diff --git a/api/server/interface/api/sresponse/wallet.go b/api/server/interface/api/sresponse/wallet.go index 595bcfd..555b875 100644 --- a/api/server/interface/api/sresponse/wallet.go +++ b/api/server/interface/api/sresponse/wallet.go @@ -6,9 +6,9 @@ import ( "github.com/tech/sendico/pkg/api/http/response" "github.com/tech/sendico/pkg/mlogger" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -53,7 +53,7 @@ type walletBalanceResponse struct { Balance walletBalance `json:"balance"` } -func Wallets(logger mlogger.Logger, resp *gatewayv1.ListManagedWalletsResponse, accessToken *TokenData) http.HandlerFunc { +func Wallets(logger mlogger.Logger, resp *chainv1.ListManagedWalletsResponse, accessToken *TokenData) http.HandlerFunc { dto := walletsResponse{ Page: resp.GetPage(), authResponse: authResponse{AccessToken: *accessToken}, @@ -65,14 +65,14 @@ func Wallets(logger mlogger.Logger, resp *gatewayv1.ListManagedWalletsResponse, return response.Ok(logger, dto) } -func WalletBalance(logger mlogger.Logger, bal *gatewayv1.WalletBalance, accessToken *TokenData) http.HandlerFunc { +func WalletBalance(logger mlogger.Logger, bal *chainv1.WalletBalance, accessToken *TokenData) http.HandlerFunc { return response.Ok(logger, walletBalanceResponse{ Balance: toWalletBalance(bal), authResponse: authResponse{AccessToken: *accessToken}, }) } -func toWallet(w *gatewayv1.ManagedWallet) wallet { +func toWallet(w *chainv1.ManagedWallet) wallet { if w == nil { return wallet{} } @@ -102,7 +102,7 @@ func toWallet(w *gatewayv1.ManagedWallet) wallet { } } -func toWalletBalance(b *gatewayv1.WalletBalance) walletBalance { +func toWalletBalance(b *chainv1.WalletBalance) walletBalance { if b == nil { return walletBalance{} } diff --git a/api/server/internal/server/accountapiimp/service.go b/api/server/internal/server/accountapiimp/service.go index 9db86cc..c48a4eb 100644 --- a/api/server/internal/server/accountapiimp/service.go +++ b/api/server/internal/server/accountapiimp/service.go @@ -7,7 +7,7 @@ import ( "strings" "time" - chaingatewayclient "github.com/tech/sendico/chain/gateway/client" + chaingatewayclient "github.com/tech/sendico/gateway/chain/client" api "github.com/tech/sendico/pkg/api/http" "github.com/tech/sendico/pkg/auth" "github.com/tech/sendico/pkg/db/account" @@ -20,7 +20,7 @@ import ( "github.com/tech/sendico/pkg/messaging" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "github.com/tech/sendico/server/interface/accountservice" eapi "github.com/tech/sendico/server/interface/api" "github.com/tech/sendico/server/interface/services/fileservice" @@ -47,11 +47,11 @@ type AccountAPI struct { accountsPermissionRef primitive.ObjectID accService accountservice.AccountService chainGateway chainWalletClient - chainAsset *gatewayv1.Asset + chainAsset *chainv1.Asset } type chainWalletClient interface { - CreateManagedWallet(ctx context.Context, req *gatewayv1.CreateManagedWalletRequest) (*gatewayv1.CreateManagedWalletResponse, error) + CreateManagedWallet(ctx context.Context, req *chainv1.CreateManagedWalletRequest) (*chainv1.CreateManagedWalletResponse, error) Close() error } @@ -192,7 +192,7 @@ func (a *AccountAPI) initChainGateway(cfg *eapi.ChainGatewayConfig) error { return nil } -func buildGatewayAsset(cfg eapi.ChainGatewayAssetConfig) (*gatewayv1.Asset, error) { +func buildGatewayAsset(cfg eapi.ChainGatewayAssetConfig) (*chainv1.Asset, error) { chain, err := parseChainNetwork(cfg.Chain) if err != nil { return nil, err @@ -201,24 +201,24 @@ func buildGatewayAsset(cfg eapi.ChainGatewayAssetConfig) (*gatewayv1.Asset, erro if tokenSymbol == "" { return nil, merrors.InvalidArgument("chain gateway token symbol is required") } - return &gatewayv1.Asset{ + return &chainv1.Asset{ Chain: chain, TokenSymbol: strings.ToUpper(tokenSymbol), ContractAddress: strings.ToLower(strings.TrimSpace(cfg.ContractAddress)), }, nil } -func parseChainNetwork(value string) (gatewayv1.ChainNetwork, error) { +func parseChainNetwork(value string) (chainv1.ChainNetwork, error) { switch strings.ToUpper(strings.TrimSpace(value)) { case "ETHEREUM_MAINNET", "CHAIN_NETWORK_ETHEREUM_MAINNET": - return gatewayv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, nil + return chainv1.ChainNetwork_CHAIN_NETWORK_ETHEREUM_MAINNET, nil case "ARBITRUM_ONE", "CHAIN_NETWORK_ARBITRUM_ONE": - return gatewayv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil + return chainv1.ChainNetwork_CHAIN_NETWORK_ARBITRUM_ONE, nil case "OTHER_EVM", "CHAIN_NETWORK_OTHER_EVM": - return gatewayv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil + return chainv1.ChainNetwork_CHAIN_NETWORK_OTHER_EVM, nil case "", "CHAIN_NETWORK_UNSPECIFIED": - return gatewayv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("chain network must be specified") + return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument("chain network must be specified") default: - return gatewayv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument(fmt.Sprintf("unsupported chain network %s", value)) + return chainv1.ChainNetwork_CHAIN_NETWORK_UNSPECIFIED, merrors.InvalidArgument(fmt.Sprintf("unsupported chain network %s", value)) } } diff --git a/api/server/internal/server/accountapiimp/signup.go b/api/server/internal/server/accountapiimp/signup.go index 58d1fba..654a84e 100644 --- a/api/server/internal/server/accountapiimp/signup.go +++ b/api/server/internal/server/accountapiimp/signup.go @@ -16,7 +16,7 @@ import ( "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" "github.com/tech/sendico/pkg/mutil/mzap" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "github.com/tech/sendico/server/interface/api/srequest" "github.com/tech/sendico/server/interface/api/sresponse" "go.mongodb.org/mongo-driver/bson/primitive" @@ -249,7 +249,7 @@ func (a *AccountAPI) openOrgWallet(ctx context.Context, org *model.Organization, return merrors.Internal("chain gateway client is not configured") } asset := *a.chainAsset - req := &gatewayv1.CreateManagedWalletRequest{ + req := &chainv1.CreateManagedWalletRequest{ IdempotencyKey: uuid.NewString(), OrganizationRef: org.ID.Hex(), OwnerRef: org.ID.Hex(), diff --git a/api/server/internal/server/accountapiimp/signup_integration_test.go b/api/server/internal/server/accountapiimp/signup_integration_test.go index 664162d..835f2a0 100644 --- a/api/server/internal/server/accountapiimp/signup_integration_test.go +++ b/api/server/internal/server/accountapiimp/signup_integration_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "net/http" "net/http/httptest" + "os" "testing" "time" @@ -27,6 +28,10 @@ func stringPtr(s string) *string { // TestSignupRequestSerialization tests JSON marshaling/unmarshaling with real MongoDB func TestSignupRequestSerialization(t *testing.T) { + if os.Getenv("RUN_DOCKER_TESTS") == "" { + t.Skip("skipping: docker-dependent integration test (set RUN_DOCKER_TESTS=1 to enable)") + } + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() diff --git a/api/server/internal/server/walletapiimp/balance.go b/api/server/internal/server/walletapiimp/balance.go index 995193e..55397ac 100644 --- a/api/server/internal/server/walletapiimp/balance.go +++ b/api/server/internal/server/walletapiimp/balance.go @@ -8,7 +8,7 @@ import ( "github.com/tech/sendico/pkg/api/http/response" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "github.com/tech/sendico/server/interface/api/sresponse" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" @@ -39,7 +39,7 @@ func (a *WalletAPI) getWalletBalance(r *http.Request, account *model.Account, to return response.Internal(a.logger, mservice.ChainGateway, errors.New("chain gateway client is not configured")) } - resp, err := a.chainGateway.GetWalletBalance(ctx, &gatewayv1.GetWalletBalanceRequest{WalletRef: walletRef}) + resp, err := a.chainGateway.GetWalletBalance(ctx, &chainv1.GetWalletBalanceRequest{WalletRef: walletRef}) if err != nil { a.logger.Warn("Failed to fetch wallet balance", zap.Error(err), zap.String("wallet_ref", walletRef)) return response.Auto(a.logger, mservice.ChainGateway, err) diff --git a/api/server/internal/server/walletapiimp/list.go b/api/server/internal/server/walletapiimp/list.go index c5acc6c..e8cb246 100644 --- a/api/server/internal/server/walletapiimp/list.go +++ b/api/server/internal/server/walletapiimp/list.go @@ -8,7 +8,7 @@ import ( "github.com/tech/sendico/pkg/api/http/response" "github.com/tech/sendico/pkg/model" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" "github.com/tech/sendico/server/interface/api/sresponse" "go.mongodb.org/mongo-driver/bson/primitive" "go.uber.org/zap" @@ -35,7 +35,7 @@ func (a *WalletAPI) listWallets(r *http.Request, account *model.Account, token * return response.Internal(a.logger, mservice.ChainGateway, errors.New("chain gateway client is not configured")) } - req := &gatewayv1.ListManagedWalletsRequest{ + req := &chainv1.ListManagedWalletsRequest{ OrganizationRef: orgRef.Hex(), } if owner := strings.TrimSpace(r.URL.Query().Get("owner_ref")); owner != "" { diff --git a/api/server/internal/server/walletapiimp/service.go b/api/server/internal/server/walletapiimp/service.go index 9077933..893c33d 100644 --- a/api/server/internal/server/walletapiimp/service.go +++ b/api/server/internal/server/walletapiimp/service.go @@ -7,13 +7,13 @@ import ( "strings" "time" - chaingatewayclient "github.com/tech/sendico/chain/gateway/client" + chaingatewayclient "github.com/tech/sendico/gateway/chain/client" api "github.com/tech/sendico/pkg/api/http" "github.com/tech/sendico/pkg/auth" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "github.com/tech/sendico/pkg/mservice" - gatewayv1 "github.com/tech/sendico/pkg/proto/chain/gateway/v1" + chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" eapi "github.com/tech/sendico/server/interface/api" mutil "github.com/tech/sendico/server/internal/mutil/param" "go.mongodb.org/mongo-driver/bson/primitive" @@ -31,8 +31,8 @@ type WalletAPI struct { } type chainWalletClient interface { - ListManagedWallets(ctx context.Context, req *gatewayv1.ListManagedWalletsRequest) (*gatewayv1.ListManagedWalletsResponse, error) - GetWalletBalance(ctx context.Context, req *gatewayv1.GetWalletBalanceRequest) (*gatewayv1.GetWalletBalanceResponse, error) + ListManagedWallets(ctx context.Context, req *chainv1.ListManagedWalletsRequest) (*chainv1.ListManagedWalletsResponse, error) + GetWalletBalance(ctx context.Context, req *chainv1.GetWalletBalanceRequest) (*chainv1.GetWalletBalanceResponse, error) Close() error } diff --git a/ci/prod/compose/chain_gateway.dockerfile b/ci/prod/compose/chain_gateway.dockerfile index b02d311..e3fcab6 100644 --- a/ci/prod/compose/chain_gateway.dockerfile +++ b/ci/prod/compose/chain_gateway.dockerfile @@ -17,25 +17,25 @@ RUN apk add --no-cache bash git build-base protoc protobuf-dev \ && go install google.golang.org/protobuf/cmd/protoc-gen-go@latest \ && go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \ && bash ci/scripts/proto/generate.sh -WORKDIR /src/api/chain/gateway +WORKDIR /src/api/gateway/chain RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg/mod \ CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \ go build -trimpath -ldflags "\ -s -w \ - -X github.com/tech/sendico/chain/gateway/internal/appversion.Version=${APP_VERSION} \ - -X github.com/tech/sendico/chain/gateway/internal/appversion.Revision=${GIT_REV} \ - -X github.com/tech/sendico/chain/gateway/internal/appversion.Branch=${BUILD_BRANCH} \ - -X github.com/tech/sendico/chain/gateway/internal/appversion.BuildUser=${BUILD_USER} \ - -X github.com/tech/sendico/chain/gateway/internal/appversion.BuildDate=${BUILD_DATE}" \ + -X github.com/tech/sendico/gateway/chain/internal/appversion.Version=${APP_VERSION} \ + -X github.com/tech/sendico/gateway/chain/internal/appversion.Revision=${GIT_REV} \ + -X github.com/tech/sendico/gateway/chain/internal/appversion.Branch=${BUILD_BRANCH} \ + -X github.com/tech/sendico/gateway/chain/internal/appversion.BuildUser=${BUILD_USER} \ + -X github.com/tech/sendico/gateway/chain/internal/appversion.BuildDate=${BUILD_DATE}" \ -o /out/chain-gateway . FROM alpine:latest AS runtime RUN apk add --no-cache ca-certificates tzdata wget WORKDIR /app -COPY api/chain/gateway/config.yml /app/config.yml -COPY api/chain/gateway/env /app/env -COPY api/chain/gateway/entrypoint.sh /app/entrypoint.sh +COPY api/gateway/chain/config.yml /app/config.yml +COPY api/gateway/chain/env /app/env +COPY api/gateway/chain/entrypoint.sh /app/entrypoint.sh COPY --from=build /out/chain-gateway /app/chain-gateway RUN chmod +x /app/entrypoint.sh EXPOSE 50070 9403 diff --git a/ci/prod/compose/chain_gateway.yml b/ci/prod/compose/chain_gateway.yml index 045ddae..9fb153b 100644 --- a/ci/prod/compose/chain_gateway.yml +++ b/ci/prod/compose/chain_gateway.yml @@ -23,7 +23,7 @@ services: <<: *common-env container_name: sendico-chain-gateway restart: unless-stopped - image: ${REGISTRY_URL}/chain/gateway:${APP_V} + image: ${REGISTRY_URL}/gateway/chain:${APP_V} pull_policy: always environment: CHAIN_GATEWAY_MONGO_HOST: ${CHAIN_GATEWAY_MONGO_HOST} diff --git a/ci/scripts/proto/generate.sh b/ci/scripts/proto/generate.sh index 0e62877..e40ceae 100755 --- a/ci/scripts/proto/generate.sh +++ b/ci/scripts/proto/generate.sh @@ -104,10 +104,10 @@ if [ -f "${PROTO_DIR}/oracle/v1/oracle.proto" ]; then generate_go_with_grpc "${PROTO_DIR}/oracle/v1/oracle.proto" fi -if [ -f "${PROTO_DIR}/chain/gateway/v1/gateway.proto" ]; then +if [ -f "${PROTO_DIR}/gateway/chain/v1/chain.proto" ]; then info "Compiling chain gateway protos" - clean_pb_files "./pkg/proto/chain/gateway" - generate_go_with_grpc "${PROTO_DIR}/chain/gateway/v1/gateway.proto" + clean_pb_files "./pkg/proto/gateway/chain" + generate_go_with_grpc "${PROTO_DIR}/gateway/chain/v1/chain.proto" fi if [ -f "${PROTO_DIR}/payments/orchestrator/v1/orchestrator.proto" ]; then diff --git a/frontend/pshared/lib/data/dto/payment/card.dart b/frontend/pshared/lib/data/dto/payment/card.dart new file mode 100644 index 0000000..0bd5651 --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/card.dart @@ -0,0 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'card.g.dart'; + + +@JsonSerializable() +class CardPaymentDataDTO { + final String pan; + final String firstName; + final String lastName; + + const CardPaymentDataDTO({ + required this.pan, + required this.firstName, + required this.lastName, + }); + + factory CardPaymentDataDTO.fromJson(Map json) => _$CardPaymentDataDTOFromJson(json); + Map toJson() => _$CardPaymentDataDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/payment/crypto_address.dart b/frontend/pshared/lib/data/dto/payment/crypto_address.dart new file mode 100644 index 0000000..4c8df60 --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/crypto_address.dart @@ -0,0 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'crypto_address.g.dart'; + + +@JsonSerializable() +class CryptoAddressPaymentDataDTO { + final String address; + final String network; + final String? destinationTag; + + const CryptoAddressPaymentDataDTO({ + required this.address, + required this.network, + this.destinationTag, + }); + + factory CryptoAddressPaymentDataDTO.fromJson(Map json) => _$CryptoAddressPaymentDataDTOFromJson(json); + Map toJson() => _$CryptoAddressPaymentDataDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/payment/iban.dart b/frontend/pshared/lib/data/dto/payment/iban.dart new file mode 100644 index 0000000..f152da7 --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/iban.dart @@ -0,0 +1,22 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'iban.g.dart'; + + +@JsonSerializable() +class IbanPaymentDataDTO { + final String iban; + final String accountHolder; + final String? bic; + final String? bankName; + + const IbanPaymentDataDTO({ + required this.iban, + required this.accountHolder, + this.bic, + this.bankName, + }); + + factory IbanPaymentDataDTO.fromJson(Map json) => _$IbanPaymentDataDTOFromJson(json); + Map toJson() => _$IbanPaymentDataDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/payment/method.dart b/frontend/pshared/lib/data/dto/payment/method.dart new file mode 100644 index 0000000..dce7bcd --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/method.dart @@ -0,0 +1,33 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'package:pshared/data/dto/date_time.dart'; +import 'package:pshared/data/dto/permissions/bound.dart'; + +part 'method.g.dart'; + + +@JsonSerializable() +class PaymentMethodDTO extends PermissionBoundDTO { + final String recipientRef; + final String type; + final Map data; + + @JsonKey(defaultValue: false) + final bool isArchived; + + const PaymentMethodDTO({ + required super.id, + required super.createdAt, + required super.updatedAt, + required super.permissionRef, + required super.organizationRef, + required this.recipientRef, + required this.type, + required this.data, + this.isArchived = false, + }); + + factory PaymentMethodDTO.fromJson(Map json) => _$PaymentMethodDTOFromJson(json); + @override + Map toJson() => _$PaymentMethodDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/payment/russian_bank.dart b/frontend/pshared/lib/data/dto/payment/russian_bank.dart new file mode 100644 index 0000000..51cc8e2 --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/russian_bank.dart @@ -0,0 +1,28 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'russian_bank.g.dart'; + + +@JsonSerializable() +class RussianBankAccountPaymentDataDTO { + final String recipientName; + final String inn; + final String kpp; + final String bankName; + final String bik; + final String accountNumber; + final String correspondentAccount; + + const RussianBankAccountPaymentDataDTO({ + required this.recipientName, + required this.inn, + required this.kpp, + required this.bankName, + required this.bik, + required this.accountNumber, + required this.correspondentAccount, + }); + + factory RussianBankAccountPaymentDataDTO.fromJson(Map json) => _$RussianBankAccountPaymentDataDTOFromJson(json); + Map toJson() => _$RussianBankAccountPaymentDataDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/payment/wallet.dart b/frontend/pshared/lib/data/dto/payment/wallet.dart new file mode 100644 index 0000000..e5075ca --- /dev/null +++ b/frontend/pshared/lib/data/dto/payment/wallet.dart @@ -0,0 +1,16 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'wallet.g.dart'; + + +@JsonSerializable() +class WalletPaymentDataDTO { + final String walletId; + + const WalletPaymentDataDTO({ + required this.walletId, + }); + + factory WalletPaymentDataDTO.fromJson(Map json) => _$WalletPaymentDataDTOFromJson(json); + Map toJson() => _$WalletPaymentDataDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/dto/recipient/recipient.dart b/frontend/pshared/lib/data/dto/recipient/recipient.dart new file mode 100644 index 0000000..ff301c1 --- /dev/null +++ b/frontend/pshared/lib/data/dto/recipient/recipient.dart @@ -0,0 +1,39 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'package:pshared/data/dto/date_time.dart'; +import 'package:pshared/data/dto/permissions/bound.dart'; + +part 'recipient.g.dart'; + + +@JsonSerializable() +class RecipientDTO extends PermissionBoundDTO { + final String name; + final String? description; + final String email; + final String? avatarUrl; + final String status; + final String type; + + @JsonKey(defaultValue: false) + final bool isArchived; + + const RecipientDTO({ + required super.id, + required super.createdAt, + required super.updatedAt, + required super.permissionRef, + required super.organizationRef, + required this.name, + required this.email, + required this.status, + required this.type, + this.description, + this.avatarUrl, + this.isArchived = false, + }); + + factory RecipientDTO.fromJson(Map json) => _$RecipientDTOFromJson(json); + @override + Map toJson() => _$RecipientDTOToJson(this); +} diff --git a/frontend/pshared/lib/data/mapper/payment/card.dart b/frontend/pshared/lib/data/mapper/payment/card.dart new file mode 100644 index 0000000..c4e19ae --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/card.dart @@ -0,0 +1,19 @@ +import 'package:pshared/data/dto/payment/card.dart'; +import 'package:pshared/models/payment/methods/card.dart'; + + +extension CardPaymentMethodMapper on CardPaymentMethod { + CardPaymentDataDTO toDTO() => CardPaymentDataDTO( + pan: pan, + firstName: firstName, + lastName: lastName, + ); +} + +extension CardPaymentDataDTOMapper on CardPaymentDataDTO { + CardPaymentMethod toDomain() => CardPaymentMethod( + pan: pan, + firstName: firstName, + lastName: lastName, + ); +} diff --git a/frontend/pshared/lib/data/mapper/payment/crypto_address.dart b/frontend/pshared/lib/data/mapper/payment/crypto_address.dart new file mode 100644 index 0000000..98788e6 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/crypto_address.dart @@ -0,0 +1,19 @@ +import 'package:pshared/data/dto/payment/crypto_address.dart'; +import 'package:pshared/models/payment/methods/crypto_address.dart'; + + +extension CryptoAddressPaymentMethodMapper on CryptoAddressPaymentMethod { + CryptoAddressPaymentDataDTO toDTO() => CryptoAddressPaymentDataDTO( + address: address, + network: network, + destinationTag: destinationTag, + ); +} + +extension CryptoAddressPaymentDataDTOMapper on CryptoAddressPaymentDataDTO { + CryptoAddressPaymentMethod toDomain() => CryptoAddressPaymentMethod( + address: address, + network: network, + destinationTag: destinationTag, + ); +} diff --git a/frontend/pshared/lib/data/mapper/payment/iban.dart b/frontend/pshared/lib/data/mapper/payment/iban.dart new file mode 100644 index 0000000..e8e0759 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/iban.dart @@ -0,0 +1,21 @@ +import 'package:pshared/data/dto/payment/iban.dart'; +import 'package:pshared/models/payment/methods/iban.dart'; + + +extension IbanPaymentMethodMapper on IbanPaymentMethod { + IbanPaymentDataDTO toDTO() => IbanPaymentDataDTO( + iban: iban, + accountHolder: accountHolder, + bic: bic, + bankName: bankName, + ); +} + +extension IbanPaymentDataDTOMapper on IbanPaymentDataDTO { + IbanPaymentMethod toDomain() => IbanPaymentMethod( + iban: iban, + accountHolder: accountHolder, + bic: bic, + bankName: bankName, + ); +} diff --git a/frontend/pshared/lib/data/mapper/payment/method.dart b/frontend/pshared/lib/data/mapper/payment/method.dart new file mode 100644 index 0000000..7879712 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/method.dart @@ -0,0 +1,81 @@ +import 'package:pshared/data/dto/payment/card.dart'; +import 'package:pshared/data/dto/payment/crypto_address.dart'; +import 'package:pshared/data/dto/payment/iban.dart'; +import 'package:pshared/data/dto/payment/method.dart'; +import 'package:pshared/data/dto/payment/russian_bank.dart'; +import 'package:pshared/data/dto/payment/wallet.dart'; +import 'package:pshared/data/mapper/payment/crypto_address.dart'; +import 'package:pshared/data/mapper/payment/card.dart'; +import 'package:pshared/data/mapper/payment/iban.dart'; +import 'package:pshared/data/mapper/payment/russian_bank.dart'; +import 'package:pshared/data/mapper/payment/type.dart'; +import 'package:pshared/data/mapper/payment/wallet.dart'; +import 'package:pshared/models/organization/bound.dart'; +import 'package:pshared/models/payment/methods/card.dart'; +import 'package:pshared/models/payment/methods/crypto_address.dart'; +import 'package:pshared/models/payment/methods/data.dart'; +import 'package:pshared/models/payment/methods/iban.dart'; +import 'package:pshared/models/payment/methods/russian_bank.dart'; +import 'package:pshared/models/payment/methods/wallet.dart'; +import 'package:pshared/models/payment/payment_method.dart'; +import 'package:pshared/models/payment/type.dart'; +import 'package:pshared/models/permissions/bound.dart'; +import 'package:pshared/models/storable.dart'; + + +extension PaymentMethodModelMapper on PaymentMethodModel { + PaymentMethodDTO toDTO() => PaymentMethodDTO( + id: storable.id, + createdAt: storable.createdAt, + updatedAt: storable.updatedAt, + permissionRef: permissionBound.permissionRef, + organizationRef: permissionBound.organizationRef, + recipientRef: recipientRef, + type: paymentTypeToValue(type), + data: _dataToJson(data), + isArchived: isArchived, + ); + + Map _dataToJson(PaymentMethodData data) { + switch (data.type) { + case PaymentType.card: + return (data as CardPaymentMethod).toDTO().toJson(); + case PaymentType.iban: + return (data as IbanPaymentMethod).toDTO().toJson(); + case PaymentType.bankAccount: + return (data as RussianBankAccountPaymentMethod).toDTO().toJson(); + case PaymentType.wallet: + return (data as WalletPaymentMethod).toDTO().toJson(); + case PaymentType.cryptoAddress: + return (data as CryptoAddressPaymentMethod).toDTO().toJson(); + } + } +} + +extension PaymentMethodDTOMapper on PaymentMethodDTO { + PaymentMethodModel toDomain() => PaymentMethodModel( + storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt), + permissionBound: newPermissionBound( + organizationBound: newOrganizationBound(organizationRef: organizationRef), + permissionRef: permissionRef, + ), + recipientRef: recipientRef, + data: _dataToDomain(paymentTypeFromValue(type), data), + isArchived: isArchived, + ); + + PaymentMethodData _dataToDomain(PaymentType paymentType, Map payload) { + switch (paymentType) { + case PaymentType.card: + return CardPaymentDataDTO.fromJson(payload).toDomain(); + case PaymentType.iban: + return IbanPaymentDataDTO.fromJson(payload).toDomain(); + case PaymentType.bankAccount: + return RussianBankAccountPaymentDataDTO.fromJson(payload).toDomain(); + case PaymentType.wallet: + return WalletPaymentDataDTO.fromJson(payload).toDomain(); + case PaymentType.cryptoAddress: + return CryptoAddressPaymentDataDTO.fromJson(payload).toDomain(); + } + } +} diff --git a/frontend/pshared/lib/data/mapper/payment/russian_bank.dart b/frontend/pshared/lib/data/mapper/payment/russian_bank.dart new file mode 100644 index 0000000..b64e084 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/russian_bank.dart @@ -0,0 +1,27 @@ +import 'package:pshared/data/dto/payment/russian_bank.dart'; +import 'package:pshared/models/payment/methods/russian_bank.dart'; + + +extension RussianBankPaymentMethodMapper on RussianBankAccountPaymentMethod { + RussianBankAccountPaymentDataDTO toDTO() => RussianBankAccountPaymentDataDTO( + recipientName: recipientName, + inn: inn, + kpp: kpp, + bankName: bankName, + bik: bik, + accountNumber: accountNumber, + correspondentAccount: correspondentAccount, + ); +} + +extension RussianBankAccountPaymentDataDTOMapper on RussianBankAccountPaymentDataDTO { + RussianBankAccountPaymentMethod toDomain() => RussianBankAccountPaymentMethod( + recipientName: recipientName, + inn: inn, + kpp: kpp, + bankName: bankName, + bik: bik, + accountNumber: accountNumber, + correspondentAccount: correspondentAccount, + ); +} diff --git a/frontend/pshared/lib/data/mapper/payment/type.dart b/frontend/pshared/lib/data/mapper/payment/type.dart new file mode 100644 index 0000000..af0c172 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/type.dart @@ -0,0 +1,34 @@ +import 'package:pshared/models/payment/type.dart'; + + +PaymentType paymentTypeFromValue(String value) { + switch (value) { + case 'iban': + return PaymentType.iban; + case 'card': + return PaymentType.card; + case 'bankAccount': + return PaymentType.bankAccount; + case 'wallet': + return PaymentType.wallet; + case 'cryptoAddress': + return PaymentType.cryptoAddress; + default: + return PaymentType.iban; + } +} + +String paymentTypeToValue(PaymentType type) { + switch (type) { + case PaymentType.iban: + return 'iban'; + case PaymentType.card: + return 'card'; + case PaymentType.bankAccount: + return 'bankAccount'; + case PaymentType.wallet: + return 'wallet'; + case PaymentType.cryptoAddress: + return 'cryptoAddress'; + } +} diff --git a/frontend/pshared/lib/data/mapper/payment/wallet.dart b/frontend/pshared/lib/data/mapper/payment/wallet.dart new file mode 100644 index 0000000..121548c --- /dev/null +++ b/frontend/pshared/lib/data/mapper/payment/wallet.dart @@ -0,0 +1,13 @@ +import 'package:pshared/data/dto/payment/wallet.dart'; +import 'package:pshared/models/payment/methods/wallet.dart'; + + +extension WalletPaymentMethodMapper on WalletPaymentMethod { + WalletPaymentDataDTO toDTO() => WalletPaymentDataDTO( + walletId: walletId, + ); +} + +extension WalletPaymentDataDTOMapper on WalletPaymentDataDTO { + WalletPaymentMethod toDomain() => WalletPaymentMethod(walletId: walletId); +} diff --git a/frontend/pshared/lib/data/mapper/recipient/recipient.dart b/frontend/pshared/lib/data/mapper/recipient/recipient.dart new file mode 100644 index 0000000..f77d477 --- /dev/null +++ b/frontend/pshared/lib/data/mapper/recipient/recipient.dart @@ -0,0 +1,85 @@ +import 'package:pshared/data/dto/recipient/recipient.dart'; +import 'package:pshared/models/describable.dart'; +import 'package:pshared/models/organization/bound.dart'; +import 'package:pshared/models/permissions/bound.dart'; +import 'package:pshared/models/recipient/recipient_model.dart'; +import 'package:pshared/models/recipient/status.dart'; +import 'package:pshared/models/recipient/type.dart'; +import 'package:pshared/models/storable.dart'; + + +extension RecipientModelMapper on RecipientModel { + RecipientDTO toDTO() => RecipientDTO( + id: storable.id, + createdAt: storable.createdAt, + updatedAt: storable.updatedAt, + permissionRef: permissionBound.permissionRef, + organizationRef: permissionBound.organizationRef, + name: name, + description: description, + email: email, + avatarUrl: avatarUrl, + status: _recipientStatusToValue(status), + type: _recipientTypeToValue(type), + isArchived: isArchived, + ); +} + +extension RecipientDTOMapper on RecipientDTO { + RecipientModel toDomain() => RecipientModel( + storable: newStorable(id: id, createdAt: createdAt, updatedAt: updatedAt), + permissionBound: newPermissionBound( + organizationBound: newOrganizationBound(organizationRef: organizationRef), + permissionRef: permissionRef, + ), + describable: newDescribable(name: name, description: description), + email: email, + avatarUrl: avatarUrl, + status: _recipientStatusFromValue(status), + type: _recipientTypeFromValue(type), + isArchived: isArchived, + ); +} + +RecipientStatus _recipientStatusFromValue(String value) { + switch (value) { + case 'ready': + return RecipientStatus.ready; + case 'registered': + return RecipientStatus.registered; + case 'notRegistered': + return RecipientStatus.notRegistered; + default: + return RecipientStatus.ready; + } +} + +String _recipientStatusToValue(RecipientStatus status) { + switch (status) { + case RecipientStatus.ready: + return 'ready'; + case RecipientStatus.registered: + return 'registered'; + case RecipientStatus.notRegistered: + return 'notRegistered'; + } +} + +RecipientType _recipientTypeFromValue(String value) { + switch (value) { + case 'external': + return RecipientType.external; + case 'internal': + default: + return RecipientType.internal; + } +} + +String _recipientTypeToValue(RecipientType type) { + switch (type) { + case RecipientType.internal: + return 'internal'; + case RecipientType.external: + return 'external'; + } +} diff --git a/frontend/pshared/lib/models/payment/methods/crypto_address.dart b/frontend/pshared/lib/models/payment/methods/crypto_address.dart new file mode 100644 index 0000000..acc8b92 --- /dev/null +++ b/frontend/pshared/lib/models/payment/methods/crypto_address.dart @@ -0,0 +1,18 @@ +import 'package:pshared/models/payment/methods/data.dart'; +import 'package:pshared/models/payment/type.dart'; + + +class CryptoAddressPaymentMethod extends PaymentMethodData { + @override + final PaymentType type = PaymentType.cryptoAddress; + + final String address; + final String network; + final String? destinationTag; + + CryptoAddressPaymentMethod({ + required this.address, + required this.network, + this.destinationTag, + }); +} diff --git a/frontend/pshared/lib/models/payment/payment_method.dart b/frontend/pshared/lib/models/payment/payment_method.dart new file mode 100644 index 0000000..0ca888a --- /dev/null +++ b/frontend/pshared/lib/models/payment/payment_method.dart @@ -0,0 +1,46 @@ +import 'package:pshared/models/payment/methods/data.dart'; +import 'package:pshared/models/payment/type.dart'; +import 'package:pshared/models/permissions/bound.dart'; +import 'package:pshared/models/storable.dart'; + + +class PaymentMethodModel implements PermissionBound, Storable { + final Storable storable; + final PermissionBound permissionBound; + final String recipientRef; + final PaymentMethodData data; + final bool isArchived; + + const PaymentMethodModel({ + required this.storable, + required this.permissionBound, + required this.recipientRef, + required this.data, + this.isArchived = false, + }); + + PaymentType get type => data.type; + + @override + String get id => storable.id; + @override + DateTime get createdAt => storable.createdAt; + @override + DateTime get updatedAt => storable.updatedAt; + + @override + String get organizationRef => permissionBound.organizationRef; + @override + String get permissionRef => permissionBound.permissionRef; + + PaymentMethodModel copyWith({ + PaymentMethodData? data, + bool? isArchived, + }) => PaymentMethodModel( + storable: storable, + permissionBound: permissionBound, + recipientRef: recipientRef, + data: data ?? this.data, + isArchived: isArchived ?? this.isArchived, + ); +} diff --git a/frontend/pshared/lib/models/payment/type.dart b/frontend/pshared/lib/models/payment/type.dart index 0dd75d6..d263401 100644 --- a/frontend/pshared/lib/models/payment/type.dart +++ b/frontend/pshared/lib/models/payment/type.dart @@ -3,4 +3,5 @@ enum PaymentType { iban, wallet, card, + cryptoAddress, } diff --git a/frontend/pshared/lib/models/recipient/recipient.dart b/frontend/pshared/lib/models/recipient/recipient.dart index f131920..43cdbfc 100644 --- a/frontend/pshared/lib/models/recipient/recipient.dart +++ b/frontend/pshared/lib/models/recipient/recipient.dart @@ -1,5 +1,6 @@ import 'package:pshared/models/payment/methods/card.dart'; import 'package:pshared/models/payment/methods/iban.dart'; +import 'package:pshared/models/payment/methods/crypto_address.dart'; import 'package:pshared/models/payment/methods/russian_bank.dart'; import 'package:pshared/models/payment/methods/wallet.dart'; import 'package:pshared/models/recipient/status.dart'; @@ -16,6 +17,7 @@ class Recipient { final IbanPaymentMethod? iban; final RussianBankAccountPaymentMethod? bank; final WalletPaymentMethod? wallet; + final CryptoAddressPaymentMethod? cryptoAddress; const Recipient({ this.avatarUrl, @@ -27,6 +29,7 @@ class Recipient { this.iban, this.bank, this.wallet, + this.cryptoAddress, }); /// Convenience factory for quickly creating mock recipients. @@ -39,6 +42,7 @@ class Recipient { IbanPaymentMethod? iban, RussianBankAccountPaymentMethod? bank, WalletPaymentMethod? wallet, + CryptoAddressPaymentMethod? cryptoAddress, }) => Recipient( avatarUrl: null, @@ -50,6 +54,7 @@ class Recipient { iban: iban, bank: bank, wallet: wallet, + cryptoAddress: cryptoAddress, ); bool matchesQuery(String q) { @@ -71,6 +76,9 @@ class Recipient { bank?.bik, bank?.correspondentAccount, wallet?.walletId, + cryptoAddress?.address, + cryptoAddress?.network, + cryptoAddress?.destinationTag, ]; return searchable.any((field) => field?.toLowerCase().contains(q) ?? false); diff --git a/frontend/pshared/lib/models/recipient/recipient_model.dart b/frontend/pshared/lib/models/recipient/recipient_model.dart new file mode 100644 index 0000000..b9a6fd7 --- /dev/null +++ b/frontend/pshared/lib/models/recipient/recipient_model.dart @@ -0,0 +1,64 @@ +import 'package:pshared/models/describable.dart'; +import 'package:pshared/models/permissions/bound/describable.dart'; +import 'package:pshared/models/permissions/bound.dart'; +import 'package:pshared/models/recipient/status.dart'; +import 'package:pshared/models/recipient/type.dart'; +import 'package:pshared/models/storable.dart'; + + +class RecipientModel implements PermissionBoundStorableDescribable { + final Storable storable; + final PermissionBound permissionBound; + final Describable describable; + final String email; + final String? avatarUrl; + final RecipientStatus status; + final RecipientType type; + final bool isArchived; + + const RecipientModel({ + required this.storable, + required this.permissionBound, + required this.describable, + required this.email, + required this.status, + required this.type, + this.avatarUrl, + this.isArchived = false, + }); + + @override + String get id => storable.id; + @override + DateTime get createdAt => storable.createdAt; + @override + DateTime get updatedAt => storable.updatedAt; + + @override + String get organizationRef => permissionBound.organizationRef; + @override + String get permissionRef => permissionBound.permissionRef; + + @override + String get name => describable.name; + @override + String? get description => describable.description; + + RecipientModel copyWith({ + Describable? describable, + String? email, + String? Function()? avatarUrl, + RecipientStatus? status, + RecipientType? type, + bool? isArchived, + }) => RecipientModel( + storable: storable, + permissionBound: permissionBound, + describable: describableCopyWithOther(this.describable, describable), + email: email ?? this.email, + avatarUrl: avatarUrl != null ? avatarUrl() : this.avatarUrl, + status: status ?? this.status, + type: type ?? this.type, + isArchived: isArchived ?? this.isArchived, + ); +} diff --git a/frontend/pweb/lib/pages/address_book/form/page.dart b/frontend/pweb/lib/pages/address_book/form/page.dart index a970ca8..635a3b5 100644 --- a/frontend/pweb/lib/pages/address_book/form/page.dart +++ b/frontend/pweb/lib/pages/address_book/form/page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:pshared/models/payment/methods/card.dart'; +import 'package:pshared/models/payment/methods/crypto_address.dart'; import 'package:pshared/models/payment/methods/iban.dart'; import 'package:pshared/models/payment/methods/russian_bank.dart'; import 'package:pshared/models/payment/methods/wallet.dart'; @@ -46,6 +47,7 @@ class _AdressBookRecipientFormState extends State { if (r?.iban != null) _methods[PaymentType.iban] = r!.iban; if (r?.wallet != null) _methods[PaymentType.wallet] = r!.wallet; if (r?.bank != null) _methods[PaymentType.bankAccount] = r!.bank; + if (r?.cryptoAddress != null) _methods[PaymentType.cryptoAddress] = r!.cryptoAddress; } //TODO Change when registration is ready @@ -74,6 +76,7 @@ class _AdressBookRecipientFormState extends State { iban: _methods[PaymentType.iban] as IbanPaymentMethod?, wallet: _methods[PaymentType.wallet] as WalletPaymentMethod?, bank: _methods[PaymentType.bankAccount] as RussianBankAccountPaymentMethod?, + cryptoAddress: _methods[PaymentType.cryptoAddress] as CryptoAddressPaymentMethod?, ); widget.onSaved?.call(recipient); @@ -106,4 +109,4 @@ class _AdressBookRecipientFormState extends State { }, ); } -} \ No newline at end of file +} diff --git a/frontend/pweb/lib/pages/address_book/page/recipient/payment_row.dart b/frontend/pweb/lib/pages/address_book/page/recipient/payment_row.dart index 1cd3aaf..a38626d 100644 --- a/frontend/pweb/lib/pages/address_book/page/recipient/payment_row.dart +++ b/frontend/pweb/lib/pages/address_book/page/recipient/payment_row.dart @@ -41,7 +41,12 @@ class RecipientPaymentRow extends StatelessWidget { type: PaymentType.wallet, value: recipient.wallet!.walletId ), + if (recipient.cryptoAddress?.address.isNotEmpty ?? false) + RecipientAddressBookInfoRow( + type: PaymentType.cryptoAddress, + value: recipient.cryptoAddress!.address, + ), ], ); } -} \ No newline at end of file +} diff --git a/frontend/pweb/lib/pages/dashboard/payouts/single/adress_book/long_list/item.dart b/frontend/pweb/lib/pages/dashboard/payouts/single/adress_book/long_list/item.dart index 76c9c74..c5dc447 100644 --- a/frontend/pweb/lib/pages/dashboard/payouts/single/adress_book/long_list/item.dart +++ b/frontend/pweb/lib/pages/dashboard/payouts/single/adress_book/long_list/item.dart @@ -73,6 +73,11 @@ class RecipientItem extends StatelessWidget { label: getPaymentTypeLabel(context, PaymentType.wallet), value: recipient.wallet!.walletId, ), + if (recipient.cryptoAddress?.address.isNotEmpty == true) + PaymentInfoRow( + label: getPaymentTypeLabel(context, PaymentType.cryptoAddress), + value: recipient.cryptoAddress!.address, + ), ], ), ], diff --git a/frontend/pweb/lib/pages/payment_methods/add/crypto_address.dart b/frontend/pweb/lib/pages/payment_methods/add/crypto_address.dart new file mode 100644 index 0000000..d848d69 --- /dev/null +++ b/frontend/pweb/lib/pages/payment_methods/add/crypto_address.dart @@ -0,0 +1,101 @@ +import 'package:flutter/material.dart'; + +import 'package:pshared/models/payment/methods/crypto_address.dart'; + +import 'package:pweb/utils/text_field_styles.dart'; + + +class CryptoAddressForm extends StatefulWidget { + final void Function(CryptoAddressPaymentMethod) onChanged; + final CryptoAddressPaymentMethod? initialData; + final bool isEditable; + + const CryptoAddressForm({ + super.key, + required this.onChanged, + this.initialData, + required this.isEditable, + }); + + @override + State createState() => _CryptoAddressFormState(); +} + +class _CryptoAddressFormState extends State { + late TextEditingController _addressCtrl; + late TextEditingController _networkCtrl; + late TextEditingController _destinationTagCtrl; + + @override + void initState() { + super.initState(); + _addressCtrl = TextEditingController(text: widget.initialData?.address); + _networkCtrl = TextEditingController(text: widget.initialData?.network); + _destinationTagCtrl = TextEditingController(text: widget.initialData?.destinationTag); + } + + void _emit() { + if (_addressCtrl.text.isNotEmpty && _networkCtrl.text.isNotEmpty) { + widget.onChanged( + CryptoAddressPaymentMethod( + address: _addressCtrl.text, + network: _networkCtrl.text, + destinationTag: _destinationTagCtrl.text.isNotEmpty ? _destinationTagCtrl.text : null, + ), + ); + } + } + + @override + void didUpdateWidget(covariant CryptoAddressForm oldWidget) { + super.didUpdateWidget(oldWidget); + final newData = widget.initialData; + final oldData = oldWidget.initialData; + + if (newData == null && oldData != null) { + _addressCtrl.clear(); + _networkCtrl.clear(); + _destinationTagCtrl.clear(); + return; + } + + if (newData != null && newData != oldData) { + _addressCtrl.text = newData.address; + _networkCtrl.text = newData.network; + _destinationTagCtrl.text = newData.destinationTag ?? ''; + } + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + TextFormField( + readOnly: !widget.isEditable, + controller: _addressCtrl, + decoration: getInputDecoration(context, 'Crypto address', widget.isEditable), + style: getTextFieldStyle(context, widget.isEditable), + onChanged: (_) => _emit(), + validator: (val) => (val?.isEmpty ?? true) ? 'Enter crypto address' : null, + ), + const SizedBox(height: 12), + TextFormField( + readOnly: !widget.isEditable, + controller: _networkCtrl, + decoration: getInputDecoration(context, 'Network', widget.isEditable), + style: getTextFieldStyle(context, widget.isEditable), + onChanged: (_) => _emit(), + validator: (val) => (val?.isEmpty ?? true) ? 'Enter network' : null, + ), + const SizedBox(height: 12), + TextFormField( + readOnly: !widget.isEditable, + controller: _destinationTagCtrl, + decoration: getInputDecoration(context, 'Destination tag / memo (optional)', widget.isEditable), + style: getTextFieldStyle(context, widget.isEditable), + onChanged: (_) => _emit(), + ), + ], + ); + } +} diff --git a/frontend/pweb/lib/pages/payment_methods/form.dart b/frontend/pweb/lib/pages/payment_methods/form.dart index 0010913..92f2314 100644 --- a/frontend/pweb/lib/pages/payment_methods/form.dart +++ b/frontend/pweb/lib/pages/payment_methods/form.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; import 'package:pshared/models/payment/methods/card.dart'; +import 'package:pshared/models/payment/methods/crypto_address.dart'; import 'package:pshared/models/payment/methods/iban.dart'; import 'package:pshared/models/payment/methods/russian_bank.dart'; import 'package:pshared/models/payment/methods/wallet.dart'; import 'package:pshared/models/payment/type.dart'; import 'package:pweb/pages/payment_methods/add/card.dart'; +import 'package:pweb/pages/payment_methods/add/crypto_address.dart'; import 'package:pweb/pages/payment_methods/add/iban.dart'; import 'package:pweb/pages/payment_methods/add/russian_bank.dart'; import 'package:pweb/pages/payment_methods/add/wallet.dart'; @@ -49,6 +51,11 @@ class PaymentMethodForm extends StatelessWidget { initialData: initialData as RussianBankAccountPaymentMethod?, isEditable: isEditable, ), + PaymentType.cryptoAddress => CryptoAddressForm( + onChanged: onChanged, + initialData: initialData as CryptoAddressPaymentMethod?, + isEditable: isEditable, + ), _ => const SizedBox.shrink(), }; } diff --git a/frontend/pweb/lib/pages/payment_methods/icon.dart b/frontend/pweb/lib/pages/payment_methods/icon.dart index faab1be..bc38a2a 100644 --- a/frontend/pweb/lib/pages/payment_methods/icon.dart +++ b/frontend/pweb/lib/pages/payment_methods/icon.dart @@ -13,5 +13,7 @@ IconData iconForPaymentType(PaymentType type) { return Icons.account_balance_wallet; case PaymentType.card: return Icons.credit_card; + case PaymentType.cryptoAddress: + return Icons.currency_bitcoin; } } diff --git a/frontend/pweb/lib/providers/page_selector.dart b/frontend/pweb/lib/providers/page_selector.dart index c113eff..7f1a6a5 100644 --- a/frontend/pweb/lib/providers/page_selector.dart +++ b/frontend/pweb/lib/providers/page_selector.dart @@ -148,6 +148,7 @@ class PageSelectorProvider extends ChangeNotifier { if (recipient.iban != null) PaymentType.iban: recipient.iban!, if (recipient.wallet != null) PaymentType.wallet: recipient.wallet!, if (recipient.bank != null) PaymentType.bankAccount: recipient.bank!, + if (recipient.cryptoAddress != null) PaymentType.cryptoAddress: recipient.cryptoAddress!, }; } diff --git a/frontend/pweb/lib/utils/payment/label.dart b/frontend/pweb/lib/utils/payment/label.dart index 11b040b..75aea00 100644 --- a/frontend/pweb/lib/utils/payment/label.dart +++ b/frontend/pweb/lib/utils/payment/label.dart @@ -12,5 +12,6 @@ String getPaymentTypeLabel(BuildContext context, PaymentType type) { PaymentType.bankAccount => l10n.paymentTypeBankAccount, PaymentType.iban => l10n.paymentTypeIban, PaymentType.wallet => l10n.paymentTypeWallet, + PaymentType.cryptoAddress => 'Crypto address', }; }