This commit is contained in:
Stephan D
2026-03-10 12:31:09 +01:00
parent d87e709f43
commit e77d1ab793
287 changed files with 2089 additions and 1550 deletions

View File

@@ -0,0 +1,47 @@
version: "2"
linters:
default: none
enable:
- bodyclose
- canonicalheader
- copyloopvar
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- gosec
- govet
- ineffassign
- nilerr
- nilnesserr
- nilnil
- noctx
- rowserrcheck
- sqlclosecheck
- staticcheck
- unconvert
- wastedassign
disable:
- depguard
- exhaustruct
- gochecknoglobals
- gochecknoinits
- gomoddirectives
- wrapcheck
- cyclop
- dupl
- funlen
- gocognit
- gocyclo
- ireturn
- lll
- mnd
- nestif
- nlreturn
- noinlineerr
- paralleltest
- tagliatelle
- testpackage
- varnamelen
- wsl_v5

View File

@@ -321,11 +321,13 @@ func (c *chainGatewayClient) callContext(ctx context.Context) (context.Context,
if timeout <= 0 {
timeout = 3 * time.Second
}
//nolint:gosec // Caller receives cancel func and defers it in every call path.
return context.WithTimeout(ctx, timeout)
}
func walletParamsFromRequest(req *chainv1.CreateManagedWalletRequest) (*structpb.Struct, error) {
if req == nil {
//nolint:nilnil // Nil request means optional params are absent.
return nil, nil
}
params := map[string]interface{}{

View File

@@ -31,7 +31,7 @@ func New(logger mlogger.Logger, cfg Config) (*Manager, error) {
}
keys, err := managedkey.New(managedkey.Options{
Logger: logger,
Config: managedkey.Config(cfg),
Config: cfg,
Component: "vault key manager",
DefaultKeyPrefix: "gateway/chain/wallets",
})

View File

@@ -264,6 +264,7 @@ func resolveNetworkConfigs(logger mlogger.Logger, chains []chainConfig) ([]gatew
func buildGasTopUpPolicy(chainName pmodel.ChainNetwork, cfg *gasTopUpPolicyConfig) (*gatewayshared.GasTopUpPolicy, error) {
if cfg == nil {
//nolint:nilnil // Nil config means gas top-up policy is intentionally disabled.
return nil, nil
}
defaultRule, defaultSet, err := parseGasTopUpRule(chainName, "default", cfg.gasTopUpRuleConfig)

View File

@@ -223,6 +223,7 @@ func defaultGasTopUp(estimatedFee *moneyv1.Money, currentBalance *moneyv1.Money)
}
required := estimated.Sub(current)
if !required.IsPositive() {
//nolint:nilnil // No top-up required is represented as (nil, nil).
return nil, nil
}
return &moneyv1.Money{

View File

@@ -143,7 +143,7 @@ func (c *createManagedWalletCommand) Execute(ctx context.Context, req *chainv1.C
Metadata: metadata,
}
if description != nil {
wallet.Describable.Description = description
wallet.Description = description
}
created, err := c.deps.Storage.Wallets().Create(ctx, wallet)

View File

@@ -42,19 +42,19 @@ func (s *Service) GetCapabilities(_ context.Context, _ *connectorv1.GetCapabilit
func (s *Service) OpenAccount(ctx context.Context, req *connectorv1.OpenAccountRequest) (*connectorv1.OpenAccountResponse, error) {
if req == nil {
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "open_account: request is required", nil, "")}, nil
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "open_account: request is required", nil)}, nil
}
if req.GetKind() != connectorv1.AccountKind_CHAIN_MANAGED_WALLET {
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_UNSUPPORTED_ACCOUNT_KIND, "open_account: unsupported account kind", nil, "")}, nil
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_UNSUPPORTED_ACCOUNT_KIND, "open_account: unsupported account kind", nil)}, nil
}
reader := params.New(req.GetParams())
orgRef := strings.TrimSpace(reader.String("organization_ref"))
if orgRef == "" {
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "open_account: organization_ref is required", nil, "")}, nil
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "open_account: organization_ref is required", nil)}, nil
}
asset, err := parseChainAsset(strings.TrimSpace(req.GetAsset()), reader)
if err != nil {
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), nil, "")}, nil
return &connectorv1.OpenAccountResponse{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), nil)}, nil
}
resp, err := s.CreateManagedWallet(ctx, &chainv1.CreateManagedWalletRequest{
@@ -66,7 +66,7 @@ func (s *Service) OpenAccount(ctx context.Context, req *connectorv1.OpenAccountR
Describable: describableFromLabel(req.GetLabel(), reader.String("description")),
})
if err != nil {
return &connectorv1.OpenAccountResponse{Error: connectorError(mapErrorCode(err), err.Error(), nil, "")}, nil
return &connectorv1.OpenAccountResponse{Error: connectorError(mapErrorCode(err), err.Error(), nil)}, nil
}
return &connectorv1.OpenAccountResponse{Account: chainWalletToAccount(resp.GetWallet())}, nil
}
@@ -136,32 +136,32 @@ func (s *Service) GetBalance(ctx context.Context, req *connectorv1.GetBalanceReq
func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOperationRequest) (*connectorv1.SubmitOperationResponse, error) {
if req == nil || req.GetOperation() == nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "submit_operation: operation is required", nil, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "submit_operation: operation is required", nil)}}, nil
}
op := req.GetOperation()
if strings.TrimSpace(op.GetIdempotencyKey()) == "" {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "submit_operation: idempotency_key is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "submit_operation: idempotency_key is required", op)}}, nil
}
reader := params.New(op.GetParams())
orgRef := strings.TrimSpace(reader.String("organization_ref"))
source := operationAccountID(op.GetFrom())
if source == "" {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "operation: from.account is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "operation: from.account is required", op)}}, nil
}
switch op.GetType() {
case connectorv1.OperationType_TRANSFER:
dest, err := transferDestinationFromOperation(op)
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op)}}, nil
}
amount := op.GetMoney()
if amount == nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "transfer: money is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "transfer: money is required", op)}}, nil
}
amount = normalizeMoneyForChain(amount)
if orgRef == "" {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "transfer: organization_ref is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "transfer: organization_ref is required", op)}}, nil
}
resp, err := s.SubmitTransfer(ctx, &chainv1.SubmitTransferRequest{
IdempotencyKey: strings.TrimSpace(op.GetIdempotencyKey()),
@@ -176,7 +176,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
PaymentRef: strings.TrimSpace(reader.String("payment_ref")),
})
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op)}}, nil
}
transfer := resp.GetTransfer()
return &connectorv1.SubmitOperationResponse{
@@ -189,11 +189,11 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
case connectorv1.OperationType_FEE_ESTIMATE:
dest, err := transferDestinationFromOperation(op)
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op)}}, nil
}
amount := op.GetMoney()
if amount == nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "estimate: money is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "estimate: money is required", op)}}, nil
}
amount = normalizeMoneyForChain(amount)
opID := strings.TrimSpace(op.GetOperationId())
@@ -206,7 +206,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
Amount: amount,
})
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op)}}, nil
}
result := feeEstimateResult(resp)
return &connectorv1.SubmitOperationResponse{
@@ -219,7 +219,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
case connectorv1.OperationType_GAS_TOPUP:
fee, err := parseMoneyFromMap(reader.Map("estimated_total_fee"))
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, err.Error(), op)}}, nil
}
fee = normalizeMoneyForChain(fee)
mode := strings.ToLower(strings.TrimSpace(reader.String("mode")))
@@ -237,7 +237,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
EstimatedTotalFee: fee,
})
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op)}}, nil
}
return &connectorv1.SubmitOperationResponse{
Receipt: &connectorv1.OperationReceipt{
@@ -252,11 +252,11 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
opID = strings.TrimSpace(op.GetIdempotencyKey())
}
if orgRef == "" {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: organization_ref is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: organization_ref is required", op)}}, nil
}
target := strings.TrimSpace(reader.String("target_wallet_ref"))
if target == "" {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: target_wallet_ref is required", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: target_wallet_ref is required", op)}}, nil
}
resp, err := s.EnsureGasTopUp(ctx, &chainv1.EnsureGasTopUpRequest{
IdempotencyKey: strings.TrimSpace(op.GetIdempotencyKey()),
@@ -270,7 +270,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
PaymentRef: strings.TrimSpace(reader.String("payment_ref")),
})
if err != nil {
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op)}}, nil
}
transferRef := ""
if transfer := resp.GetTransfer(); transfer != nil {
@@ -284,10 +284,10 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
},
}, nil
default:
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: invalid mode", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_INVALID_PARAMS, "gas_topup: invalid mode", op)}}, nil
}
default:
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_UNSUPPORTED_OPERATION, "submit_operation: unsupported operation type", op, "")}}, nil
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(connectorv1.ErrorCode_UNSUPPORTED_OPERATION, "submit_operation: unsupported operation type", op)}}, nil
}
}
@@ -722,11 +722,10 @@ func structFromMap(values map[string]interface{}) *structpb.Struct {
return result
}
func connectorError(code connectorv1.ErrorCode, message string, op *connectorv1.Operation, accountID string) *connectorv1.ConnectorError {
func connectorError(code connectorv1.ErrorCode, message string, op *connectorv1.Operation) *connectorv1.ConnectorError {
err := &connectorv1.ConnectorError{
Code: code,
Message: strings.TrimSpace(message),
AccountId: strings.TrimSpace(accountID),
Code: code,
Message: strings.TrimSpace(message),
}
if op != nil {
err.CorrelationId = strings.TrimSpace(op.GetCorrelationId())

View File

@@ -297,7 +297,7 @@ func EstimateFee(ctx context.Context, deps driver.Deps, network shared.Network,
GasPrice: gasPrice,
Value: amountBase,
}
gasLimit, err := estimateGas(timeoutCtx, network, client, rpcClient, callMsg)
gasLimit, err := estimateGas(timeoutCtx, client, callMsg)
if err != nil {
logger.Warn("Failed to estimate gas", zap.Error(err), zap.Any("call_mesasge", callMsg))
return nil, merrors.Internal("failed to estimate gas: " + err.Error())
@@ -345,7 +345,7 @@ func EstimateFee(ctx context.Context, deps driver.Deps, network shared.Network,
GasPrice: gasPrice,
Data: input,
}
gasLimit, err := estimateGas(timeoutCtx, network, client, rpcClient, callMsg)
gasLimit, err := estimateGas(timeoutCtx, client, callMsg)
if err != nil {
logger.Warn("Failed to estimate gas", zap.Error(err), zap.Any("call_message", callMsg))
return nil, merrors.Internal("failed to estimate gas: " + err.Error())
@@ -456,7 +456,7 @@ func SubmitTransfer(ctx context.Context, deps driver.Deps, network shared.Networ
GasPrice: gasPrice,
Value: amountInt,
}
gasLimit, err := estimateGas(ctx, network, client, rpcClient, callMsg)
gasLimit, err := estimateGas(ctx, client, callMsg)
if err != nil {
logger.Warn("Failed to estimate gas", zap.Error(err),
zap.String("transfer_ref", transfer.TransferRef),
@@ -504,7 +504,7 @@ func SubmitTransfer(ctx context.Context, deps driver.Deps, network shared.Networ
GasPrice: gasPrice,
Data: input,
}
gasLimit, err := estimateGas(ctx, network, client, rpcClient, callMsg)
gasLimit, err := estimateGas(ctx, client, callMsg)
if err != nil {
logger.Warn("Failed to estimate gas", zap.Error(err),
zap.String("transfer_ref", transfer.TransferRef),
@@ -653,26 +653,10 @@ type gasEstimator interface {
EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error)
}
func estimateGas(ctx context.Context, network shared.Network, client gasEstimator, rpcClient *rpc.Client, callMsg ethereum.CallMsg) (uint64, error) {
func estimateGas(ctx context.Context, client gasEstimator, callMsg ethereum.CallMsg) (uint64, error) {
return client.EstimateGas(ctx, callMsg)
}
func estimateGasTron(ctx context.Context, rpcClient *rpc.Client, callMsg ethereum.CallMsg) (uint64, error) {
call := tronEstimateCall(callMsg)
var hexResp string
if err := rpcClient.CallContext(ctx, &hexResp, "eth_estimateGas", call); err != nil {
return 0, err
}
val, err := shared.DecodeHexBig(hexResp)
if err != nil {
return 0, err
}
if val == nil {
return 0, merrors.Internal("failed to decode gas estimate")
}
return val.Uint64(), nil
}
func tronEstimateCall(callMsg ethereum.CallMsg) map[string]string {
call := make(map[string]string)
if callMsg.From != (common.Address{}) {

View File

@@ -24,15 +24,15 @@ func (s *Service) outboxStore() gatewayoutbox.Store {
return provider.Outbox()
}
func (s *Service) startOutboxReliableProducer() error {
func (s *Service) startOutboxReliableProducer(_ context.Context) error {
if s == nil || s.storage == nil {
return nil
}
return s.outbox.Start(s.logger, s.producer, s.outboxStore(), s.msgCfg)
return s.outbox.Start(s.logger, s.producer, s.outboxStore(), s.msgCfg) //nolint:contextcheck // Reliable runtime start API does not accept context.
}
func (s *Service) sendWithOutbox(ctx context.Context, env me.Envelope) error {
if err := s.startOutboxReliableProducer(); err != nil {
if err := s.startOutboxReliableProducer(ctx); err != nil {
return err
}
return s.outbox.Send(ctx, env)

View File

@@ -163,7 +163,9 @@ func (l *loggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
}
bodyBytes, _ := io.ReadAll(resp.Body)
resp.Body.Close()
if closeErr := resp.Body.Close(); closeErr != nil {
l.logger.Warn("Failed to close RPC response body", append(fields, zap.Error(closeErr))...)
}
resp.Body = io.NopCloser(strings.NewReader(string(bodyBytes)))
respFields := append(fields,

View File

@@ -89,7 +89,7 @@ func NewService(logger mlogger.Logger, repo storage.Repository, producer msg.Pro
}
svc.settings = svc.settings.withDefaults()
svc.networkRegistry = rpcclient.NewRegistry(svc.networks, svc.rpcClients)
if err := svc.startOutboxReliableProducer(); err != nil {
if err := svc.startOutboxReliableProducer(context.Background()); err != nil {
svc.logger.Warn("Failed to initialise outbox reliable producer", zap.Error(err))
}
@@ -231,7 +231,7 @@ func (s *Service) startDiscoveryAnnouncers() {
InvokeURI: s.invokeURI,
Version: version,
}
announcer := discovery.NewAnnouncer(s.logger, s.producer, string(mservice.ChainGateway), announce)
announcer := discovery.NewAnnouncer(s.logger, s.producer, mservice.ChainGateway, announce)
announcer.Start()
s.announcers = append(s.announcers, announcer)
}

View File

@@ -272,7 +272,7 @@ type walletsNoDataRepository struct {
}
func (r *walletsNoDataRepository) Wallets() storage.WalletsStore {
return &walletsNoDataStore{WalletsStore: r.inMemoryRepository.wallets}
return &walletsNoDataStore{WalletsStore: r.wallets}
}
type walletsNoDataStore struct {
@@ -673,10 +673,11 @@ func sanitizeLimit(requested int32, def, max int64) int64 {
if requested <= 0 {
return def
}
if requested > int32(max) {
requested64 := int64(requested)
if requested64 > max {
return max
}
return int64(requested)
return requested64
}
func newTestService(t *testing.T) (*Service, *inMemoryRepository) {

View File

@@ -1,6 +1,7 @@
package shared
import (
"math"
"math/big"
"strings"
@@ -46,5 +47,9 @@ func DecodeHexUint8(input string) (uint8, error) {
if val.BitLen() > 8 {
return 0, errHexOutOfRange
}
return uint8(val.Uint64()), nil
decoded := val.Uint64()
if decoded > math.MaxUint8 {
return 0, errHexOutOfRange
}
return uint8(decoded), nil
}

View File

@@ -41,26 +41,26 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
return err
}
if _, err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusProcessing, "", ""); err != nil {
if err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusProcessing, "", ""); err != nil {
s.logger.Warn("Failed to update transfer status to signing", zap.String("transfer_ref", transferRef), zap.Error(err))
}
driverDeps := s.driverDeps()
chainDriver, err := s.driverForNetwork(network.Name)
if err != nil {
_, _ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
_ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
return err
}
destinationAddress, err := s.destinationAddress(ctx, chainDriver, transfer.Destination)
if err != nil {
_, _ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
_ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
return err
}
sourceAddress, err := chainDriver.NormalizeAddress(sourceWallet.DepositAddress)
if err != nil {
_, _ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
_ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
return err
}
if chainDriver.Name() == "tron" && sourceAddress == destinationAddress {
@@ -69,7 +69,7 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
zap.String("wallet_ref", sourceWalletRef),
zap.String("network", string(network.Name)),
)
if _, err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusSuccess, "", ""); err != nil {
if err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusSuccess, "", ""); err != nil {
s.logger.Warn("Failed to update transfer status to confirmed", zap.String("transfer_ref", transferRef), zap.Error(err))
}
return nil
@@ -78,13 +78,13 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
txHash, err := chainDriver.SubmitTransfer(ctx, driverDeps, network, transfer, sourceWallet, destinationAddress)
if err != nil {
s.logger.Warn("Failed to submit transfer", zap.String("transfer_ref", transferRef), zap.Error(err))
if _, e := s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), ""); e != nil {
if e := s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), ""); e != nil {
s.logger.Warn("Failed to update transfer status to failed", zap.String("transfer_ref", transferRef), zap.Error(e))
}
return err
}
if _, err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusWaiting, "", txHash); err != nil {
if err := s.updateTransferStatus(ctx, transferRef, model.TransferStatusWaiting, "", txHash); err != nil {
s.logger.Warn("Failed to update transfer status to submitted", zap.String("transfer_ref", transferRef), zap.Error(err))
}
@@ -104,7 +104,7 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
failureReason = "transaction reverted"
pStatus = model.TransferStatusFailed
}
if _, err := s.updateTransferStatus(ctx, transferRef, pStatus, failureReason, txHash); err != nil {
if err := s.updateTransferStatus(ctx, transferRef, pStatus, failureReason, txHash); err != nil {
s.logger.Warn("Failed to update transfer status", zap.Error(err),
zap.String("transfer_ref", transferRef), zap.String("status", string(pStatus)))
}

View File

@@ -57,16 +57,16 @@ func toError(t *model.Transfer) string {
return t.FailureReason
}
func (s *Service) updateTransferStatus(ctx context.Context, transferRef string, status model.TransferStatus, failureReason, txHash string) (*model.Transfer, error) {
func (s *Service) updateTransferStatus(ctx context.Context, transferRef string, status model.TransferStatus, failureReason, txHash string) error {
if !isFinalTransferStatus(status) {
transfer, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, status, failureReason, txHash)
_, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, status, failureReason, txHash)
if err != nil {
s.logger.Warn("Failed to update transfer status", zap.String("transfer_ref", transferRef), zap.String("status", string(status)), zap.Error(err))
}
return transfer, err
return err
}
res, err := s.executeTransaction(ctx, func(txCtx context.Context) (any, error) {
_, err := s.executeTransaction(ctx, func(txCtx context.Context) (any, error) {
transfer, statusErr := s.storage.Transfers().UpdateStatus(txCtx, transferRef, status, failureReason, txHash)
if statusErr != nil {
return nil, statusErr
@@ -80,11 +80,9 @@ func (s *Service) updateTransferStatus(ctx context.Context, transferRef string,
})
if err != nil {
s.logger.Warn("Failed to update transfer status", zap.String("transfer_ref", transferRef), zap.String("status", string(status)), zap.Error(err))
return nil, err
return err
}
transfer, _ := res.(*model.Transfer)
return transfer, nil
return nil
}
func (s *Service) emitTransferStatusEvent(ctx context.Context, transfer *model.Transfer) error {

View File

@@ -6,7 +6,6 @@ import (
"github.com/tech/sendico/pkg/db/storable"
pkgmodel "github.com/tech/sendico/pkg/model"
pmodel "github.com/tech/sendico/pkg/model"
"github.com/tech/sendico/pkg/mservice"
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
)
@@ -67,7 +66,7 @@ type ManagedWalletFilter struct {
// - pointer to empty string: filter for wallets where owner_ref is empty
// - pointer to a value: filter for wallets where owner_ref matches
OwnerRefFilter *string
Network pmodel.ChainNetwork
Network pkgmodel.ChainNetwork
TokenSymbol string
Cursor string
Limit int32

View File

@@ -186,7 +186,6 @@ func (w *Wallets) List(ctx context.Context, filter model.ManagedWalletFilter) (*
if listErr != nil {
if errors.Is(listErr, merrors.ErrNoData) {
wallets = make([]model.ManagedWallet, 0)
listErr = nil
} else {
w.logger.Warn("Wallet list failed", append(fields, zap.Error(listErr))...)
return nil, listErr