transaction

package
v1.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package transaction is the business-logic layer for the platform's transaction ledger — the durable record of every money movement, whether it settled on the Stellar network, through an external provider, or internally. Service wraps the transaction repository and adds validation, uniqueness, and status-transition rules.

Build a Service with NewService. It records transactions (Create, BatchCreate), looks them up by ID, Stellar hash, external ID, loan, user, or status, and applies updates. List operations are paginated through services.Pagination, which the service clamps (default page size 10, capped at 100). Requests and responses are the DTOs in dto.go; failures are the sentinel errors in errors.go, which handlers map onto HTTP status codes.

What a record holds

Each transaction carries a type and a category — on-chain, off-chain, or internal — an amount and asset, and optional links to a user, account, or loan. Settlement details hang off the same row: the Stellar hash, ledger, and status for on-chain work, or the external ID, provider, and status for an off-ramp provider. New transactions default to the on-chain category and open in the pending status.

Status lifecycle

A transaction moves from pending to submitted, then to success or failed. A failed transaction may return to pending for a retry; pending may also be cancelled. success and cancelled are terminal — Update refuses to modify a transaction in either state, and every other status change is checked against the transition table, rejecting an illegal move with ErrInvalidStatusTransition.

Uniqueness

A Stellar hash, when supplied, must be unique: Create rejects a duplicate with ErrStellarHashAlreadyExists, so one on-chain payment cannot be recorded twice. A genuine retry carries a different hash and is therefore still recordable.

External IDs are deliberately not unique. One anchor transaction settles as several legs — a MoneyGram cash pickup writes an anchor_transfer, an off_ramp and possibly a refund — and all of them carry the provider's request ID, which is what makes the reference reverse-lookupable when a provider quotes it. Uniqueness for the off-chain legs is enforced instead by a partial unique index on (loan_id, tx_type), stating the real invariant: one fiat payout per loan.

Index

Constants

This section is empty.

Variables

View Source
var (
	// Resource not found errors
	ErrTransactionNotFound = errors.New("transaction not found")

	// Conflict errors
	ErrStellarHashAlreadyExists = errors.New("stellar transaction hash already registered")

	// Business logic errors
	ErrInvalidStatusTransition = errors.New("invalid status transition")
	ErrCannotModifyTransaction = errors.New("cannot modify completed transaction")

	// Validation errors
	ErrInvalidInput  = errors.New("invalid input")
	ErrInvalidTxType = errors.New("invalid transaction type")
	ErrInvalidAmount = errors.New("invalid amount")
	ErrInvalidStatus = errors.New("invalid transaction status")
)

Transaction service specific errors

Functions

This section is empty.

Types

type CreateTransactionRequest

type CreateTransactionRequest struct {
	UserID           *string `json:"user_id,omitempty"`
	AccountID        *string `json:"account_id,omitempty"`
	LoanID           *string `json:"loan_id,omitempty"`
	TxType           string  `json:"tx_type" validate:"required"`
	Amount           int64   `json:"amount" validate:"required,gt=0"`
	Asset            string  `json:"asset" validate:"required"`
	StellarTxHash    *string `json:"stellar_tx_hash,omitempty"`
	StellarLedger    *int64  `json:"stellar_ledger,omitempty"`
	ContractID       *string `json:"contract_id,omitempty"`
	ContractFunction *string `json:"contract_function,omitempty"`
	ExternalID       *string `json:"external_id,omitempty"`
	ExternalProvider *string `json:"external_provider,omitempty"`
	Description      *string `json:"description,omitempty"`
	Metadata         *string `json:"metadata,omitempty"`
}

CreateTransactionRequest represents the request to create a new transaction

type Service

type Service interface {
	// Transaction management
	Create(ctx context.Context, req CreateTransactionRequest) (*TransactionResponse, error)
	BatchCreate(ctx context.Context, reqs []CreateTransactionRequest) ([]*TransactionResponse, error)
	GetByID(ctx context.Context, id string) (*TransactionResponse, error)
	GetByStellarHash(ctx context.Context, txHash string) (*TransactionResponse, error)
	ListByExternalID(ctx context.Context, externalID string) ([]*TransactionResponse, error)
	GetByLoanIDAndType(ctx context.Context, loanID, txType string) (*TransactionResponse, error)
	GetByLoanID(ctx context.Context, loanID string, pagination services.Pagination) (*services.PaginatedResponse[TransactionResponse], error)
	GetByUserID(ctx context.Context, userID string, pagination services.Pagination) (*services.PaginatedResponse[TransactionResponse], error)
	GetByStatus(ctx context.Context, status string, pagination services.Pagination) (*services.PaginatedResponse[TransactionResponse], error)
	Update(ctx context.Context, id string, req UpdateTransactionRequest) (*TransactionResponse, error)
}

Service defines the interface for transaction business logic operations

func NewService

func NewService(repo repository.TransactionRepository) Service

NewService creates a new transaction service instance

type TransactionFilters

type TransactionFilters struct {
	UserID string `json:"user_id,omitempty"`
	LoanID string `json:"loan_id,omitempty"`
	Status string `json:"status,omitempty"`
	TxType string `json:"tx_type,omitempty"`
}

TransactionFilters represents filters for listing transactions

type TransactionResponse

type TransactionResponse struct {
	ID        string  `json:"id"`
	UserID    *string `json:"user_id,omitempty"`
	AccountID *string `json:"account_id,omitempty"`
	LoanID    *string `json:"loan_id,omitempty"`
	TxType    string  `json:"tx_type"`
	// TxCategory is derived from TxType, not stored. See models.TxCategoryFor.
	TxCategory       string    `json:"tx_category"`
	Amount           int64     `json:"amount"`
	Asset            string    `json:"asset"`
	StellarTxHash    *string   `json:"stellar_tx_hash,omitempty"`
	StellarLedger    *int64    `json:"stellar_ledger,omitempty"`
	ContractID       *string   `json:"contract_id,omitempty"`
	ContractFunction *string   `json:"contract_function,omitempty"`
	ExternalID       *string   `json:"external_id,omitempty"`
	ExternalProvider *string   `json:"external_provider,omitempty"`
	ExternalStatus   *string   `json:"external_status,omitempty"`
	Description      *string   `json:"description,omitempty"`
	Metadata         *string   `json:"metadata,omitempty"`
	Status           string    `json:"status"`
	CreatedAt        time.Time `json:"created_at"`
	UpdatedAt        time.Time `json:"updated_at"`
}

TransactionResponse represents the response containing transaction information

type UpdateTransactionRequest

type UpdateTransactionRequest struct {
	StellarTxHash    *string `json:"stellar_tx_hash,omitempty"`
	StellarLedger    *int64  `json:"stellar_ledger,omitempty"`
	ExternalID       *string `json:"external_id,omitempty"`
	ExternalProvider *string `json:"external_provider,omitempty"`
	ExternalStatus   *string `json:"external_status,omitempty"`
	Status           *string `json:"status,omitempty"`
	Description      *string `json:"description,omitempty"`
	Metadata         *string `json:"metadata,omitempty"`
}

UpdateTransactionRequest represents the request to update a transaction

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL