Documentation
¶
Overview ¶
Package offramp defines the off-ramp Provider contract that every provider in the platform satisfies.
Provider is the single mandatory interface (ID + Initiate). Optional capabilities — StatusReader, Quoter, Directory, MobileMoneyDirectory, BalanceReporter — are separate small interfaces; consumers type-assert for what they need and providers implement only what they genuinely support.
Request and Result carry only cross-provider fields. Provider-specific extras travel on typed payloads via the ProviderOptions / ProviderPayload marker interfaces; the concrete types live in each provider's own package.
Registry resolves a Request to a concrete Provider, first by inspecting req.Options.ProviderID(), otherwise by aliasing req.PayoutMethod to a registered ProviderID. NoOpProvider in noop.go is a stand-in for tests.
Index ¶
- Constants
- func Fraction(f float64) *float64
- func LocalCurrency(countryCode string) string
- type BalanceReporter
- type Directory
- type ExchangeRate
- type MobileMoneyDirectory
- type MobileMoneyNetwork
- type NoOpProvider
- type Provider
- type ProviderID
- type ProviderInfo
- type ProviderOptions
- type ProviderPayload
- type ProviderRef
- type QuoteRequest
- type Quoter
- type RateBuffer
- type Registry
- type Request
- type Result
- type Status
- type StatusReader
- type TreasuryTransfer
Constants ¶
const ( PayoutMethodMobileMoney = "mobile_money" PayoutMethodCashPickup = "cash_pickup" )
PayoutMethod selects which provider handles a request when multiple are wired in via the registry. Empty string is treated as PayoutMethodMobileMoney.
Variables ¶
This section is empty.
Functions ¶
func Fraction ¶
Fraction returns a pointer to f, for populating optional buffer settings from literals in configuration and tests.
func LocalCurrency ¶ added in v1.1.2
LocalCurrency maps a country to the currency its rails settle in, or "" when the corridor is unsupported.
Types ¶
type BalanceReporter ¶
BalanceReporter reports a pre-funded balance held with the provider. Not implemented by providers that settle per-transaction (e.g. MoneyGram).
type Directory ¶
type Directory interface {
SupportedProviders(ctx context.Context, countryCode string) ([]ProviderInfo, error)
}
Directory advertises which provider configurations are available for a given country (e.g. YC's per-channel info, MG's cash-pickup option).
type ExchangeRate ¶
type ExchangeRate struct {
FromCurrency string
ToCurrency string
SellRate float64
BuyRate float64
RateID string
Locale string
UpdatedAt time.Time
}
ExchangeRate is the canonical quote shape returned by Quoter.
type MobileMoneyDirectory ¶
type MobileMoneyDirectory interface {
Networks(ctx context.Context, countryCode string) ([]MobileMoneyNetwork, error)
}
MobileMoneyDirectory lists the MoMo operators available in a country. Only implemented by providers that actually operate on mobile-money rails.
type MobileMoneyNetwork ¶
MobileMoneyNetwork represents a MoMo operator.
type NoOpProvider ¶
type NoOpProvider struct{}
NoOpProvider is a minimal Provider stub for tests and bootstrap wiring. It returns a mock Result and nothing else — callers that need richer behaviour should depend on a real provider or a hand-rolled fake.
type Provider ¶
type Provider interface {
ID() ProviderID
Initiate(ctx context.Context, req Request) (*Result, error)
}
Provider is the single mandatory capability — every off-ramp must register and initiate. Optional behaviour is split into the other capability interfaces below; consumers type-assert for what they need.
type ProviderID ¶
type ProviderID string
ProviderID identifies a concrete off-ramp implementation in the registry.
const ( ProviderYellowCard ProviderID = "yellowcard" ProviderMoneyGram ProviderID = "moneygram" ProviderFonbnk ProviderID = "fonbnk" )
Known provider IDs. New providers should add their constant here.
type ProviderInfo ¶
type ProviderInfo struct {
ID string
Name string
SupportedMethods []string
MinAmount float64
MaxAmount float64
Currency string
Status string
FeeUSD float64
FeeLocal float64
EstimatedSettlementTime int
}
ProviderInfo describes an available off-ramp provider for a country.
type ProviderOptions ¶
type ProviderOptions interface {
ProviderID() ProviderID
}
ProviderOptions is the marker interface implemented by per-provider request extras (e.g. yellowcard.Options.SettlementMethod, moneygram.Options.BirthDate). Callers attach a concrete implementation to Request.Options; the receiving adapter type-asserts to its own concrete type.
type ProviderPayload ¶
type ProviderPayload interface {
ProviderID() ProviderID
}
ProviderPayload is the marker interface implemented by per-provider result extras (e.g. yellowcard.DirectSettlementPayload, moneygram.CashPickupPayload). Adapters set Result.Provider to a concrete implementation; consumers type- assert to read provider-specific output.
type ProviderRef ¶
type ProviderRef struct {
ID string
Provider ProviderID
Extra map[string]any
}
ProviderRef identifies an in-flight transaction enough to look it up. Extra is provider-scoped; document the expected keys in each provider's adapter so callers know what to pass.
type QuoteRequest ¶
type QuoteRequest struct {
Currency string
}
QuoteRequest carries the inputs a provider needs to quote a corridor. Future fields (amount, originating country, service option) can be added without breaking the interface.
type Quoter ¶
type Quoter interface {
Quote(ctx context.Context, q QuoteRequest) (*ExchangeRate, error)
}
Quoter exposes the provider's view of the FX rate for a corridor. The quote response may be cached upstream; the orchestration of multi-source quoting lives outside this interface.
type RateBuffer ¶
type RateBuffer struct {
// contains filtered or unexported fields
}
RateBuffer is a fractional safety margin deducted from a quoted FX rate to hedge drift between the moment a borrower is quoted and the moment the off-ramp settles.
func NewRateBuffer ¶
func NewRateBuffer(pct *float64, def float64) RateBuffer
NewRateBuffer resolves a configured fraction against a default.
pct is a pointer because zero is a meaningful setting — quote raw, no margin — and has to stay distinguishable from "not configured", which takes def instead.
func (RateBuffer) Apply ¶
func (b RateBuffer) Apply(rate float64) float64
Apply returns rate reduced by the margin, clamped at zero.
func (RateBuffer) Pct ¶
func (b RateBuffer) Pct() float64
Pct returns the resolved fraction, where 0.01 is 1 %. Zero means rates are quoted raw. Persist it alongside the rate so drift is auditable after the fact.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps ProviderIDs to Provider implementations and resolves an incoming Request to the right provider. The resolution order is:
func (*Registry) Alias ¶
func (r *Registry) Alias(payoutMethod string, id ProviderID) error
Alias maps a PayoutMethod string (e.g. PayoutMethodMobileMoney) to a registered ProviderID. The provider must already be registered.
func (*Registry) All ¶
All returns every registered Provider in unspecified order. Useful for fanning out menu rendering across providers (Directory capability).
func (*Registry) Get ¶
func (r *Registry) Get(id ProviderID) (Provider, bool)
Get returns the Provider for an explicit ID. Useful for callers that already know which provider they want (e.g. a poller bound to MG loans).
type Request ¶
type Request struct {
LoanID string
UserID string
RecipientName string
AmountUSD float64
AmountStroops int64
DestinationPhone string
CountryCode string
IdempotencyKey string
NetworkCode string
NetworkName string
// PayoutMethod is consulted by the registry to pick a provider when the
// caller doesn't pin one via Options. Empty defaults to mobile money.
PayoutMethod string
// Options carries per-provider extras (yellowcard.Options,
// moneygram.Options). nil is acceptable; each adapter documents its
// expectations for missing/wrong types.
Options ProviderOptions
}
Request contains the cross-provider data needed to initiate an off-ramp. Provider-specific extras live on Options.
type Result ¶
type Result struct {
RequestID string
SequenceID string
Status string
AmountUSD float64
AmountLocal float64
LocalCurrency string
ExchangeRate float64
Fee float64
FeeLocal float64
EstimatedTime int
CreatedAt time.Time
SettlementMethod string // tag for downstream persistence: "direct"|"fiat"|"cash_pickup"
// Provider is the typed payload returned by the adapter. Consumers
// type-assert to the concrete payload type owned by the provider package.
Provider ProviderPayload
}
Result is what Provider.Initiate returns. Cross-provider summary fields stay on the struct; provider-specific output lives in Provider.
type Status ¶
type Status struct {
RequestID string
SequenceID string
Status string
AmountLocal float64
LocalCurrency string
CompletedAt *time.Time
FailureReason *string
}
Status contains status information for an in-flight off-ramp.
type StatusReader ¶
type StatusReader interface {
Status(ctx context.Context, ref ProviderRef) (*Status, error)
}
StatusReader looks up an in-flight off-ramp by ProviderRef. ProviderRef carries the transaction ID plus provider-scoped extras (e.g. MoneyGram needs the child memo to authenticate the SEP-10 session).
type TreasuryTransfer ¶
type TreasuryTransfer interface {
SendUSDC(ctx context.Context, destination string, memo string, amount int64) (txHash string, err error)
CheckUSDCTrustline(ctx context.Context, address string) (hasTrustline bool, err error)
}
TreasuryTransfer abstracts sending USDC from the custodial treasury to an external Stellar address. Implemented by Stellar service adapters; injected into off-ramp providers that need to settle on-chain.