All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
102 lines
3.6 KiB
Go
102 lines
3.6 KiB
Go
package gateway
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/tech/sendico/gateway/chain/storage/model"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/tech/sendico/gateway/chain/internal/service/gateway/shared"
|
|
)
|
|
|
|
func (s *Service) launchTransferExecution(transferRef, sourceWalletRef string, network shared.Network) {
|
|
if s.executor == nil {
|
|
return
|
|
}
|
|
|
|
go func(ref, walletRef string, net shared.Network) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
|
|
defer cancel()
|
|
|
|
if err := s.executeTransfer(ctx, ref, walletRef, net); err != nil {
|
|
s.logger.Error("failed to execute transfer", zap.String("transfer_ref", ref), zap.Error(err))
|
|
}
|
|
}(transferRef, sourceWalletRef, network)
|
|
}
|
|
|
|
func (s *Service) executeTransfer(ctx context.Context, transferRef, sourceWalletRef string, network shared.Network) error {
|
|
transfer, err := s.storage.Transfers().Get(ctx, transferRef)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sourceWallet, err := s.storage.Wallets().Get(ctx, sourceWalletRef)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusSigning, "", ""); err != nil {
|
|
s.logger.Warn("failed to update transfer status to signing", zap.String("transfer_ref", transferRef), zap.Error(err))
|
|
}
|
|
|
|
destinationAddress, err := s.destinationAddress(ctx, transfer.Destination)
|
|
if err != nil {
|
|
_, _ = s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
|
|
return err
|
|
}
|
|
|
|
txHash, err := s.executor.SubmitTransfer(ctx, transfer, sourceWallet, destinationAddress, network)
|
|
if err != nil {
|
|
_, _ = s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusFailed, err.Error(), "")
|
|
return err
|
|
}
|
|
|
|
if _, err := s.storage.Transfers().UpdateStatus(ctx, transferRef, model.TransferStatusSubmitted, "", txHash); err != nil {
|
|
s.logger.Warn("failed to update transfer status to submitted", zap.String("transfer_ref", transferRef), zap.Error(err))
|
|
}
|
|
|
|
receiptCtx, cancel := context.WithTimeout(ctx, 10*time.Minute)
|
|
defer cancel()
|
|
receipt, err := s.executor.AwaitConfirmation(receiptCtx, network, txHash)
|
|
if err != nil {
|
|
if !errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, context.Canceled) {
|
|
s.logger.Warn("failed to await transfer confirmation", zap.String("transfer_ref", transferRef), zap.Error(err))
|
|
}
|
|
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
|
|
}
|
|
|
|
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))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Service) destinationAddress(ctx context.Context, dest model.TransferDestination) (string, error) {
|
|
if ref := strings.TrimSpace(dest.ManagedWalletRef); ref != "" {
|
|
wallet, err := s.storage.Wallets().Get(ctx, ref)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if strings.TrimSpace(wallet.DepositAddress) == "" {
|
|
return "", merrors.Internal("destination wallet missing deposit address")
|
|
}
|
|
return wallet.DepositAddress, nil
|
|
}
|
|
if addr := strings.TrimSpace(dest.ExternalAddress); addr != "" {
|
|
return strings.ToLower(addr), nil
|
|
}
|
|
return "", merrors.InvalidArgument("transfer destination address not resolved")
|
|
}
|