Help us shape the future of Go! Take the 2026 Go Developer Survey

storage

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package storage defines the kit's persistence contract: shared domain types mirroring specs/008-exchange-integration-kit/data-model.md and the repository interfaces implemented by storage/sqlite and storage/postgres.

Every uniqueness rule in the data model is a real database constraint (R7); the repository layer additionally enforces the legal state-machine transitions (see transitions.go) — implementations MUST call the Validate*Transition helpers before any status write.

All token amounts are integer base units (usovr) carried as math.Int; floats never appear in a money path (FR-017).

Index

Constants

View Source
const BaseDenom = "usovr"

BaseDenom is the only denom the kit records; non-usovr coins are filtered pre-insert and never create records.

View Source
const SignModeDirect = "SIGN_MODE_DIRECT"

SignModeDirect is the only sign mode the kit produces (R4).

Variables

View Source
var (
	// ErrNotFound reports that no row matches the lookup.
	ErrNotFound = errors.New("storage: not found")

	// ErrDuplicate reports a unique-constraint hit (deposit unique key,
	// withdrawal/sweep idempotency key, sequence slot, work_ref, outbox
	// dedup key, ledger identity).
	ErrDuplicate = errors.New("storage: duplicate")

	// ErrActiveSweepExists reports the sweep partial-unique hit: a
	// non-terminal SweepJob already exists for (chain_id, source_address).
	ErrActiveSweepExists = errors.New("storage: active sweep exists")

	// ErrIllegalTransition reports a state change outside the entity's legal
	// state machine (data model §3b/§5/§6/§7).
	ErrIllegalTransition = errors.New("storage: illegal state transition")

	// ErrStatusConflict reports that the stored status did not match the
	// caller's expected `from` status (lost optimistic race), or a resolve
	// of an already-resolved item.
	ErrStatusConflict = errors.New("storage: status conflict")

	// ErrInvalidRecord reports a record that fails pre-insert validation
	// (unknown enum value, non-usovr denom, non-positive amount).
	ErrInvalidRecord = errors.New("storage: invalid record")
)

AllChainReviewTriggers lists every valid ChainReviewTrigger.

AllClassifications lists every valid Classification.

AllControlFlows lists every valid ControlFlow.

AllDepositStatuses lists every valid DepositStatus.

View Source
var AllLedgerDirections = []LedgerDirection{DirectionIn, DirectionOut}

AllLedgerDirections lists every valid LedgerDirection.

AllLedgerEntryKinds lists every valid LedgerEntryKind.

AllReconciliationKinds lists every valid ReconciliationKind.

AllReviewItemKinds lists every valid ReviewItemKind.

AllSequenceReservationStatuses lists every valid SequenceReservationStatus.

AllSweepStatuses lists every valid SweepStatus.

AllSweepStrategies lists every valid SweepStrategy.

AllWatchedAddressKinds lists every valid WatchedAddressKind.

AllWithdrawalStatuses lists every valid WithdrawalStatus.

View Source
var AllWorkKinds = []WorkKind{WorkWithdrawal, WorkSweep}

AllWorkKinds lists every valid WorkKind.

TerminalSweepStatuses is the terminal set backing the partial-unique constraint: at most one NON-terminal sweep per (chain_id, source_address).

Functions

func ValidateDepositTransition

func ValidateDepositTransition(from, to DepositStatus) error

ValidateDepositTransition rejects any deposit status change outside §3b.

func ValidateSequenceTransition

func ValidateSequenceTransition(from, to SequenceReservationStatus) error

ValidateSequenceTransition rejects any reservation status change outside §6.

func ValidateSweepTransition

func ValidateSweepTransition(from, to SweepStatus) error

ValidateSweepTransition rejects any sweep status change outside §7.

func ValidateWithdrawalTransition

func ValidateWithdrawalTransition(from, to WithdrawalStatus) error

ValidateWithdrawalTransition rejects any withdrawal status change outside §5.

Types

type ChainReviewCondition

type ChainReviewCondition struct {
	ConditionID string
	ChainID     string
	Trigger     ChainReviewTrigger
	NodeA       NodeObservation
	NodeB       NodeObservation
	OpenedAt    time.Time
	ResolvedAt  *time.Time
	Resolution  string
}

ChainReviewCondition is an FR-044 condition (data model §11). While one is open for a chain, the FR-023 crediting gate is closed.

type ChainReviewRepo

type ChainReviewRepo interface {
	Open(ctx context.Context, c ChainReviewCondition) (ChainReviewCondition, error)
	Get(ctx context.Context, conditionID string) (ChainReviewCondition, error)
	// HasOpen backs the FR-023 crediting gate.
	HasOpen(ctx context.Context, chainID string) (bool, error)
	ListOpen(ctx context.Context, chainID string) ([]ChainReviewCondition, error)
	Resolve(ctx context.Context, conditionID, resolution string, at time.Time) error
}

ChainReviewRepo persists FR-044 ChainReviewConditions.

type ChainReviewTrigger

type ChainReviewTrigger string

ChainReviewTrigger is the FR-044 trigger taxonomy (data model §11).

const (
	TriggerBlockHashMismatch   ChainReviewTrigger = "BLOCK_HASH_MISMATCH"
	TriggerQueryResultMismatch ChainReviewTrigger = "QUERY_RESULT_MISMATCH"
	TriggerHeightDivergence    ChainReviewTrigger = "HEIGHT_DIVERGENCE"
	TriggerChainHalt           ChainReviewTrigger = "CHAIN_HALT"
	TriggerWrongChainID        ChainReviewTrigger = "WRONG_CHAIN_ID"
	TriggerUpgradeWindow       ChainReviewTrigger = "UPGRADE_WINDOW"
)

func (ChainReviewTrigger) Valid

func (t ChainReviewTrigger) Valid() bool

Valid reports whether t is a known trigger.

type CheckpointRepo

type CheckpointRepo interface {
	Get(ctx context.Context, chainID string) (ScannerCheckpoint, error)
	Set(ctx context.Context, cp ScannerCheckpoint) error
}

CheckpointRepo persists ScannerCheckpoints. Set MUST be called inside the same Store.WithTx transaction as the block's record writes (FR-026).

type Classification

type Classification string

Classification is the ledger-entry classification (data model §3).

const (
	ClassExternalDeposit    Classification = "EXTERNAL_DEPOSIT"
	ClassInternalTransfer   Classification = "INTERNAL_TRANSFER"
	ClassFeeFunding         Classification = "FEE_FUNDING"
	ClassSweep              Classification = "SWEEP"
	ClassWithdrawal         Classification = "WITHDRAWAL"
	ClassFeeDeduction       Classification = "FEE_DEDUCTION"
	ClassUnattributedReview Classification = "UNATTRIBUTED_REVIEW"
)

func (Classification) Valid

func (c Classification) Valid() bool

Valid reports whether c is a known classification.

type ControlFlow

type ControlFlow string

ControlFlow names one independently pausable flow (FR-051).

const (
	FlowCredit    ControlFlow = "credit"
	FlowSigning   ControlFlow = "signing"
	FlowBroadcast ControlFlow = "broadcast"
	FlowSweep     ControlFlow = "sweep"
)

func (ControlFlow) Valid

func (f ControlFlow) Valid() bool

Valid reports whether f is a known flow.

type ControlsAuditEntry

type ControlsAuditEntry struct {
	ID       int64
	ChainID  string
	Field    string
	OldValue string
	NewValue string
	Actor    string
	Reason   string
	At       time.Time
}

ControlsAuditEntry records one control flip (who/when/why — FR-051).

type ControlsRepo

type ControlsRepo interface {
	// Get returns the controls row, or the all-false zero value when none
	// exists yet (controls default to running).
	Get(ctx context.Context, chainID string) (OperationalControls, error)
	// Apply performs a partial update and writes one audit entry per changed
	// field, atomically.
	Apply(ctx context.Context, chainID string, u ControlsUpdate, actor, reason string) (OperationalControls, error)
	ListAudit(ctx context.Context, chainID string, limit int) ([]ControlsAuditEntry, error)
}

ControlsRepo persists OperationalControls; every flip is audit-logged.

type ControlsUpdate

type ControlsUpdate struct {
	CreditPaused          *bool
	SigningPaused         *bool
	BroadcastPaused       *bool
	SweepPaused           *bool
	ScanWithoutCredit     *bool
	ResumeFromHeight      *uint64
	ClearResumeFromHeight bool
}

ControlsUpdate is a partial update of OperationalControls; nil fields are left unchanged. ClearResumeFromHeight wins over ResumeFromHeight.

type DepositRecord

type DepositRecord struct {
	ID               int64
	ChainID          string
	TxHash           string
	MessageIndex     uint32
	CoinIndex        uint32
	BlockHeight      uint64
	BlockTimestamp   time.Time
	SenderAddress    *string // nil when the input set is ambiguous (MsgMultiSend)
	RecipientAddress string
	Denom            string
	AmountBaseUnits  sdkmath.Int
	Memo             string
	TxCode           uint32
	TxLog            string
	Status           DepositStatus
	// PriorStatus is set while Status == SUSPENDED; resume returns to it.
	PriorStatus *DepositStatus
	CreditedAt  *time.Time
	SweepTxHash *string
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

DepositRecord is the customer-credit state machine record (data model §3b), derived exclusively from EXTERNAL_DEPOSIT ledger entries. UNIQUE(ChainID, TxHash, MessageIndex, CoinIndex, RecipientAddress) (FR-024).

type DepositRepo

type DepositRepo interface {
	// Insert creates a deposit; a unique-key hit returns ErrDuplicate (the
	// caller records the DUPLICATE observation for metrics — never re-credits).
	Insert(ctx context.Context, d DepositRecord) (DepositRecord, error)
	Get(ctx context.Context, chainID, txHash string, messageIndex, coinIndex uint32, recipientAddress string) (DepositRecord, error)
	GetByID(ctx context.Context, id int64) (DepositRecord, error)
	ListByStatus(ctx context.Context, chainID string, status DepositStatus, limit int) ([]DepositRecord, error)

	// UpdateStatus moves a deposit from → to, applying set. It returns
	// ErrStatusConflict when the stored status differs from `from`,
	// ErrIllegalTransition when the (from, to) pair is not legal, including
	// resuming SUSPENDED to anything but the recorded prior status.
	UpdateStatus(ctx context.Context, id int64, from, to DepositStatus, set DepositUpdate) error
}

DepositRepo persists DepositRecords and enforces the §3b state machine.

type DepositStatus

type DepositStatus string

DepositStatus is the customer-credit state machine status (data model §3b).

const (
	DepositDiscovered            DepositStatus = "DISCOVERED"
	DepositValidated             DepositStatus = "VALIDATED"
	DepositAwaitingConfirmations DepositStatus = "AWAITING_CONFIRMATIONS"
	DepositCreditable            DepositStatus = "CREDITABLE"
	DepositCredited              DepositStatus = "CREDITED"
	DepositSweepPending          DepositStatus = "SWEEP_PENDING"
	DepositSwept                 DepositStatus = "SWEPT"
	DepositRejected              DepositStatus = "REJECTED"
	DepositReviewRequired        DepositStatus = "REVIEW_REQUIRED"
	DepositOrphaned              DepositStatus = "ORPHANED"
	DepositDuplicate             DepositStatus = "DUPLICATE"
	DepositBelowMinimum          DepositStatus = "BELOW_MINIMUM"
	DepositSuspended             DepositStatus = "SUSPENDED"
)

func (DepositStatus) Valid

func (s DepositStatus) Valid() bool

Valid reports whether s is a known status.

type DepositUpdate

type DepositUpdate struct {
	CreditedAt  *time.Time
	SweepTxHash *string
	TxLog       *string
}

DepositUpdate carries the writable fields of a deposit status change.

type FeeFundingSpend

type FeeFundingSpend struct {
	ID               int64
	ChainID          string
	TxHash           string
	FeeWalletAddress string
	AmountBaseUnits  sdkmath.Int
	BlockHeight      uint64
	CreatedAt        time.Time
}

FeeFundingSpend is a durable, confirm-time record of one FEE_FUND fee-wallet spend (a confirmed funding leg: fee wallet → deposit address). It is written by the sweeper atomically with the funding leg's confirmation, NOT by the deposit scanner, so the fee-wallet spend cap reads authoritative spend the instant a leg confirms rather than waiting for the scanner to catch up. UNIQUE(ChainID, TxHash): one funding tx is one spend.

type FeeOutflow

type FeeOutflow struct {
	ID           int64
	ChainID      string
	TxHash       string
	PayerAddress string
	FeeBaseUnits sdkmath.Int
	TxCode       uint32
	BlockHeight  uint64
	CreatedAt    time.Time
}

FeeOutflow is one FEE_DEDUCTION event-truth record (data model §8a): recorded iff the fee-deduction ante event was emitted and the resolved payer is watched. UNIQUE(ChainID, TxHash).

type LedgerDirection

type LedgerDirection string

LedgerDirection is the flow direction relative to the watched address.

const (
	DirectionIn  LedgerDirection = "IN"
	DirectionOut LedgerDirection = "OUT"
)

func (LedgerDirection) Valid

func (d LedgerDirection) Valid() bool

Valid reports whether d is a known direction.

type LedgerEntry

type LedgerEntry struct {
	ID              int64
	ChainID         string
	Kind            LedgerEntryKind
	TxHash          string
	MessageIndex    uint32
	OpIndex         uint32
	BlockHeight     uint64
	EventIndex      uint32
	Direction       LedgerDirection
	Address         string
	CounterpartySet []string
	AmountBaseUnits sdkmath.Int
	Denom           string
	TxCode          uint32
	Classification  Classification
	CreatedAt       time.Time
}

LedgerEntry is one immutable, append-only ChainTransferLedger row (data model §3). Rows are never mutated; corrections append superseding entries.

Identity: kind TX ⇒ (ChainID, TxHash, MessageIndex, OpIndex) UNIQUE; kind BLOCK_EVENT ⇒ (ChainID, BlockHeight, EventIndex) UNIQUE, with no tx attribution (TxHash empty, MessageIndex/OpIndex unused).

type LedgerEntryKind

type LedgerEntryKind string

LedgerEntryKind distinguishes tx-attributed ledger rows from block-scoped event rows (finalize_block_events carry no tx hash — data model §3).

const (
	LedgerKindTx         LedgerEntryKind = "TX"
	LedgerKindBlockEvent LedgerEntryKind = "BLOCK_EVENT"
)

func (LedgerEntryKind) Valid

func (k LedgerEntryKind) Valid() bool

Valid reports whether k is a known kind.

type LedgerQuery

type LedgerQuery struct {
	ChainID    string
	Address    string
	FromHeight uint64
	ToHeight   uint64
	AfterID    int64
	Limit      int
}

LedgerQuery selects ledger entries for an address over a height range. Zero ToHeight means unbounded; AfterID is the pagination cursor.

type LedgerRepo

type LedgerRepo interface {
	// Append inserts one entry; a unique-key hit returns ErrDuplicate.
	Append(ctx context.Context, e LedgerEntry) (LedgerEntry, error)
	GetTxEntry(ctx context.Context, chainID, txHash string, messageIndex, opIndex uint32) (LedgerEntry, error)
	GetBlockEventEntry(ctx context.Context, chainID string, blockHeight uint64, eventIndex uint32) (LedgerEntry, error)
	List(ctx context.Context, q LedgerQuery) ([]LedgerEntry, error)

	// AppendFeeOutflow inserts one FEE_DEDUCTION record; a (chain_id, tx_hash)
	// hit returns ErrDuplicate.
	AppendFeeOutflow(ctx context.Context, f FeeOutflow) (FeeOutflow, error)
	ListFeeOutflows(ctx context.Context, chainID, payerAddress string, fromHeight, toHeight uint64) ([]FeeOutflow, error)

	// AppendFeeFundingSpend records one confirmed FEE_FUND fee-wallet spend; a
	// (chain_id, tx_hash) hit returns ErrDuplicate (a re-confirm is a no-op).
	AppendFeeFundingSpend(ctx context.Context, s FeeFundingSpend) (FeeFundingSpend, error)
	// SumFeeFundingSpend totals confirmed fee-wallet FEE_FUND spend over the
	// inclusive [fromHeight, toHeight] block window (toHeight 0 = open-ended).
	SumFeeFundingSpend(ctx context.Context, chainID, feeWalletAddress string, fromHeight, toHeight uint64) (sdkmath.Int, error)
}

LedgerRepo persists the ChainTransferLedger and its FEE_DEDUCTION sibling table. Append-only: no update or delete methods exist by design.

type NodeObservation

type NodeObservation struct {
	Endpoint string
	Height   uint64
	Value    string // block hash or query-result digest, trigger-dependent
}

NodeObservation is one node's view inside a ChainReviewCondition.

type OperationalControls

type OperationalControls struct {
	ChainID           string
	CreditPaused      bool
	SigningPaused     bool
	BroadcastPaused   bool
	SweepPaused       bool
	ScanWithoutCredit bool
	ResumeFromHeight  *uint64
	UpdatedAt         time.Time
}

OperationalControls is the singleton-per-chain pause switchboard (FR-051, data model §10).

type OutboxEvent

type OutboxEvent struct {
	ID           int64
	ChainID      string
	Topic        string
	DedupKey     string
	Payload      []byte
	CreatedAt    time.Time
	DispatchedAt *time.Time
}

OutboxEvent is one transactional-outbox row: written in the same DB transaction as the state flip it announces (e.g. deposit CREDITED — data model §3b invariant), dispatched at-least-once afterwards. DedupKey, when non-empty, is UNIQUE and makes the emission exactly-once per key.

type OutboxRepo

type OutboxRepo interface {
	// Enqueue inserts an event; a DedupKey hit returns ErrDuplicate.
	Enqueue(ctx context.Context, ev OutboxEvent) (OutboxEvent, error)
	ListPending(ctx context.Context, limit int) ([]OutboxEvent, error)
	MarkDispatched(ctx context.Context, id int64, at time.Time) error
}

OutboxRepo persists the transactional outbox.

type ReconRepo

type ReconRepo interface {
	SaveReport(ctx context.Context, r ReconciliationReport) error
	GetReport(ctx context.Context, reportID string) (ReconciliationReport, error)
	ListReports(ctx context.Context, chainID string, kind ReconciliationKind, limit int) ([]ReconciliationReport, error)
}

ReconRepo persists ReconciliationReports.

type ReconciliationEntry

type ReconciliationEntry struct {
	Address                 string
	ExpectedBaseUnits       sdkmath.Int
	ObservedBaseUnits       sdkmath.Int
	Difference              sdkmath.Int
	EarliestSuspectedHeight uint64
	RelatedTxHashes         []string
	RecommendedRescanHeight uint64
}

ReconciliationEntry is one address line of a report (data model §8): expected is computed from the ledger (Σ inflows − Σ outflows, including FEE_DEDUCTION), never from credit status.

type ReconciliationKind

type ReconciliationKind string

ReconciliationKind is the report cadence kind (data model §8).

const (
	ReconTxNearRealTime ReconciliationKind = "TX_NEAR_REAL_TIME"
	ReconWalletHourly   ReconciliationKind = "WALLET_HOURLY"
	ReconAddressDaily   ReconciliationKind = "ADDRESS_DAILY"
	ReconManual         ReconciliationKind = "MANUAL"
)

func (ReconciliationKind) Valid

func (k ReconciliationKind) Valid() bool

Valid reports whether k is a known kind.

type ReconciliationReport

type ReconciliationReport struct {
	ReportID         string
	ChainID          string
	Kind             ReconciliationKind
	PeriodStart      time.Time
	PeriodEnd        time.Time
	GeneratedAt      time.Time
	Entries          []ReconciliationEntry
	DiscrepancyCount int
}

ReconciliationReport is a persisted FR-046 report.

type ReviewItem

type ReviewItem struct {
	ID         int64
	ChainID    string
	Kind       ReviewItemKind
	RefID      string // deposit ID, withdrawal ID, or ledger-entry ID
	Reason     string
	OpenedAt   time.Time
	ResolvedAt *time.Time
	Resolution string
}

ReviewItem is one operator review-queue entry (FR-030/FR-044 surfaces; admin API /v1/review-queue).

type ReviewItemKind

type ReviewItemKind string

ReviewItemKind identifies which entity a review-queue item references.

const (
	ReviewKindDeposit     ReviewItemKind = "DEPOSIT"
	ReviewKindWithdrawal  ReviewItemKind = "WITHDRAWAL"
	ReviewKindLedgerEntry ReviewItemKind = "LEDGER_ENTRY"
)

func (ReviewItemKind) Valid

func (k ReviewItemKind) Valid() bool

Valid reports whether k is a known kind.

type ReviewRepo

type ReviewRepo interface {
	Open(ctx context.Context, item ReviewItem) (ReviewItem, error)
	Get(ctx context.Context, id int64) (ReviewItem, error)
	ListOpen(ctx context.Context, chainID string, limit int) ([]ReviewItem, error)
	// Resolve stamps ResolvedAt/Resolution; resolving an already-resolved
	// item returns ErrStatusConflict.
	Resolve(ctx context.Context, id int64, resolution string, at time.Time) error
}

ReviewRepo persists the operator review queue.

type ScannerCheckpoint

type ScannerCheckpoint struct {
	ChainID                  string
	LastFullyProcessedHeight uint64
	LastObservedBlockHash    string
	UpdatedAt                time.Time
}

ScannerCheckpoint is the per-chain scan cursor (data model §4). Advancing it MUST happen in the same transaction as the block's deposit/ledger writes (FR-026) — use Store.WithTx.

type SequenceRepo

type SequenceRepo interface {
	// Reserve inserts a reservation in status RESERVED. A (chain, source,
	// sequence) hit on a live row returns ErrDuplicate; a hit on a RELEASED
	// row reclaims it (new WorkRef, back to RESERVED). A WorkRef hit returns
	// ErrDuplicate.
	Reserve(ctx context.Context, r SequenceReservation) (SequenceReservation, error)
	GetByWorkRef(ctx context.Context, ref WorkRef) (SequenceReservation, error)
	// ListUnconsumed returns every reservation not in a terminal status for
	// startup/mismatch reconciliation (§6 reconciliation rule).
	ListUnconsumed(ctx context.Context, chainID, sourceAddress string) ([]SequenceReservation, error)

	// UpdateStatus moves a reservation from → to; semantics as
	// DepositRepo.UpdateStatus. Note RELEASED is only reachable from
	// RESERVED or RECONCILIATION_REQUIRED — never from SIGNED/BROADCAST
	// (signed bytes may still redeem the sequence).
	UpdateStatus(ctx context.Context, id int64, from, to SequenceReservationStatus) error
}

SequenceRepo persists SequenceReservations. Implementations serialize reservation for one (chain_id, source_address) — Postgres via SELECT … FOR UPDATE on the chain_account_locks row (created on demand), SQLite via the single-writer connection + BEGIN IMMEDIATE. The UNIQUE constraints remain the last-line guarantee in both.

type SequenceReservation

type SequenceReservation struct {
	ID            int64
	ChainID       string
	SourceAddress string
	AccountNumber uint64
	Sequence      uint64
	WorkRef       WorkRef
	Status        SequenceReservationStatus
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

SequenceReservation binds one (chain, account, sequence) slot to one work item (data model §6). UNIQUE(ChainID, SourceAddress, Sequence) is the last-line double-spend guarantee; UNIQUE(WorkRef) gives one reservation per work item across kinds.

type SequenceReservationStatus

type SequenceReservationStatus string

SequenceReservationStatus is the reservation state machine status (data model §6).

const (
	SequenceReserved               SequenceReservationStatus = "RESERVED"
	SequenceSigned                 SequenceReservationStatus = "SIGNED"
	SequenceBroadcast              SequenceReservationStatus = "BROADCAST"
	SequenceConsumed               SequenceReservationStatus = "CONSUMED"
	SequenceReleased               SequenceReservationStatus = "RELEASED"
	SequenceReconciliationRequired SequenceReservationStatus = "RECONCILIATION_REQUIRED"
)

func (SequenceReservationStatus) Valid

func (s SequenceReservationStatus) Valid() bool

Valid reports whether s is a known status.

type Store

type Store interface {
	Tx

	Ledger() LedgerRepo
	Deposits() DepositRepo
	Checkpoints() CheckpointRepo
	Withdrawals() WithdrawalRepo
	Sequences() SequenceRepo
	Sweeps() SweepRepo
	Watch() WatchRepo
	Controls() ControlsRepo
	Review() ReviewRepo
	ChainReview() ChainReviewRepo
	Recon() ReconRepo
	Outbox() OutboxRepo

	Close() error
}

Store aggregates the repositories over one backend (SQLite or Postgres).

type SweepJob

type SweepJob struct {
	SweepID             string
	IdempotencyKey      string
	ChainID             string
	SourceAddress       string
	HotWalletAddress    string
	Strategy            SweepStrategy
	AmountBaseUnits     sdkmath.Int
	FeeReserveBaseUnits sdkmath.Int
	DepositIDs          []int64
	SignedTxBytes       []byte
	TxHash              *string
	TxCode              *uint32
	Status              SweepStatus
	CreatedAt           time.Time
	UpdatedAt           time.Time
}

SweepJob is the sweep state machine record (data model §7). At most one non-terminal job per (ChainID, SourceAddress) — DB partial-unique; IdempotencyKey UNIQUE is the subordinate request-dedup layer (FR-039).

type SweepRepo

type SweepRepo interface {
	// Create inserts a sweep in status PENDING. An existing non-terminal job
	// for (chain_id, source_address) returns ErrActiveSweepExists; an
	// idempotency-key hit returns ErrDuplicate.
	Create(ctx context.Context, j SweepJob) (SweepJob, error)
	Get(ctx context.Context, sweepID string) (SweepJob, error)
	GetByIdempotencyKey(ctx context.Context, idempotencyKey string) (SweepJob, error)
	// GetActive returns the single non-terminal job for the account, or
	// ErrNotFound.
	GetActive(ctx context.Context, chainID, sourceAddress string) (SweepJob, error)
	ListByStatus(ctx context.Context, chainID string, status SweepStatus, limit int) ([]SweepJob, error)

	// UpdateStatus moves a sweep from → to, applying set; semantics as
	// DepositRepo.UpdateStatus.
	UpdateStatus(ctx context.Context, sweepID string, from, to SweepStatus, set SweepUpdate) error
}

SweepRepo persists SweepJobs and enforces the §7 state machine.

type SweepStatus

type SweepStatus string

SweepStatus is the sweep-job state machine status (data model §7).

const (
	SweepPending   SweepStatus = "PENDING"
	SweepBuilt     SweepStatus = "BUILT"
	SweepSigned    SweepStatus = "SIGNED"
	SweepBroadcast SweepStatus = "BROADCAST"
	SweepConfirmed SweepStatus = "CONFIRMED"
	SweepDeferred  SweepStatus = "DEFERRED"
	SweepFailed    SweepStatus = "FAILED"
	SweepCancelled SweepStatus = "CANCELLED"
)

func (SweepStatus) Terminal

func (s SweepStatus) Terminal() bool

Terminal reports whether s is outside the partial-unique scope.

func (SweepStatus) Valid

func (s SweepStatus) Valid() bool

Valid reports whether s is a known status.

type SweepStrategy

type SweepStrategy string

SweepStrategy selects the fee-handling strategy for sweeps (FR-038).

const (
	StrategyFeeReserve      SweepStrategy = "FEE_RESERVE"
	StrategyFeeFund         SweepStrategy = "FEE_FUND"
	StrategyThresholdOnly   SweepStrategy = "THRESHOLD_ONLY"
	StrategyCustodyAbstract SweepStrategy = "CUSTODY_ABSTRACTED"
)

func (SweepStrategy) Valid

func (s SweepStrategy) Valid() bool

Valid reports whether s is a known strategy.

type SweepUpdate

type SweepUpdate struct {
	SignedTxBytes []byte
	TxHash        *string
	TxCode        *uint32
	DepositIDs    []int64 // non-nil replaces the covered-deposit set
}

SweepUpdate carries the writable fields of a sweep status change.

type Tx

type Tx interface {
	WithTx(ctx context.Context, fn func(ctx context.Context, s Store) error) error
}

Tx is the transactional boundary. WithTx runs fn inside one database transaction: every repo call made through fn's Store is atomic with the others — commit on nil, rollback on error or panic. Required for the multi-record invariants: checkpoint advance + block record writes (FR-026), deposit CREDITED flip + outbox emission (§3b), sweep create + sequence reserve. Implementations run nested WithTx calls inside the already-open transaction.

type WatchRepo

type WatchRepo interface {
	Upsert(ctx context.Context, w WatchedAddress) error
	Get(ctx context.Context, chainID, address string) (WatchedAddress, error)
	ListActive(ctx context.Context, chainID string) ([]WatchedAddress, error)
	SetActive(ctx context.Context, chainID, address string, active bool) error
}

WatchRepo persists the exchange-controlled address set.

type WatchedAddress

type WatchedAddress struct {
	ChainID      string
	Address      string
	Kind         WatchedAddressKind
	CustomerRef  string
	MemoRequired bool
	Active       bool
}

WatchedAddress is one exchange-controlled address (data model §9). UNIQUE(ChainID, Address). CustomerRef is an opaque exchange-side reference; the kit never stores PII.

type WatchedAddressKind

type WatchedAddressKind string

WatchedAddressKind drives scanner attribution and sweep/reconciliation scoping (data model §9).

const (
	WatchCustomerDeposit WatchedAddressKind = "CUSTOMER_DEPOSIT"
	WatchHotWallet       WatchedAddressKind = "HOT_WALLET"
	WatchColdWallet      WatchedAddressKind = "COLD_WALLET"
	WatchFeeWallet       WatchedAddressKind = "FEE_WALLET"
	WatchOmnibus         WatchedAddressKind = "OMNIBUS"
)

func (WatchedAddressKind) Valid

func (k WatchedAddressKind) Valid() bool

Valid reports whether k is a known kind.

type WithdrawalRecord

type WithdrawalRecord struct {
	WithdrawalID       string
	IdempotencyKey     string
	ChainID            string
	SourceAddress      string
	DestinationAddress string
	Denom              string
	AmountBaseUnits    sdkmath.Int
	Memo               string
	AccountNumber      *uint64
	Sequence           *uint64
	GasWanted          *uint64
	GasLimit           *uint64
	FeeAmountBaseUnits *sdkmath.Int
	SignMode           string
	SignedTxBytes      []byte
	TxHash             *string
	BlockHeight        *uint64
	TxCode             *uint32
	RawLog             string
	Status             WithdrawalStatus
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

WithdrawalRecord is the withdrawal state machine record (data model §5). PK WithdrawalID; UNIQUE IdempotencyKey (FR-033). SignedTxBytes is persisted at SIGNED so reconciliation rebroadcasts the exact same bytes, never re-signs.

type WithdrawalRepo

type WithdrawalRepo interface {
	// Create inserts a withdrawal; an idempotency-key hit returns
	// ErrDuplicate (FR-033 — resolve the original via GetByIdempotencyKey).
	Create(ctx context.Context, w WithdrawalRecord) (WithdrawalRecord, error)
	Get(ctx context.Context, withdrawalID string) (WithdrawalRecord, error)
	GetByIdempotencyKey(ctx context.Context, idempotencyKey string) (WithdrawalRecord, error)
	ListByStatus(ctx context.Context, chainID string, status WithdrawalStatus, limit int) ([]WithdrawalRecord, error)

	// UpdateStatus moves a withdrawal from → to, applying set; semantics as
	// DepositRepo.UpdateStatus.
	UpdateStatus(ctx context.Context, withdrawalID string, from, to WithdrawalStatus, set WithdrawalUpdate) error

	// SumCommittedBySource reports the count and summed AmountBaseUnits of the
	// withdrawals for (chainID, sourceAddress) that currently hold a funds
	// reservation — status in {FUNDS_RESERVED, SEQUENCE_RESERVED,
	// TRANSACTION_BUILT, TRANSACTION_SIMULATED, SIGNED, BROADCAST}; REQUESTED /
	// ADDRESS_VALIDATED / COMPLIANCE_APPROVED (not yet reserved) and the
	// terminal states (CONFIRMED / FAILED / CANCELLED) are excluded. A
	// REVIEW_REQUIRED record remains committed when signed_tx_bytes is present:
	// an uncertain signed or broadcast transaction may still spend the funds.
	// Pre-sign review records do not hold a reservation. The caller adds count ×
	// its configured max-fee cap to obtain
	// the conservative reserved total; the on-chain balance must cover that
	// total plus the new withdrawal before FUNDS_RESERVED, so concurrent
	// reserves from one source cannot jointly over-commit the wallet.
	SumCommittedBySource(ctx context.Context, chainID, sourceAddress string) (count int64, sumAmount sdkmath.Int, err error)
}

WithdrawalRepo persists WithdrawalRecords and enforces the §5 state machine.

type WithdrawalStatus

type WithdrawalStatus string

WithdrawalStatus is the withdrawal state machine status (data model §5).

const (
	WithdrawalRequested            WithdrawalStatus = "REQUESTED"
	WithdrawalAddressValidated     WithdrawalStatus = "ADDRESS_VALIDATED"
	WithdrawalComplianceApproved   WithdrawalStatus = "COMPLIANCE_APPROVED"
	WithdrawalFundsReserved        WithdrawalStatus = "FUNDS_RESERVED"
	WithdrawalSequenceReserved     WithdrawalStatus = "SEQUENCE_RESERVED"
	WithdrawalTransactionBuilt     WithdrawalStatus = "TRANSACTION_BUILT"
	WithdrawalTransactionSimulated WithdrawalStatus = "TRANSACTION_SIMULATED"
	WithdrawalSigned               WithdrawalStatus = "SIGNED"
	WithdrawalBroadcast            WithdrawalStatus = "BROADCAST"
	WithdrawalIncluded             WithdrawalStatus = "INCLUDED"
	WithdrawalConfirmed            WithdrawalStatus = "CONFIRMED"
	WithdrawalFailed               WithdrawalStatus = "FAILED"
	WithdrawalCancelled            WithdrawalStatus = "CANCELLED"
	WithdrawalReviewRequired       WithdrawalStatus = "REVIEW_REQUIRED"
)

func (WithdrawalStatus) Valid

func (s WithdrawalStatus) Valid() bool

Valid reports whether s is a known status.

type WithdrawalUpdate

type WithdrawalUpdate struct {
	AccountNumber      *uint64
	Sequence           *uint64
	GasWanted          *uint64
	GasLimit           *uint64
	FeeAmountBaseUnits *sdkmath.Int
	SignedTxBytes      []byte
	TxHash             *string
	BlockHeight        *uint64
	TxCode             *uint32
	RawLog             *string
}

WithdrawalUpdate carries the writable fields of a withdrawal status change.

type WorkKind

type WorkKind string

WorkKind identifies the work item owning a sequence reservation.

const (
	WorkWithdrawal WorkKind = "WITHDRAWAL"
	WorkSweep      WorkKind = "SWEEP"
)

func (WorkKind) Valid

func (k WorkKind) Valid() bool

Valid reports whether k is a known kind.

type WorkRef

type WorkRef struct {
	Kind WorkKind
	ID   string
}

WorkRef binds a sequence reservation to exactly one work item (UNIQUE(work_kind, work_id) — one reservation per work item).

Directories

Path Synopsis
internal
sqlstore
Package sqlstore is the shared database/sql implementation of the storage.Store contract.
Package sqlstore is the shared database/sql implementation of the storage.Store contract.
storetest
Package storetest is the backend-agnostic conformance suite for storage.Store implementations.
Package storetest is the backend-agnostic conformance suite for storage.Store implementations.
Package migrations embeds the kit's SQL schema, one file set per dialect.
Package migrations embeds the kit's SQL schema, one file set per dialect.
Package postgres provides the kit's production storage backend over pgx/v5's database/sql driver (R7).
Package postgres provides the kit's production storage backend over pgx/v5's database/sql driver (R7).
Package sqlite provides the kit's default, CGO-free storage backend over modernc.org/sqlite (R7).
Package sqlite provides the kit's default, CGO-free storage backend over modernc.org/sqlite (R7).

Jump to

Keyboard shortcuts

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