Ctrl K
ComunidadGuías…

internal/domain/donations.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package domain

import (
	"errors"
	"time"
)

// Crypto donations: one deterministic BIP32 deposit address per user, the
// same address on every EVM-compatible chain (same secp256k1 curve and
// derivation path; only the RPC endpoint and token contracts differ per
// chain). A background watcher per enabled chain detects incoming native
// currency or stablecoin transfers to a user's address and credits Stars
// once the deposit reaches the chain's configured confirmation depth. See
// docs/donations.md.

var (
	ErrDonationWalletNotConfigured = errors.New("donations: wallet not configured")
	ErrDonationWalletAlreadyExists = errors.New("donations: wallet already exists")
	ErrDonationChainDisabled       = errors.New("donations: chain disabled or misconfigured")
	ErrDonationChainNotFound       = errors.New("donations: chain not found")
	ErrDonationDepositInvalid      = errors.New("donations: deposit invalid")
)

// DonationDepositStatus is the deposit's lifecycle: pending (seen, not yet
// at the required confirmation depth) -> confirmed (depth reached, about to
// be priced and credited) -> credited (Stars granted; terminal) or orphaned
// (the block it was in was reorganized out of the canonical chain before
// reaching depth; terminal, never credited).
type DonationDepositStatus string

const (
	DonationDepositPending   DonationDepositStatus = "pending"
	DonationDepositConfirmed DonationDepositStatus = "confirmed"
	DonationDepositCredited  DonationDepositStatus = "credited"
	DonationDepositOrphaned  DonationDepositStatus = "orphaned"
)

// DonationChain is one configured EVM-compatible network. Disabled chains
// (Enabled false, typically because RPCURL is still empty) are never
// watched. ManualUSDRateMicros is USD per one whole native unit, scaled by
// 1e6, used when PriceFeedAddress has no reachable Chainlink aggregator
// (e.g. local Ganache, or before an operator sets one).
type DonationChain struct {
	Key                   string
	Name                  string
	ChainID               int64
	RPCURL                string
	WSURL                 string
	NativeSymbol          string
	NativeDecimals        int
	ConfirmationsRequired int
	PriceFeedAddress      string
	ManualUSDRateMicros   int64
	Enabled               bool
}

// Valid reports whether the chain is enabled and has enough configuration
// to actually be watched.
func (c DonationChain) Valid() bool {
	return c.Key != "" && c.ChainID > 0 && c.NativeDecimals > 0 && c.ConfirmationsRequired > 0
}

// Watchable reports whether the chain is enabled and has an RPC endpoint to
// connect to -- the two things a migration-seeded placeholder row lacks
// until an operator fills them in.
func (c DonationChain) Watchable() bool {
	return c.Valid() && c.Enabled && c.RPCURL != ""
}

// DonationToken is a stablecoin contract watched on one chain. An empty
// ContractAddress means the operator hasn't filled it in yet (e.g. no
// citable official Sepolia USDT deployment, or Ganache's mock not deployed
// yet) -- the watcher skips it rather than watching a zero address.
type DonationToken struct {
	ChainKey        string
	Symbol          string
	ContractAddress string
	Decimals        int
}

// Watchable reports whether this token has a contract address to watch.
func (t DonationToken) Watchable() bool {
	return t.ContractAddress != ""
}

// DonationAddress is a user's permanent, chain-agnostic deposit address.
type DonationAddress struct {
	UserID          int64
	DerivationIndex int64
	Address         string
	CreatedAt       time.Time
}

// DonationDeposit is one detected on-chain transfer to a user's deposit
// address, tracked from first sight through crediting (or orphaning on a
// reorg). TokenSymbol is empty for a native-currency deposit; LogIndex is
// -1 for one (there is no ERC-20 Transfer log to index).
type DonationDeposit struct {
	ID             int64
	UserID         int64
	ChainKey       string
	TokenSymbol    string
	TxHash         string
	LogIndex       int
	BlockNumber    int64
	AmountRaw      string // decimal string; arbitrary precision, smallest unit (wei etc.)
	USDValueMicros int64
	StarsCredited  int64
	Status         DonationDepositStatus
	Confirmations  int
	DetectedAt     time.Time
	CreditedAt     time.Time
}

// DonationChainConfigUpdate is the operator-editable subset of a
// DonationChain: everything except the chain's identity (Key/Name/ChainID)
// and its currency's fixed properties (NativeSymbol/NativeDecimals), which
// describe the network itself rather than how this server watches it.
type DonationChainConfigUpdate struct {
	ChainKey              string
	RPCURL                string
	WSURL                 string
	ConfirmationsRequired int
	PriceFeedAddress      string
	ManualUSDRateMicros   int64
	Enabled               bool
}

// DonationCreditNotice is everything a "your deposit was credited" chat
// notification needs, handed from the watcher (which knows the chain/asset
// it just priced) to whatever sends the actual message (app/bots.Service,
// via the donations.CreditNotifier port) without either side depending on
// the other's package.
type DonationCreditNotice struct {
	UserID        int64
	ChainName     string
	AssetSymbol   string
	AssetDecimals int
	Deposit       DonationDeposit // already Status == DonationDepositCredited
}