Documentation
¶
Overview ¶
Package compliance orchestrates the KYB lifecycle described in elliptic-compliance-integration.md §13: a counterparty submits an address, KYB approval triggers screening via pkg/compliance.Screener, and the verdict is applied to pkg/repository.CounterpartyRepository's three tables.
This is core-owned end to end — unlike pkg/services/mgpoller, which splits its interfaces because MoneyGram's flow touches credit-owned loans, nothing here reaches outside core, so there is no adapter indirection to a credit-side implementation.
Scope for this pass (Phase 2 of the source design doc): persistence and the lifecycle service. It does not submit the vault contract's allow_depositor transaction — see RecordScreening's doc comment on why that stays a separate, not-yet-built worker.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidAddress is a submitted address that isn't a well-formed // Stellar Ed25519 public key — rejected before any Elliptic call. ErrInvalidAddress = errors.New("address is not a valid stellar public key") // ErrCounterpartyMissing means an address's counterparty association // could not be loaded — should not happen given the foreign key, but // screening needs the counterparty's elliptic_customer_reference, so // this is checked explicitly rather than trusting a nil pointer. ErrCounterpartyMissing = errors.New("address has no associated counterparty") )
Functions ¶
This section is empty.
Types ¶
type Deps ¶
type Deps struct {
Repo repository.CounterpartyRepository
Screener pkgcompliance.Screener
ScreeningValidity time.Duration
Logger *slog.Logger
}
Deps are Service's collaborators; all required except Logger and ScreeningValidity.
type OnchainSigner ¶
type OnchainSigner interface {
AllowDepositor(ctx context.Context, address string) error
DisallowDepositor(ctx context.Context, address string) error
}
OnchainSigner is the two vault-contract calls the writer needs — narrow enough that soroban.Service satisfies it directly, and tests can fake it without a real signing key. See soroban.Service.WithComplianceRole's doc comment on why these calls need the compliance role key, not the admin key the rest of this backend already holds.
type OnchainWriter ¶
type OnchainWriter struct {
// contains filtered or unexported fields
}
OnchainWriter is the separate worker the source design doc §14 calls for: "the admin writes intent to counterparty_addresses and a separate worker performs the on-chain write and reconciles onchain_state — which keeps signing keys out of the web process." It runs in the credit backend (which already holds the treasury/admin keys), not cmd/admin.
func NewOnchainWriter ¶
func NewOnchainWriter(deps OnchainWriterDeps) *OnchainWriter
NewOnchainWriter builds the worker.
func (*OnchainWriter) Start ¶
func (w *OnchainWriter) Start(ctx context.Context)
Start runs the write loop until ctx is cancelled — the same tick-immediately-then-on-interval shape as every other ticker in this codebase (pkg/services/mpesapoller, pkg/services/vaultwatch).
type OnchainWriterDeps ¶
type OnchainWriterDeps struct {
Repo repository.CounterpartyRepository
Signer OnchainSigner
Interval time.Duration
Logger *slog.Logger
}
OnchainWriterDeps are OnchainWriter's collaborators; all required except Logger.
type RescreenSweep ¶
type RescreenSweep struct {
// contains filtered or unexported fields
}
RescreenSweep is the source design doc §6's "our own sweep": neither of Elliptic's own rescreening mechanisms (three rescreens over a window, or retries on a failed call) amount to standing monitoring, so an allowlist that gates money needs its own scheduled walk of every address whose screening has gone stale.
Unlike a batch-endpoint sweep, this reuses Service.ScreenAndRecord one address at a time — Phase 1 deliberately didn't build the POST /v2/wallet batch endpoint (out of scope, see pkg/compliance/elliptic doc.go), and at this volume the sync endpoint in a loop costs nothing extra worth a second client code path for.
func NewRescreenSweep ¶
func NewRescreenSweep(deps RescreenSweepDeps) *RescreenSweep
NewRescreenSweep builds the sweep.
func (*RescreenSweep) Start ¶
func (s *RescreenSweep) Start(ctx context.Context)
Start runs the sweep until ctx is cancelled — the same shape as every other ticker in this codebase.
type RescreenSweepDeps ¶
type RescreenSweepDeps struct {
Repo repository.CounterpartyRepository
Service *Service
Interval time.Duration
Logger *slog.Logger
}
RescreenSweepDeps are RescreenSweep's collaborators; all required except Logger.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service runs the KYB lifecycle described in doc.go.
func (*Service) ApproveKYB ¶
ApproveKYB approves the counterparty's KYB status, then screens every address already on file — source design doc §13 step 3.
func (*Service) ScreenAndRecord ¶
ScreenAndRecord is the core operation: screen one address via pkg/compliance.Screener and apply the source design doc §13 step 4 / §10 verdict branches. Also the admin's "rescreen now" action — screening is idempotent to call again, and address_screenings is append-only, so a manual rescreen is simply another call to this with no separate path.
func (*Service) SubmitAddress ¶
func (s *Service) SubmitAddress(ctx context.Context, counterpartyID, address string) (*models.CounterpartyAddress, error)
SubmitAddress validates address locally before writing anything — "a typo should not cost an API call" (source design doc §13 step 1) — then records it. If the counterparty's KYB is already approved, it is screened immediately; otherwise it waits at AddressStatusPending until ApproveKYB screens it.