refactored payment orchestration
This commit is contained in:
@@ -126,9 +126,11 @@ func (c *ensureGasTopUpCommand) Execute(ctx context.Context, req *chainv1.Ensure
|
||||
Destination: &chainv1.TransferDestination{
|
||||
Destination: &chainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: targetWalletRef},
|
||||
},
|
||||
Amount: topUp,
|
||||
Metadata: shared.CloneMetadata(req.GetMetadata()),
|
||||
ClientReference: strings.TrimSpace(req.GetClientReference()),
|
||||
Amount: topUp,
|
||||
Metadata: shared.CloneMetadata(req.GetMetadata()),
|
||||
PaymentRef: strings.TrimSpace(req.GetPaymentRef()),
|
||||
IntentRef: strings.TrimSpace(req.GetIntentRef()),
|
||||
OperationRef: strings.TrimSpace(req.GetOperationRef()),
|
||||
}
|
||||
|
||||
submitResponder := NewSubmitTransfer(c.deps.WithLogger("transfer.submit")).Execute(ctx, submitReq)
|
||||
|
||||
@@ -38,11 +38,12 @@ func toProtoTransfer(transfer *model.Transfer) *chainv1.Transfer {
|
||||
TransferRef: transfer.TransferRef,
|
||||
IdempotencyKey: transfer.IdempotencyKey,
|
||||
OrganizationRef: transfer.OrganizationRef,
|
||||
IntentRef: transfer.IntentRef,
|
||||
SourceWalletRef: transfer.SourceWalletRef,
|
||||
Destination: destination,
|
||||
Asset: asset,
|
||||
RequestedAmount: shared.CloneMoney(transfer.RequestedAmount),
|
||||
NetAmount: shared.CloneMoney(transfer.NetAmount),
|
||||
RequestedAmount: shared.MonenyToProto(transfer.RequestedAmount),
|
||||
NetAmount: shared.MonenyToProto(transfer.NetAmount),
|
||||
Fees: protoFees,
|
||||
Status: shared.TransferStatusToProto(transfer.Status),
|
||||
TransactionHash: transfer.TxHash,
|
||||
|
||||
@@ -38,6 +38,17 @@ func (c *submitTransferCommand) Execute(ctx context.Context, req *chainv1.Submit
|
||||
c.deps.Logger.Warn("Missing idempotency key")
|
||||
return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("idempotency_key is required"))
|
||||
}
|
||||
intentRef := strings.TrimSpace(req.GetIntentRef())
|
||||
if intentRef == "" {
|
||||
c.deps.Logger.Warn("Missing intent reference")
|
||||
return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("intentRef is required"))
|
||||
}
|
||||
operationRef := strings.TrimSpace(req.GetOperationRef())
|
||||
if operationRef == "" {
|
||||
c.deps.Logger.Warn("Missing operation reference")
|
||||
return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("operationRef is required"))
|
||||
}
|
||||
|
||||
organizationRef := strings.TrimSpace(req.GetOrganizationRef())
|
||||
if organizationRef == "" {
|
||||
c.deps.Logger.Warn("Missing organization ref")
|
||||
@@ -63,6 +74,11 @@ func (c *submitTransferCommand) Execute(ctx context.Context, req *chainv1.Submit
|
||||
c.deps.Logger.Warn("Missing amount value")
|
||||
return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("amount.amount is required"))
|
||||
}
|
||||
paymentRef := strings.TrimSpace(req.GetPaymentRef())
|
||||
if paymentRef == "" {
|
||||
c.deps.Logger.Warn("Missing payment reference")
|
||||
return gsresponse.InvalidArgument[chainv1.SubmitTransferResponse](c.deps.Logger, mservice.ChainGateway, merrors.InvalidArgument("payment reference is required", "paymentRef"))
|
||||
}
|
||||
|
||||
sourceWallet, err := c.deps.Storage.Wallets().Get(ctx, sourceWalletRef)
|
||||
if err != nil {
|
||||
@@ -123,6 +139,8 @@ func (c *submitTransferCommand) Execute(ctx context.Context, req *chainv1.Submit
|
||||
|
||||
transfer := &model.Transfer{
|
||||
IdempotencyKey: idempotencyKey,
|
||||
OperationRef: operationRef,
|
||||
IntentRef: intentRef,
|
||||
TransferRef: shared.GenerateTransferRef(),
|
||||
OrganizationRef: organizationRef,
|
||||
SourceWalletRef: sourceWalletRef,
|
||||
@@ -130,11 +148,11 @@ func (c *submitTransferCommand) Execute(ctx context.Context, req *chainv1.Submit
|
||||
Network: sourceWallet.Network,
|
||||
TokenSymbol: effectiveTokenSymbol,
|
||||
ContractAddress: effectiveContractAddress,
|
||||
RequestedAmount: shared.CloneMoney(amount),
|
||||
NetAmount: netAmount,
|
||||
RequestedAmount: shared.ProtoToMoney(amount),
|
||||
NetAmount: shared.ProtoToMoney(netAmount),
|
||||
PaymentRef: paymentRef,
|
||||
Fees: fees,
|
||||
Status: model.TransferStatusPending,
|
||||
ClientReference: strings.TrimSpace(req.GetClientReference()),
|
||||
Status: model.TransferStatusCreated,
|
||||
LastStatusAt: c.deps.Clock.Now().UTC(),
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,9 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
|
||||
Amount: amount,
|
||||
Fees: parseChainFees(reader),
|
||||
Metadata: shared.CloneMetadata(reader.StringMap("metadata")),
|
||||
ClientReference: strings.TrimSpace(reader.String("client_reference")),
|
||||
PaymentRef: strings.TrimSpace(reader.String("payment_ref")),
|
||||
IntentRef: strings.TrimSpace(op.GetIntentRef()),
|
||||
OperationRef: strings.TrimSpace(op.GetOperationRef()),
|
||||
})
|
||||
if err != nil {
|
||||
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
|
||||
@@ -208,7 +210,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
|
||||
return &connectorv1.SubmitOperationResponse{
|
||||
Receipt: &connectorv1.OperationReceipt{
|
||||
OperationId: opID,
|
||||
Status: connectorv1.OperationStatus_CONFIRMED,
|
||||
Status: connectorv1.OperationStatus_OPERATION_SUCCESS,
|
||||
Result: result,
|
||||
},
|
||||
}, nil
|
||||
@@ -238,7 +240,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
|
||||
return &connectorv1.SubmitOperationResponse{
|
||||
Receipt: &connectorv1.OperationReceipt{
|
||||
OperationId: opID,
|
||||
Status: connectorv1.OperationStatus_CONFIRMED,
|
||||
Status: connectorv1.OperationStatus_OPERATION_SUCCESS,
|
||||
Result: gasTopUpResult(resp.GetTopupAmount(), resp.GetCapHit(), ""),
|
||||
},
|
||||
}, nil
|
||||
@@ -256,12 +258,14 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
|
||||
}
|
||||
resp, err := s.EnsureGasTopUp(ctx, &chainv1.EnsureGasTopUpRequest{
|
||||
IdempotencyKey: strings.TrimSpace(op.GetIdempotencyKey()),
|
||||
IntentRef: strings.TrimSpace(op.GetIntentRef()),
|
||||
OperationRef: strings.TrimSpace(op.GetOperationRef()),
|
||||
OrganizationRef: orgRef,
|
||||
SourceWalletRef: source,
|
||||
TargetWalletRef: target,
|
||||
EstimatedTotalFee: fee,
|
||||
Metadata: shared.CloneMetadata(reader.StringMap("metadata")),
|
||||
ClientReference: strings.TrimSpace(reader.String("client_reference")),
|
||||
PaymentRef: strings.TrimSpace(reader.String("payment_ref")),
|
||||
})
|
||||
if err != nil {
|
||||
return &connectorv1.SubmitOperationResponse{Receipt: &connectorv1.OperationReceipt{Error: connectorError(mapErrorCode(err), err.Error(), op, "")}}, nil
|
||||
@@ -273,7 +277,7 @@ func (s *Service) SubmitOperation(ctx context.Context, req *connectorv1.SubmitOp
|
||||
return &connectorv1.SubmitOperationResponse{
|
||||
Receipt: &connectorv1.OperationReceipt{
|
||||
OperationId: opID,
|
||||
Status: connectorv1.OperationStatus_CONFIRMED,
|
||||
Status: shared.ChainTransferStatusToOperation(resp.GetTransfer().GetStatus()),
|
||||
Result: gasTopUpResult(resp.GetTopupAmount(), resp.GetCapHit(), transferRef),
|
||||
},
|
||||
}, nil
|
||||
@@ -544,25 +548,51 @@ func chainTransferToOperation(transfer *chainv1.Transfer) *connectorv1.Operation
|
||||
|
||||
func chainTransferStatusToOperation(status chainv1.TransferStatus) connectorv1.OperationStatus {
|
||||
switch status {
|
||||
case chainv1.TransferStatus_TRANSFER_CONFIRMED:
|
||||
return connectorv1.OperationStatus_CONFIRMED
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CREATED:
|
||||
return connectorv1.OperationStatus_OPERATION_CREATED
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_PROCESSING:
|
||||
return connectorv1.OperationStatus_OPERATION_PROCESSING
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_WAITING:
|
||||
return connectorv1.OperationStatus_OPERATION_WAITING
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_SUCCESS:
|
||||
return connectorv1.OperationStatus_OPERATION_SUCCESS
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_FAILED:
|
||||
return connectorv1.OperationStatus_FAILED
|
||||
return connectorv1.OperationStatus_OPERATION_FAILED
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CANCELLED:
|
||||
return connectorv1.OperationStatus_CANCELED
|
||||
return connectorv1.OperationStatus_OPERATION_CANCELLED
|
||||
|
||||
default:
|
||||
return connectorv1.OperationStatus_PENDING
|
||||
return connectorv1.OperationStatus_OPERATION_STATUS_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func chainStatusFromOperation(status connectorv1.OperationStatus) chainv1.TransferStatus {
|
||||
switch status {
|
||||
case connectorv1.OperationStatus_CONFIRMED:
|
||||
return chainv1.TransferStatus_TRANSFER_CONFIRMED
|
||||
case connectorv1.OperationStatus_FAILED:
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_CREATED:
|
||||
return chainv1.TransferStatus_TRANSFER_CREATED
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_PROCESSING:
|
||||
return chainv1.TransferStatus_TRANSFER_PROCESSING
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_WAITING:
|
||||
return chainv1.TransferStatus_TRANSFER_WAITING
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_SUCCESS:
|
||||
return chainv1.TransferStatus_TRANSFER_SUCCESS
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_FAILED:
|
||||
return chainv1.TransferStatus_TRANSFER_FAILED
|
||||
case connectorv1.OperationStatus_CANCELED:
|
||||
|
||||
case connectorv1.OperationStatus_OPERATION_CANCELLED:
|
||||
return chainv1.TransferStatus_TRANSFER_CANCELLED
|
||||
|
||||
default:
|
||||
return chainv1.TransferStatus_TRANSFER_STATUS_UNSPECIFIED
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package tron
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -157,9 +156,3 @@ func GetTransactionStatus(
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// isTronNetwork checks if the network name indicates a TRON network.
|
||||
func isTronNetwork(networkName string) bool {
|
||||
name := strings.ToLower(strings.TrimSpace(networkName))
|
||||
return strings.HasPrefix(name, "tron")
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) {
|
||||
IdempotencyKey: "transfer-1",
|
||||
OrganizationRef: "org-1",
|
||||
SourceWalletRef: srcRef,
|
||||
PaymentRef: "ref-1",
|
||||
Destination: &ichainv1.TransferDestination{
|
||||
Destination: &ichainv1.TransferDestination_ManagedWalletRef{ManagedWalletRef: dstRef},
|
||||
},
|
||||
@@ -172,6 +173,8 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) {
|
||||
Amount: &moneyv1.Money{Currency: "USDT", Amount: "5"},
|
||||
},
|
||||
},
|
||||
OperationRef: "oper-1",
|
||||
IntentRef: "intent-1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, transferResp.GetTransfer())
|
||||
@@ -179,7 +182,7 @@ func TestSubmitTransfer_ManagedDestination(t *testing.T) {
|
||||
|
||||
stored := repo.transfers.get(transferResp.GetTransfer().GetTransferRef())
|
||||
require.NotNil(t, stored)
|
||||
require.Equal(t, model.TransferStatusPending, stored.Status)
|
||||
require.Equal(t, model.TransferStatusCreated, stored.Status)
|
||||
|
||||
// GetTransfer
|
||||
getResp, err := svc.GetTransfer(ctx, &ichainv1.GetTransferRequest{TransferRef: stored.TransferRef})
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
"github.com/tech/sendico/gateway/tron/storage/model"
|
||||
chainasset "github.com/tech/sendico/pkg/chain"
|
||||
pmodel "github.com/tech/sendico/pkg/model"
|
||||
paymenttypes "github.com/tech/sendico/pkg/payments/types"
|
||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||
connectorv1 "github.com/tech/sendico/pkg/proto/connector/v1"
|
||||
chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
@@ -77,42 +79,82 @@ func ManagedWalletStatusToProto(status model.ManagedWalletStatus) chainv1.Manage
|
||||
|
||||
func TransferStatusToModel(status chainv1.TransferStatus) model.TransferStatus {
|
||||
switch status {
|
||||
case chainv1.TransferStatus_TRANSFER_PENDING:
|
||||
return model.TransferStatusPending
|
||||
case chainv1.TransferStatus_TRANSFER_SIGNING:
|
||||
return model.TransferStatusSigning
|
||||
case chainv1.TransferStatus_TRANSFER_SUBMITTED:
|
||||
return model.TransferStatusSubmitted
|
||||
case chainv1.TransferStatus_TRANSFER_CONFIRMED:
|
||||
return model.TransferStatusConfirmed
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CREATED:
|
||||
return model.TransferStatusCreated
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_PROCESSING:
|
||||
return model.TransferStatusProcessing
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_WAITING:
|
||||
return model.TransferStatusWaiting
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_SUCCESS:
|
||||
return model.TransferStatusSuccess
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_FAILED:
|
||||
return model.TransferStatusFailed
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CANCELLED:
|
||||
return model.TransferStatusCancelled
|
||||
|
||||
default:
|
||||
return ""
|
||||
return model.TransferStatus("")
|
||||
}
|
||||
}
|
||||
|
||||
func TransferStatusToProto(status model.TransferStatus) chainv1.TransferStatus {
|
||||
switch status {
|
||||
case model.TransferStatusPending:
|
||||
return chainv1.TransferStatus_TRANSFER_PENDING
|
||||
case model.TransferStatusSigning:
|
||||
return chainv1.TransferStatus_TRANSFER_SIGNING
|
||||
case model.TransferStatusSubmitted:
|
||||
return chainv1.TransferStatus_TRANSFER_SUBMITTED
|
||||
case model.TransferStatusConfirmed:
|
||||
return chainv1.TransferStatus_TRANSFER_CONFIRMED
|
||||
|
||||
case model.TransferStatusCreated:
|
||||
return chainv1.TransferStatus_TRANSFER_CREATED
|
||||
|
||||
case model.TransferStatusProcessing:
|
||||
return chainv1.TransferStatus_TRANSFER_PROCESSING
|
||||
|
||||
case model.TransferStatusWaiting:
|
||||
return chainv1.TransferStatus_TRANSFER_WAITING
|
||||
|
||||
case model.TransferStatusSuccess:
|
||||
return chainv1.TransferStatus_TRANSFER_SUCCESS
|
||||
|
||||
case model.TransferStatusFailed:
|
||||
return chainv1.TransferStatus_TRANSFER_FAILED
|
||||
|
||||
case model.TransferStatusCancelled:
|
||||
return chainv1.TransferStatus_TRANSFER_CANCELLED
|
||||
|
||||
default:
|
||||
return chainv1.TransferStatus_TRANSFER_STATUS_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
func ChainTransferStatusToOperation(status chainv1.TransferStatus) connectorv1.OperationStatus {
|
||||
switch status {
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CREATED:
|
||||
return connectorv1.OperationStatus_OPERATION_CREATED
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_PROCESSING:
|
||||
return connectorv1.OperationStatus_OPERATION_PROCESSING
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_WAITING:
|
||||
return connectorv1.OperationStatus_OPERATION_WAITING
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_SUCCESS:
|
||||
return connectorv1.OperationStatus_OPERATION_SUCCESS
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_FAILED:
|
||||
return connectorv1.OperationStatus_OPERATION_FAILED
|
||||
|
||||
case chainv1.TransferStatus_TRANSFER_CANCELLED:
|
||||
return connectorv1.OperationStatus_OPERATION_CANCELLED
|
||||
|
||||
default:
|
||||
return connectorv1.OperationStatus_OPERATION_STATUS_UNSPECIFIED
|
||||
}
|
||||
}
|
||||
|
||||
// NativeCurrency returns the canonical native token symbol for a network.
|
||||
func NativeCurrency(network Network) string {
|
||||
currency := strings.ToUpper(strings.TrimSpace(network.NativeToken))
|
||||
@@ -146,3 +188,23 @@ type ServiceWallet struct {
|
||||
Address string
|
||||
PrivateKey string
|
||||
}
|
||||
|
||||
func ProtoToMoney(money *moneyv1.Money) *paymenttypes.Money {
|
||||
if money == nil {
|
||||
return &paymenttypes.Money{}
|
||||
}
|
||||
return &paymenttypes.Money{
|
||||
Amount: money.GetAmount(),
|
||||
Currency: money.GetCurrency(),
|
||||
}
|
||||
}
|
||||
|
||||
func MonenyToProto(money *paymenttypes.Money) *moneyv1.Money {
|
||||
if money == nil {
|
||||
return &moneyv1.Money{}
|
||||
}
|
||||
return &moneyv1.Money{
|
||||
Amount: money.Amount,
|
||||
Currency: money.Currency,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,26 +40,26 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusSigning, "", ""); 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.String())
|
||||
if err != nil {
|
||||
_, _ = s.storage.Transfers().UpdateStatus(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.storage.Transfers().UpdateStatus(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.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
|
||||
_, _ = s.updateTransferStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
|
||||
return err
|
||||
}
|
||||
if chainDriver.Name() == "tron" && sourceAddress == destinationAddress {
|
||||
@@ -68,7 +68,7 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
|
||||
zap.String("wallet_ref", sourceWalletRef),
|
||||
zap.String("network", network.Name.String()),
|
||||
)
|
||||
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusConfirmed, "", ""); 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
|
||||
@@ -76,11 +76,14 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
|
||||
|
||||
txHash, err := chainDriver.SubmitTransfer(ctx, driverDeps, network, transfer, sourceWallet, destinationAddress)
|
||||
if err != nil {
|
||||
_, _ = s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
|
||||
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 {
|
||||
s.logger.Warn("Failed to update transfer status to failed", zap.String("transfer_ref", transferRef), zap.Error(e))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusSubmitted, "", 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))
|
||||
}
|
||||
|
||||
@@ -94,15 +97,15 @@ func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWallet
|
||||
return err
|
||||
}
|
||||
|
||||
if receipt != nil && receipt.Status == types.ReceiptStatusSuccessful {
|
||||
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusConfirmed, "", txHash); err != nil {
|
||||
s.logger.Warn("Failed to update transfer status to confirmed", zap.String("transfer_ref", transferRef), zap.Error(err))
|
||||
}
|
||||
return nil
|
||||
failureReason := ""
|
||||
pStatus := model.TransferStatusSuccess
|
||||
if receipt != nil && receipt.Status != types.ReceiptStatusSuccessful {
|
||||
failureReason = "transaction reverted"
|
||||
pStatus = model.TransferStatusFailed
|
||||
}
|
||||
|
||||
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusFailed, "transaction reverted", txHash); err != nil {
|
||||
s.logger.Warn("Failed to update transfer status to failed", zap.String("transfer_ref", transferRef), zap.Error(err))
|
||||
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)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/tech/sendico/gateway/tron/storage/model"
|
||||
paymentgateway "github.com/tech/sendico/pkg/messaging/notifications/paymentgateway"
|
||||
pmodel "github.com/tech/sendico/pkg/model"
|
||||
"github.com/tech/sendico/pkg/mservice"
|
||||
"github.com/tech/sendico/pkg/payments/rail"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func isFinalStatus(t *model.Transfer) bool {
|
||||
switch t.Status {
|
||||
case model.TransferStatusFailed, model.TransferStatusSuccess, model.TransferStatusCancelled:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func toOpStatus(t *model.Transfer) rail.OperationResult {
|
||||
switch t.Status {
|
||||
case model.TransferStatusFailed:
|
||||
return rail.OperationResultFailed
|
||||
case model.TransferStatusSuccess:
|
||||
return rail.OperationResultSuccess
|
||||
case model.TransferStatusCancelled:
|
||||
return rail.OperationResultCancelled
|
||||
default:
|
||||
panic(fmt.Sprintf("toOpStatus: unexpected transfer status: %s", t.Status))
|
||||
}
|
||||
}
|
||||
|
||||
func toError(t *model.Transfer) string {
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
if t.Status == model.TransferStatusSuccess {
|
||||
return ""
|
||||
}
|
||||
return t.FailureReason
|
||||
}
|
||||
|
||||
func (s *Service) updateTransferStatus(ctx context.Context, transferRef string, status model.TransferStatus, failureReason, txHash string) (*model.Transfer, error) {
|
||||
transfer, 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))
|
||||
}
|
||||
if isFinalStatus(transfer) {
|
||||
s.emitTransferStatusEvent(transfer)
|
||||
}
|
||||
return transfer, err
|
||||
}
|
||||
|
||||
func (s *Service) emitTransferStatusEvent(transfer *model.Transfer) {
|
||||
if s == nil || s.producer == nil || transfer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
exec := pmodel.PaymentGatewayExecution{
|
||||
PaymentIntentID: transfer.IntentRef,
|
||||
IdempotencyKey: transfer.IdempotencyKey,
|
||||
ExecutedMoney: transfer.NetAmount,
|
||||
PaymentRef: transfer.PaymentRef,
|
||||
Status: toOpStatus(transfer),
|
||||
OperationRef: transfer.OperationRef,
|
||||
Error: toError(transfer),
|
||||
TransferRef: transfer.TransferRef,
|
||||
}
|
||||
env := paymentgateway.PaymentGatewayExecution(mservice.ChainGateway, &exec)
|
||||
if err := s.producer.SendMessage(env); err != nil {
|
||||
s.logger.Warn("Failed to publish transfer status event", zap.Error(err), zap.String("transfer_ref", transfer.TransferRef))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user