contracts

package
v1.0.5 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: AGPL-3.0 Imports: 3 Imported by: 0

Documentation

Overview

Package contracts holds the interface seams between the platform's modules, together with the data types those interfaces exchange. It is a dependency-free boundary layer: producers and consumers both import contracts and depend on its abstractions rather than on each other, which keeps implementations swappable and avoids import cycles.

The interfaces

Lender (lending.go) is the loan port — eligibility assessment, origination, and retrieval. The package that originates loans implements it; handlers and jobs depend only on the interface.

LoanNotifier (lending.go) and AccountNotifier (pin.go) are the notification ports. They are implemented by the notification layer, which may deliver over SMS, push, or any other transport, and are consumed by the services that need to tell a user about loan lifecycle events (approved, disbursed, off-ramp failed, cash-pickup ready, repayment received) or account and PIN events (registration, wrong-PIN attempts, lockout, PIN change and reset).

The data types

EligibilityRequest and EligibilityResult frame an eligibility check; CreateLoanRequest and LoanRecord cover origination. A LoanRecord tracks both sides of a loan: the on-chain vault disbursement and the off-ramp settlement, including the settlement method, disbursement status, and provider reference. LoanNotification and AccountNotification carry the fields each notification method needs — not every field applies to every method. Monetary amounts are in stroops (USDC times ten million); display amounts and currencies travel alongside them on the notification types. Sentinel errors live in lending_errors.go.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotEligible           = errors.New("user is not eligible for a loan")
	ErrInsufficientLiquidity = errors.New("insufficient vault liquidity")
	ErrLoanNotFound          = errors.New("loan not found")
	ErrLoanNotActive         = errors.New("loan is not in an active state")
	ErrAccountNotFound       = errors.New("account not found")
	ErrAccountNotOwned       = errors.New("account is not owned by the user")
)

Functions

This section is empty.

Types

type AccountNotification

type AccountNotification struct {
	// UserID is the unique identifier of the user being notified.
	UserID string

	// PhoneNumber is the destination for SMS delivery (E.164 format).
	PhoneNumber string

	// FullName is used in registration welcome messages.
	FullName string

	// RemainingAttempts indicates how many PIN attempts remain before lockout.
	// Used by NotifyPINWrongAttempt.
	RemainingAttempts int

	// LockedUntil is a human-readable duration string (e.g. "15 minutes")
	// indicating how long until the lockout expires. Used by NotifyAccountLocked.
	LockedUntil string

	// Reason provides a human-readable explanation for failure notifications.
	Reason string

	// Language optionally pins the SMS language (ISO code: en/sw/fr). When
	// empty the notifier resolves it from the recipient's stored preference.
	Language string
}

AccountNotification carries the data needed to notify a user about account and PIN lifecycle events. Not all fields are used by every notification method; see individual method documentation for which fields are relevant.

type AccountNotifier

type AccountNotifier interface {
	// NotifyRegistrationSuccess informs a user that their account has been
	// created and their PIN is set.
	NotifyRegistrationSuccess(ctx context.Context, n AccountNotification) error

	// NotifyRegistrationFailed informs a user that their registration could
	// not be completed, along with a human-readable reason.
	NotifyRegistrationFailed(ctx context.Context, n AccountNotification) error

	// NotifyPINWrongAttempt warns a user that an incorrect PIN was entered
	// and includes the number of remaining attempts before lockout.
	NotifyPINWrongAttempt(ctx context.Context, n AccountNotification) error

	// NotifyAccountLocked informs a user that their account has been
	// temporarily locked due to repeated failed PIN attempts.
	NotifyAccountLocked(ctx context.Context, n AccountNotification) error

	// NotifyPINChanged confirms that the user's PIN was changed successfully.
	NotifyPINChanged(ctx context.Context, n AccountNotification) error

	// NotifyPINChangeFailed alerts a user that a PIN change attempt was
	// unsuccessful, along with the reason.
	NotifyPINChangeFailed(ctx context.Context, n AccountNotification) error

	// NotifyPINReset confirms that the user's PIN was reset successfully
	// via the recovery flow.
	NotifyPINReset(ctx context.Context, n AccountNotification) error

	// NotifyPINResetFailed alerts a user that a PIN reset attempt failed,
	// along with the reason.
	NotifyPINResetFailed(ctx context.Context, n AccountNotification) error
}

AccountNotifier defines the interface for sending account and PIN lifecycle notifications to users. Implementations may deliver via SMS, push, email, or any other transport. Methods must be safe for concurrent use.

type CreateLoanRequest

type CreateLoanRequest struct {
	UserID            string
	AccountID         string
	PrincipalAmount   int64  // In stroops
	PrincipalAsset    string // e.g. "USDC"
	InterestRateBps   int32  // Basis points
	DurationDays      int
	RepaymentSchedule string // "daily", "weekly", "bi_weekly", "monthly", "lump_sum"
}

CreateLoanRequest contains the data needed to create a new loan.

type EligibilityRequest

type EligibilityRequest struct {
	UserID       string
	Amount       int64 // In stroops (USDC * 10^7)
	DurationDays int
}

EligibilityRequest contains the data needed to assess loan eligibility.

type EligibilityResult

type EligibilityResult struct {
	Approved     bool
	Reason       string
	MaxAmount    int64   // Maximum eligible amount in stroops
	InterestRate float64 // Annual interest rate as a decimal (e.g. 0.12 = 12%)
}

EligibilityResult contains the outcome of an eligibility assessment.

type Lender

type Lender interface {
	AssessEligibility(ctx context.Context, req EligibilityRequest) (*EligibilityResult, error)
	CreateLoan(ctx context.Context, req CreateLoanRequest) (*LoanRecord, error)
	GetLoan(ctx context.Context, loanID string) (*LoanRecord, error)
	GetUserLoans(ctx context.Context, userID string) ([]*LoanRecord, error)
}

Lender defines the interface for loan origination and retrieval.

type LoanNotification

type LoanNotification struct {
	LoanID           string
	LoanReference    string
	UserID           string
	PhoneNumber      string
	Amount           int64   // Raw amount (stroops/cents) for consumers that need it
	DisplayAmount    float64 // Display-ready (e.g. 5000.00)
	DisplayCurrency  string  // e.g. "KES", "USD"
	Status           string
	Reason           string     // For rejection notifications
	RemainingBalance float64    // For repayment confirmations
	DueDate          *time.Time // For repayment reminders

	// InteractiveURL is the MoneyGram SEP-24 webview URL sent in the
	// cash-pickup initiated SMS. Empty for non-MG notifications.
	InteractiveURL string

	// CashPickupRef is the reference number the user quotes at the MG agent
	// when collecting cash. Populated once MG locks the payout.
	CashPickupRef string

	// CashPickupInfoURL is MoneyGram's support deep-link for the transaction,
	// sent alongside the reference so a borrower with a problem at the agent
	// has somewhere to go. Unlike InteractiveURL it stays valid after the
	// withdrawal settles.
	CashPickupInfoURL string

	// Language optionally pins the SMS language (ISO code: en/sw/fr). When
	// empty the notifier resolves it from the recipient's stored preference.
	Language string
}

LoanNotification contains data for loan lifecycle notifications.

type LoanNotifier

type LoanNotifier interface {
	NotifyLoanApproved(ctx context.Context, n LoanNotification) error
	NotifyLoanRejected(ctx context.Context, n LoanNotification) error
	NotifyLoanDisbursed(ctx context.Context, n LoanNotification) error
	NotifyLoanFailed(ctx context.Context, n LoanNotification) error
	// NotifyLoanOffRampFailed reports that vault borrow succeeded but fiat
	// disbursement could not be completed and the USDC has been returned to
	// the vault. Distinct from NotifyLoanFailed, which is a credit-default
	// notice.
	NotifyLoanOffRampFailed(ctx context.Context, n LoanNotification) error
	// NotifyLoanCashPickupApproved acknowledges approval of a cash-pickup
	// loan without implying a push disbursement is on the way. A subsequent
	// NotifyLoanCashPickupInitiated carries the MoneyGram interactive URL.
	NotifyLoanCashPickupApproved(ctx context.Context, n LoanNotification) error
	NotifyRepaymentReceived(ctx context.Context, n LoanNotification) error
	NotifyRepaymentReminder(ctx context.Context, n LoanNotification) error

	// NotifyLoanCashPickupInitiated sends the MoneyGram interactive URL to
	// the user. The locked payout amount is unknown at this point and
	// confirmed when the user opens the link; the template should make that
	// disclosure explicit.
	NotifyLoanCashPickupInitiated(ctx context.Context, n LoanNotification) error

	// NotifyLoanCashPickupReady sends the cash-pickup reference number once
	// MoneyGram has locked the payout. Template should include the
	// reference, the locked amount, and the currency.
	NotifyLoanCashPickupReady(ctx context.Context, n LoanNotification) error

	// NotifyLoanCashPickupCancelled tells the borrower their cash pickup was
	// cancelled and the funds returned. Distinct from NotifyLoanOffRampFailed:
	// the usual cause is the borrower cancelling in MoneyGram's own app, so
	// this reads as an acknowledgement rather than a failure.
	NotifyLoanCashPickupCancelled(ctx context.Context, n LoanNotification) error
}

LoanNotifier defines the interface for sending loan lifecycle notifications.

type LoanRecord

type LoanRecord struct {
	ID                 string
	LoanReference      string
	UserID             string
	AccountID          string
	PrincipalAmount    int64
	PrincipalAsset     string
	InterestRateBps    int32
	TotalAmount        int64
	DurationDays       int
	RepaymentSchedule  string
	DueDate            *time.Time
	Status             string // "pending", "approved", "disbursed", "repaid", "defaulted", "cancelled"
	VaultTxHash        string
	RampProvider       string
	RampRequestID      string
	RampSequenceID     string
	RampFiatAmount     int64
	RampFiatCurrency   string
	SettlementMethod   string // "direct" or "fiat"
	DisbursementStatus string // "pending", "crypto_sent", "processing", "complete", "refund_pending", "failed"
	CreatedAt          time.Time
	UpdatedAt          time.Time
}

LoanRecord represents a loan with vault and ramp disbursement tracking.

Jump to

Keyboard shortcuts

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