fixed linting config
This commit is contained in:
@@ -21,8 +21,8 @@ func announcementFields(announce Announcement) []zap.Field {
|
||||
if announce.Rail != "" {
|
||||
fields = append(fields, zap.String("rail", announce.Rail))
|
||||
}
|
||||
if announce.Network != "" {
|
||||
fields = append(fields, zap.String("network", announce.Network))
|
||||
if network := legacyNetworkFromCurrencies(announce.Currencies); network != "" {
|
||||
fields = append(fields, zap.String("network", network))
|
||||
}
|
||||
if announce.InvokeURI != "" {
|
||||
fields = append(fields, zap.String("invoke_uri", announce.InvokeURI))
|
||||
|
||||
@@ -23,17 +23,18 @@ type ServiceSummary struct {
|
||||
}
|
||||
|
||||
type GatewaySummary struct {
|
||||
ID string `json:"id"`
|
||||
InstanceID string `json:"instanceId"`
|
||||
Rail string `json:"rail"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Currencies []string `json:"currencies,omitempty"`
|
||||
Ops []string `json:"ops,omitempty"`
|
||||
Limits *Limits `json:"limits,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Healthy bool `json:"healthy,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
ID string `json:"id"`
|
||||
InstanceID string `json:"instanceId"`
|
||||
Rail string `json:"rail"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Currencies []string `json:"currencies,omitempty"`
|
||||
CurrencyMeta []CurrencyAnnouncement `json:"currencyMeta,omitempty"`
|
||||
Ops []string `json:"ops,omitempty"`
|
||||
Limits *Limits `json:"limits,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Healthy bool `json:"healthy,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
}
|
||||
|
||||
func (r *Registry) Lookup(now time.Time) LookupResponse {
|
||||
@@ -51,6 +52,7 @@ func (r *Registry) Lookup(now time.Time) LookupResponse {
|
||||
Rail: entry.Rail,
|
||||
Network: entry.Network,
|
||||
Currencies: cloneStrings(entry.Currencies),
|
||||
CurrencyMeta: cloneCurrencyAnnouncements(entry.CurrencyMeta),
|
||||
Ops: cloneStrings(entry.Operations),
|
||||
Limits: cloneLimits(entry.Limits),
|
||||
Version: entry.Version,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -12,21 +13,22 @@ const (
|
||||
)
|
||||
|
||||
type RegistryEntry struct {
|
||||
ID string `json:"id"`
|
||||
InstanceID string `bson:"instanceId" json:"instanceId"`
|
||||
Service string `json:"service"`
|
||||
Rail string `json:"rail,omitempty"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Operations []string `json:"operations,omitempty"`
|
||||
Currencies []string `json:"currencies,omitempty"`
|
||||
Limits *Limits `json:"limits,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Health HealthParams `json:"health,omitempty"`
|
||||
LastHeartbeat time.Time `json:"lastHeartbeat,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Healthy bool `json:"healthy,omitempty"`
|
||||
ID string `json:"id"`
|
||||
InstanceID string `bson:"instanceId" json:"instanceId"`
|
||||
Service string `json:"service"`
|
||||
Rail string `json:"rail,omitempty"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Operations []string `json:"operations,omitempty"`
|
||||
Currencies []string `json:"currencies,omitempty"`
|
||||
CurrencyMeta []CurrencyAnnouncement `json:"currencyMeta,omitempty"`
|
||||
Limits *Limits `json:"limits,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Health HealthParams `json:"health,omitempty"`
|
||||
LastHeartbeat time.Time `json:"lastHeartbeat,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Healthy bool `json:"healthy,omitempty"`
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
@@ -200,15 +202,17 @@ func (r *Registry) List(now time.Time, onlyHealthy bool) []RegistryEntry {
|
||||
|
||||
func registryEntryFromAnnouncement(announce Announcement, now time.Time) RegistryEntry {
|
||||
status := "ok"
|
||||
currencies := cloneCurrencyAnnouncements(announce.Currencies)
|
||||
return RegistryEntry{
|
||||
ID: strings.TrimSpace(announce.ID),
|
||||
InstanceID: strings.TrimSpace(announce.InstanceID),
|
||||
Service: strings.TrimSpace(announce.Service),
|
||||
Rail: strings.ToUpper(strings.TrimSpace(announce.Rail)),
|
||||
Network: strings.ToUpper(strings.TrimSpace(announce.Network)),
|
||||
Network: legacyNetworkFromCurrencies(currencies),
|
||||
Operations: cloneStrings(announce.Operations),
|
||||
Currencies: cloneStrings(announce.Currencies),
|
||||
Limits: cloneLimits(announce.Limits),
|
||||
Currencies: legacyCurrencyCodes(currencies),
|
||||
CurrencyMeta: currencies,
|
||||
Limits: legacyLimitsFromCurrencies(currencies),
|
||||
InvokeURI: strings.TrimSpace(announce.InvokeURI),
|
||||
RoutingPriority: announce.RoutingPriority,
|
||||
Version: strings.TrimSpace(announce.Version),
|
||||
@@ -228,12 +232,21 @@ func normalizeEntry(entry RegistryEntry) RegistryEntry {
|
||||
entry.Rail = strings.ToUpper(strings.TrimSpace(entry.Rail))
|
||||
entry.Network = strings.ToUpper(strings.TrimSpace(entry.Network))
|
||||
entry.Operations = normalizeStrings(entry.Operations, false)
|
||||
entry.Currencies = normalizeStrings(entry.Currencies, true)
|
||||
entry.CurrencyMeta = normalizeCurrencyAnnouncements(entry.CurrencyMeta)
|
||||
if len(entry.CurrencyMeta) > 0 {
|
||||
entry.Currencies = legacyCurrencyCodes(entry.CurrencyMeta)
|
||||
if derivedNetwork := legacyNetworkFromCurrencies(entry.CurrencyMeta); derivedNetwork != "" {
|
||||
entry.Network = derivedNetwork
|
||||
}
|
||||
entry.Limits = legacyLimitsFromCurrencies(entry.CurrencyMeta)
|
||||
} else {
|
||||
entry.Currencies = normalizeStrings(entry.Currencies, true)
|
||||
}
|
||||
entry.InvokeURI = strings.TrimSpace(entry.InvokeURI)
|
||||
entry.Version = strings.TrimSpace(entry.Version)
|
||||
entry.Status = strings.TrimSpace(entry.Status)
|
||||
entry.Health = normalizeHealth(entry.Health)
|
||||
if entry.Limits != nil {
|
||||
if len(entry.CurrencyMeta) == 0 && entry.Limits != nil {
|
||||
entry.Limits = normalizeLimits(*entry.Limits)
|
||||
}
|
||||
return entry
|
||||
@@ -247,15 +260,11 @@ func normalizeAnnouncement(announce Announcement) Announcement {
|
||||
}
|
||||
announce.Service = strings.TrimSpace(announce.Service)
|
||||
announce.Rail = strings.ToUpper(strings.TrimSpace(announce.Rail))
|
||||
announce.Network = strings.ToUpper(strings.TrimSpace(announce.Network))
|
||||
announce.Operations = normalizeStrings(announce.Operations, false)
|
||||
announce.Currencies = normalizeStrings(announce.Currencies, true)
|
||||
announce.Currencies = normalizeCurrencyAnnouncements(announce.Currencies)
|
||||
announce.InvokeURI = strings.TrimSpace(announce.InvokeURI)
|
||||
announce.Version = strings.TrimSpace(announce.Version)
|
||||
announce.Health = normalizeHealth(announce.Health)
|
||||
if announce.Limits != nil {
|
||||
announce.Limits = normalizeLimits(*announce.Limits)
|
||||
}
|
||||
return announce
|
||||
}
|
||||
|
||||
@@ -309,6 +318,364 @@ func cloneLimits(src *Limits) *Limits {
|
||||
return &dst
|
||||
}
|
||||
|
||||
func normalizeCurrencyAnnouncements(values []CurrencyAnnouncement) []CurrencyAnnouncement {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
result := make([]CurrencyAnnouncement, 0, len(values))
|
||||
for _, value := range values {
|
||||
clean, ok := normalizeCurrencyAnnouncement(value)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key := strings.Join([]string{
|
||||
clean.Currency,
|
||||
clean.Network,
|
||||
clean.ProviderID,
|
||||
clean.ContractAddress,
|
||||
}, "|")
|
||||
if seen[key] {
|
||||
continue
|
||||
}
|
||||
seen[key] = true
|
||||
result = append(result, clean)
|
||||
}
|
||||
if len(result) == 0 {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func normalizeCurrencyAnnouncement(src CurrencyAnnouncement) (CurrencyAnnouncement, bool) {
|
||||
src.Currency = strings.ToUpper(strings.TrimSpace(src.Currency))
|
||||
if src.Currency == "" {
|
||||
return CurrencyAnnouncement{}, false
|
||||
}
|
||||
src.Network = strings.ToUpper(strings.TrimSpace(src.Network))
|
||||
src.ProviderID = strings.TrimSpace(src.ProviderID)
|
||||
src.ContractAddress = strings.ToLower(strings.TrimSpace(src.ContractAddress))
|
||||
if src.Decimals != nil && *src.Decimals < 0 {
|
||||
src.Decimals = nil
|
||||
}
|
||||
src.Limits = normalizeCurrencyLimits(src.Limits)
|
||||
return src, true
|
||||
}
|
||||
|
||||
func normalizeCurrencyLimits(src *CurrencyLimits) *CurrencyLimits {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := &CurrencyLimits{}
|
||||
if src.Amount != nil {
|
||||
amount := &CurrencyAmount{
|
||||
Min: strings.TrimSpace(src.Amount.Min),
|
||||
Max: strings.TrimSpace(src.Amount.Max),
|
||||
}
|
||||
if amount.Min != "" || amount.Max != "" {
|
||||
dst.Amount = amount
|
||||
}
|
||||
}
|
||||
if src.Running != nil {
|
||||
running := &CurrencyRunningLimits{}
|
||||
for _, limit := range src.Running.Volume {
|
||||
max := strings.TrimSpace(limit.Max)
|
||||
if max == "" {
|
||||
continue
|
||||
}
|
||||
window := normalizeWindow(limit.Window)
|
||||
if legacyWindowKey(window) == "" {
|
||||
continue
|
||||
}
|
||||
running.Volume = append(running.Volume, VolumeLimit{
|
||||
Window: window,
|
||||
Max: max,
|
||||
})
|
||||
}
|
||||
for _, limit := range src.Running.Velocity {
|
||||
if limit.Max <= 0 {
|
||||
continue
|
||||
}
|
||||
window := normalizeWindow(limit.Window)
|
||||
if legacyWindowKey(window) == "" {
|
||||
continue
|
||||
}
|
||||
running.Velocity = append(running.Velocity, VelocityLimit{
|
||||
Window: window,
|
||||
Max: limit.Max,
|
||||
})
|
||||
}
|
||||
if len(running.Volume) > 0 || len(running.Velocity) > 0 {
|
||||
dst.Running = running
|
||||
}
|
||||
}
|
||||
if dst.Amount == nil && dst.Running == nil {
|
||||
return nil
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func normalizeWindow(src Window) Window {
|
||||
src.Raw = strings.TrimSpace(src.Raw)
|
||||
src.Duration = strings.TrimSpace(src.Duration)
|
||||
src.Named = strings.TrimSpace(src.Named)
|
||||
if src.Calendar != nil {
|
||||
cal := &CalendarWindow{
|
||||
Unit: CalendarUnit(strings.ToLower(strings.TrimSpace(string(src.Calendar.Unit)))),
|
||||
Count: src.Calendar.Count,
|
||||
}
|
||||
if cal.Count <= 0 {
|
||||
cal.Count = 1
|
||||
}
|
||||
if cal.Unit == CalendarUnitUnspecified {
|
||||
cal = nil
|
||||
}
|
||||
src.Calendar = cal
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
func cloneCurrencyAnnouncements(values []CurrencyAnnouncement) []CurrencyAnnouncement {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]CurrencyAnnouncement, 0, len(values))
|
||||
for _, value := range values {
|
||||
cp := CurrencyAnnouncement{
|
||||
Currency: value.Currency,
|
||||
Network: value.Network,
|
||||
ProviderID: value.ProviderID,
|
||||
ContractAddress: value.ContractAddress,
|
||||
}
|
||||
if value.Decimals != nil {
|
||||
decimals := *value.Decimals
|
||||
cp.Decimals = &decimals
|
||||
}
|
||||
cp.Limits = cloneCurrencyLimits(value.Limits)
|
||||
out = append(out, cp)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneCurrencyLimits(src *CurrencyLimits) *CurrencyLimits {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := &CurrencyLimits{}
|
||||
if src.Amount != nil {
|
||||
dst.Amount = &CurrencyAmount{
|
||||
Min: src.Amount.Min,
|
||||
Max: src.Amount.Max,
|
||||
}
|
||||
}
|
||||
if src.Running != nil {
|
||||
running := &CurrencyRunningLimits{}
|
||||
if len(src.Running.Volume) > 0 {
|
||||
running.Volume = make([]VolumeLimit, 0, len(src.Running.Volume))
|
||||
for _, item := range src.Running.Volume {
|
||||
running.Volume = append(running.Volume, VolumeLimit{
|
||||
Window: cloneWindow(item.Window),
|
||||
Max: item.Max,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(src.Running.Velocity) > 0 {
|
||||
running.Velocity = make([]VelocityLimit, 0, len(src.Running.Velocity))
|
||||
for _, item := range src.Running.Velocity {
|
||||
running.Velocity = append(running.Velocity, VelocityLimit{
|
||||
Window: cloneWindow(item.Window),
|
||||
Max: item.Max,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(running.Volume) > 0 || len(running.Velocity) > 0 {
|
||||
dst.Running = running
|
||||
}
|
||||
}
|
||||
if dst.Amount == nil && dst.Running == nil {
|
||||
return nil
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func cloneWindow(src Window) Window {
|
||||
dst := Window{
|
||||
Raw: src.Raw,
|
||||
Duration: src.Duration,
|
||||
Named: src.Named,
|
||||
}
|
||||
if src.Calendar != nil {
|
||||
dst.Calendar = &CalendarWindow{
|
||||
Unit: src.Calendar.Unit,
|
||||
Count: src.Calendar.Count,
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func legacyCurrencyCodes(values []CurrencyAnnouncement) []string {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
out := make([]string, 0, len(values))
|
||||
for _, value := range values {
|
||||
currency := strings.ToUpper(strings.TrimSpace(value.Currency))
|
||||
if currency == "" || seen[currency] {
|
||||
continue
|
||||
}
|
||||
seen[currency] = true
|
||||
out = append(out, currency)
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func legacyNetworkFromCurrencies(values []CurrencyAnnouncement) string {
|
||||
if len(values) == 0 {
|
||||
return ""
|
||||
}
|
||||
network := ""
|
||||
for _, value := range values {
|
||||
current := strings.ToUpper(strings.TrimSpace(value.Network))
|
||||
if current == "" {
|
||||
continue
|
||||
}
|
||||
if network == "" {
|
||||
network = current
|
||||
continue
|
||||
}
|
||||
if network != current {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return network
|
||||
}
|
||||
|
||||
func legacyLimitsFromCurrencies(values []CurrencyAnnouncement) *Limits {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
var merged *Limits
|
||||
for _, value := range values {
|
||||
current := legacyLimitsFromCurrency(value.Limits)
|
||||
if current == nil {
|
||||
continue
|
||||
}
|
||||
if merged == nil {
|
||||
merged = current
|
||||
continue
|
||||
}
|
||||
if !strings.EqualFold(strings.TrimSpace(merged.MinAmount), strings.TrimSpace(current.MinAmount)) {
|
||||
merged.MinAmount = ""
|
||||
}
|
||||
if !strings.EqualFold(strings.TrimSpace(merged.MaxAmount), strings.TrimSpace(current.MaxAmount)) {
|
||||
merged.MaxAmount = ""
|
||||
}
|
||||
merged.VolumeLimit = intersectStringMaps(merged.VolumeLimit, current.VolumeLimit)
|
||||
merged.VelocityLimit = intersectIntMaps(merged.VelocityLimit, current.VelocityLimit)
|
||||
}
|
||||
if merged == nil {
|
||||
return nil
|
||||
}
|
||||
if merged.MinAmount == "" && merged.MaxAmount == "" && len(merged.VolumeLimit) == 0 && len(merged.VelocityLimit) == 0 {
|
||||
return nil
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
func legacyLimitsFromCurrency(src *CurrencyLimits) *Limits {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
out := &Limits{}
|
||||
if src.Amount != nil {
|
||||
out.MinAmount = strings.TrimSpace(src.Amount.Min)
|
||||
out.MaxAmount = strings.TrimSpace(src.Amount.Max)
|
||||
}
|
||||
if src.Running != nil {
|
||||
if len(src.Running.Volume) > 0 {
|
||||
out.VolumeLimit = map[string]string{}
|
||||
for _, item := range src.Running.Volume {
|
||||
key := legacyWindowKey(item.Window)
|
||||
max := strings.TrimSpace(item.Max)
|
||||
if key == "" || max == "" {
|
||||
continue
|
||||
}
|
||||
out.VolumeLimit[key] = max
|
||||
}
|
||||
}
|
||||
if len(src.Running.Velocity) > 0 {
|
||||
out.VelocityLimit = map[string]int{}
|
||||
for _, item := range src.Running.Velocity {
|
||||
key := legacyWindowKey(item.Window)
|
||||
if key == "" || item.Max <= 0 {
|
||||
continue
|
||||
}
|
||||
out.VelocityLimit[key] = item.Max
|
||||
}
|
||||
}
|
||||
}
|
||||
if out.MinAmount == "" && out.MaxAmount == "" && len(out.VolumeLimit) == 0 && len(out.VelocityLimit) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func intersectStringMaps(left, right map[string]string) map[string]string {
|
||||
if len(left) == 0 || len(right) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := map[string]string{}
|
||||
for key, value := range left {
|
||||
if rightValue, ok := right[key]; ok && strings.EqualFold(strings.TrimSpace(value), strings.TrimSpace(rightValue)) {
|
||||
out[key] = value
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func intersectIntMaps(left, right map[string]int) map[string]int {
|
||||
if len(left) == 0 || len(right) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := map[string]int{}
|
||||
for key, value := range left {
|
||||
if rightValue, ok := right[key]; ok && value == rightValue {
|
||||
out[key] = value
|
||||
}
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func legacyWindowKey(window Window) string {
|
||||
if raw := strings.TrimSpace(window.Raw); raw != "" {
|
||||
return raw
|
||||
}
|
||||
if named := strings.TrimSpace(window.Named); named != "" {
|
||||
return named
|
||||
}
|
||||
if duration := strings.TrimSpace(window.Duration); duration != "" {
|
||||
return duration
|
||||
}
|
||||
if window.Calendar != nil && window.Calendar.Unit != CalendarUnitUnspecified {
|
||||
count := window.Calendar.Count
|
||||
if count <= 0 {
|
||||
count = 1
|
||||
}
|
||||
return fmt.Sprintf("%d%s", count, strings.ToLower(strings.TrimSpace(string(window.Calendar.Unit))))
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func normalizeStrings(values []string, upper bool) []string {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
|
||||
@@ -5,6 +5,78 @@ type HealthParams struct {
|
||||
TimeoutSec int `json:"timeoutSec"`
|
||||
}
|
||||
|
||||
// CurrencyAmount defines per-transfer min/max for a unit (fiat currency or crypto asset).
|
||||
// Values are decimals in string form to avoid float issues.
|
||||
type CurrencyAmount struct {
|
||||
Min string `json:"min,omitempty"`
|
||||
Max string `json:"max,omitempty"`
|
||||
}
|
||||
|
||||
// CalendarUnit is used for calendar-aligned windows (e.g. 1 calendar month).
|
||||
type CalendarUnit string
|
||||
|
||||
const (
|
||||
CalendarUnitUnspecified CalendarUnit = ""
|
||||
CalendarUnitHour CalendarUnit = "hour"
|
||||
CalendarUnitDay CalendarUnit = "day"
|
||||
CalendarUnitWeek CalendarUnit = "week"
|
||||
CalendarUnitMonth CalendarUnit = "month"
|
||||
)
|
||||
|
||||
// CalendarWindow represents a calendar-aligned window.
|
||||
// Example: {unit:"month", count:1} means "1 calendar month".
|
||||
type CalendarWindow struct {
|
||||
Unit CalendarUnit `json:"unit"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
// Window is a typed description of a running-limit window.
|
||||
// Gateways/providers can express windows differently, so we keep:
|
||||
// - Raw: original provider token/string (optional but recommended)
|
||||
// and one of the normalized forms:
|
||||
// - Duration: fixed window expressed as a Go-duration string (e.g. "24h", "168h")
|
||||
// - Calendar: calendar-aligned window (e.g. 1 month)
|
||||
// - Named: opaque provider token when you do not want/cannot normalize (e.g. "daily")
|
||||
type Window struct {
|
||||
// Raw may be set alongside the normalized form.
|
||||
// Normalized form: exactly one of Duration/Calendar/Named SHOULD be set.
|
||||
Raw string `json:"raw,omitempty"`
|
||||
|
||||
// Duration uses Go time.Duration format and MUST NOT use "d".
|
||||
// Use "24h", "168h", "720h", etc.
|
||||
Duration string `json:"duration,omitempty"` // e.g. "24h"
|
||||
Calendar *CalendarWindow `json:"calendar,omitempty"` // e.g. month x1
|
||||
Named string `json:"named,omitempty"` // e.g. "daily"
|
||||
}
|
||||
|
||||
// VolumeLimit is the max total amount allowed within a window.
|
||||
// Amount is a decimal string in the same unit as the announcement (currency/asset).
|
||||
type VolumeLimit struct {
|
||||
Window Window `json:"window"`
|
||||
Max string `json:"max"`
|
||||
}
|
||||
|
||||
// VelocityLimit is the max number of operations allowed within a window.
|
||||
type VelocityLimit struct {
|
||||
Window Window `json:"window"`
|
||||
Max int `json:"max"`
|
||||
}
|
||||
|
||||
// CurrencyRunningLimits groups windowed limits.
|
||||
// Slices are used instead of maps to avoid relying on untyped map keys.
|
||||
type CurrencyRunningLimits struct {
|
||||
Volume []VolumeLimit `json:"volume,omitempty"`
|
||||
Velocity []VelocityLimit `json:"velocity,omitempty"`
|
||||
}
|
||||
|
||||
// CurrencyLimits combines per-transfer and running limits for a unit.
|
||||
type CurrencyLimits struct {
|
||||
Amount *CurrencyAmount `json:"amount,omitempty"`
|
||||
Running *CurrencyRunningLimits `json:"running,omitempty"`
|
||||
}
|
||||
|
||||
// Limits is a legacy flat limits shape used by lookup summaries.
|
||||
// Deprecated: use CurrencyAnnouncement.Limits for announcement payloads.
|
||||
type Limits struct {
|
||||
MinAmount string `json:"minAmount,omitempty"`
|
||||
MaxAmount string `json:"maxAmount,omitempty"`
|
||||
@@ -12,19 +84,33 @@ type Limits struct {
|
||||
VelocityLimit map[string]int `json:"velocityLimit,omitempty"`
|
||||
}
|
||||
|
||||
// CurrencyAnnouncement declares limits for a unit.
|
||||
// For fiat: Currency is ISO 4217 ("EUR", "USD").
|
||||
// For crypto: Currency is the ticker ("USDT", "BTC") and you SHOULD also fill Network,
|
||||
// and for tokens ContractAddress + Decimals.
|
||||
type CurrencyAnnouncement struct {
|
||||
// Unit identity
|
||||
Currency string `json:"currency"` // fiat code or crypto ticker
|
||||
Network string `json:"network,omitempty"` // crypto chain or fiat rail, e.g. "tron", "ethereum", "sepa", "swift", "visa"
|
||||
ProviderID string `json:"providerId,omitempty"` // specific provider identifier providing currency over network/rail (e.g. "binance", "circle")
|
||||
ContractAddress string `json:"contractAddress,omitempty"` // for tokens only
|
||||
Decimals *int `json:"decimals,omitempty"` // for crypto/token precision
|
||||
|
||||
// Limits for this unit
|
||||
Limits *CurrencyLimits `json:"limits,omitempty"`
|
||||
}
|
||||
|
||||
type Announcement struct {
|
||||
ID string `json:"id"`
|
||||
InstanceID string `bson:"instanceId" json:"instanceId"`
|
||||
Service string `json:"service"`
|
||||
Rail string `json:"rail,omitempty"`
|
||||
Network string `json:"network,omitempty"`
|
||||
Operations []string `json:"operations,omitempty"`
|
||||
Currencies []string `json:"currencies,omitempty"`
|
||||
Limits *Limits `json:"limits,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Health HealthParams `json:"health,omitempty"`
|
||||
ID string `json:"id"`
|
||||
InstanceID string `bson:"instanceId" json:"instanceId"`
|
||||
Service string `json:"service"`
|
||||
Rail string `json:"rail,omitempty"`
|
||||
Operations []string `json:"operations,omitempty"`
|
||||
Currencies []CurrencyAnnouncement `json:"currencies,omitempty"`
|
||||
InvokeURI string `json:"invokeURI,omitempty"`
|
||||
RoutingPriority int `json:"routingPriority,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Health HealthParams `json:"health,omitempty"`
|
||||
}
|
||||
|
||||
type Heartbeat struct {
|
||||
|
||||
Reference in New Issue
Block a user