package orchestrator import ( "strings" "time" "github.com/tech/sendico/payments/storage/model" chainasset "github.com/tech/sendico/pkg/chain" paymenttypes "github.com/tech/sendico/pkg/payments/types" feesv1 "github.com/tech/sendico/pkg/proto/billing/fees/v1" accountingv1 "github.com/tech/sendico/pkg/proto/common/accounting/v1" fxv1 "github.com/tech/sendico/pkg/proto/common/fx/v1" gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1" moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1" chainv1 "github.com/tech/sendico/pkg/proto/gateway/chain/v1" oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1" orchestratorv1 "github.com/tech/sendico/pkg/proto/payments/orchestrator/v1" "google.golang.org/protobuf/types/known/timestamppb" ) func intentFromProto(src *orchestratorv1.PaymentIntent) model.PaymentIntent { if src == nil { return model.PaymentIntent{} } intent := model.PaymentIntent{ Ref: src.GetRef(), Kind: modelKindFromProto(src.GetKind()), Source: endpointFromProto(src.GetSource()), Destination: endpointFromProto(src.GetDestination()), Amount: moneyFromProto(src.GetAmount()), RequiresFX: src.GetRequiresFx(), FeePolicy: feePolicyFromProto(src.GetFeePolicy()), SettlementMode: settlementModeFromProto(src.GetSettlementMode()), SettlementCurrency: strings.TrimSpace(src.GetSettlementCurrency()), Attributes: cloneMetadata(src.GetAttributes()), Customer: customerFromProto(src.GetCustomer()), } if src.GetFx() != nil { intent.FX = fxIntentFromProto(src.GetFx()) } return intent } func endpointFromProto(src *orchestratorv1.PaymentEndpoint) model.PaymentEndpoint { if src == nil { return model.PaymentEndpoint{Type: model.EndpointTypeUnspecified} } result := model.PaymentEndpoint{ Type: model.EndpointTypeUnspecified, InstanceID: strings.TrimSpace(src.GetInstanceId()), Metadata: cloneMetadata(src.GetMetadata()), } if ledger := src.GetLedger(); ledger != nil { result.Type = model.EndpointTypeLedger result.Ledger = &model.LedgerEndpoint{ LedgerAccountRef: strings.TrimSpace(ledger.GetLedgerAccountRef()), ContraLedgerAccountRef: strings.TrimSpace(ledger.GetContraLedgerAccountRef()), } return result } if managed := src.GetManagedWallet(); managed != nil { result.Type = model.EndpointTypeManagedWallet result.ManagedWallet = &model.ManagedWalletEndpoint{ ManagedWalletRef: strings.TrimSpace(managed.GetManagedWalletRef()), Asset: assetFromProto(managed.GetAsset()), } return result } if external := src.GetExternalChain(); external != nil { result.Type = model.EndpointTypeExternalChain result.ExternalChain = &model.ExternalChainEndpoint{ Asset: assetFromProto(external.GetAsset()), Address: strings.TrimSpace(external.GetAddress()), Memo: strings.TrimSpace(external.GetMemo()), } return result } if card := src.GetCard(); card != nil { result.Type = model.EndpointTypeCard result.Card = &model.CardEndpoint{ Pan: strings.TrimSpace(card.GetPan()), Token: strings.TrimSpace(card.GetToken()), Cardholder: strings.TrimSpace(card.GetCardholderName()), CardholderSurname: strings.TrimSpace(card.GetCardholderSurname()), ExpMonth: card.GetExpMonth(), ExpYear: card.GetExpYear(), Country: strings.TrimSpace(card.GetCountry()), MaskedPan: strings.TrimSpace(card.GetMaskedPan()), } return result } return result } func fxIntentFromProto(src *orchestratorv1.FXIntent) *model.FXIntent { if src == nil { return nil } return &model.FXIntent{ Pair: pairFromProto(src.GetPair()), Side: fxSideFromProto(src.GetSide()), Firm: src.GetFirm(), TTLMillis: src.GetTtlMs(), PreferredProvider: strings.TrimSpace(src.GetPreferredProvider()), MaxAgeMillis: src.GetMaxAgeMs(), } } func quoteSnapshotToModel(src *orchestratorv1.PaymentQuote) *model.PaymentQuoteSnapshot { if src == nil { return nil } return &model.PaymentQuoteSnapshot{ DebitAmount: moneyFromProto(src.GetDebitAmount()), DebitSettlementAmount: moneyFromProto(src.GetDebitSettlementAmount()), ExpectedSettlementAmount: moneyFromProto(src.GetExpectedSettlementAmount()), ExpectedFeeTotal: moneyFromProto(src.GetExpectedFeeTotal()), FeeLines: feeLinesFromProto(src.GetFeeLines()), FeeRules: feeRulesFromProto(src.GetFeeRules()), FXQuote: fxQuoteFromProto(src.GetFxQuote()), NetworkFee: networkFeeFromProto(src.GetNetworkFee()), QuoteRef: strings.TrimSpace(src.GetQuoteRef()), } } func toProtoPayment(src *model.Payment) *orchestratorv1.Payment { if src == nil { return nil } payment := &orchestratorv1.Payment{ PaymentRef: src.PaymentRef, IdempotencyKey: src.IdempotencyKey, Intent: protoIntentFromModel(src.Intent), State: protoStateFromModel(src.State), FailureCode: protoFailureFromModel(src.FailureCode), FailureReason: src.FailureReason, LastQuote: modelQuoteToProto(src.LastQuote), Execution: protoExecutionFromModel(src.Execution), ExecutionPlan: protoExecutionPlanFromModel(src.ExecutionPlan), PaymentPlan: protoPaymentPlanFromModel(src.PaymentPlan), Metadata: cloneMetadata(src.Metadata), } if src.CardPayout != nil { payment.CardPayout = &orchestratorv1.CardPayout{ PayoutRef: src.CardPayout.PayoutRef, ProviderPaymentId: src.CardPayout.ProviderPaymentID, Status: src.CardPayout.Status, FailureReason: src.CardPayout.FailureReason, CardCountry: src.CardPayout.CardCountry, MaskedPan: src.CardPayout.MaskedPan, ProviderCode: src.CardPayout.ProviderCode, GatewayReference: src.CardPayout.GatewayReference, } } if src.CreatedAt.IsZero() { payment.CreatedAt = timestamppb.New(time.Now().UTC()) } else { payment.CreatedAt = timestamppb.New(src.CreatedAt.UTC()) } if src.UpdatedAt != (time.Time{}) { payment.UpdatedAt = timestamppb.New(src.UpdatedAt.UTC()) } return payment } func protoIntentFromModel(src model.PaymentIntent) *orchestratorv1.PaymentIntent { intent := &orchestratorv1.PaymentIntent{ Ref: src.Ref, Kind: protoKindFromModel(src.Kind), Source: protoEndpointFromModel(src.Source), Destination: protoEndpointFromModel(src.Destination), Amount: protoMoney(src.Amount), RequiresFx: src.RequiresFX, FeePolicy: feePolicyToProto(src.FeePolicy), SettlementMode: settlementModeToProto(src.SettlementMode), SettlementCurrency: strings.TrimSpace(src.SettlementCurrency), Attributes: cloneMetadata(src.Attributes), Customer: protoCustomerFromModel(src.Customer), } if src.FX != nil { intent.Fx = protoFXIntentFromModel(src.FX) } return intent } func customerFromProto(src *orchestratorv1.Customer) *model.Customer { if src == nil { return nil } return &model.Customer{ ID: strings.TrimSpace(src.GetId()), FirstName: strings.TrimSpace(src.GetFirstName()), MiddleName: strings.TrimSpace(src.GetMiddleName()), LastName: strings.TrimSpace(src.GetLastName()), IP: strings.TrimSpace(src.GetIp()), Zip: strings.TrimSpace(src.GetZip()), Country: strings.TrimSpace(src.GetCountry()), State: strings.TrimSpace(src.GetState()), City: strings.TrimSpace(src.GetCity()), Address: strings.TrimSpace(src.GetAddress()), } } func protoCustomerFromModel(src *model.Customer) *orchestratorv1.Customer { if src == nil { return nil } return &orchestratorv1.Customer{ Id: strings.TrimSpace(src.ID), FirstName: strings.TrimSpace(src.FirstName), MiddleName: strings.TrimSpace(src.MiddleName), LastName: strings.TrimSpace(src.LastName), Ip: strings.TrimSpace(src.IP), Zip: strings.TrimSpace(src.Zip), Country: strings.TrimSpace(src.Country), State: strings.TrimSpace(src.State), City: strings.TrimSpace(src.City), Address: strings.TrimSpace(src.Address), } } func protoEndpointFromModel(src model.PaymentEndpoint) *orchestratorv1.PaymentEndpoint { endpoint := &orchestratorv1.PaymentEndpoint{ Metadata: cloneMetadata(src.Metadata), InstanceId: strings.TrimSpace(src.InstanceID), } switch src.Type { case model.EndpointTypeLedger: if src.Ledger != nil { endpoint.Endpoint = &orchestratorv1.PaymentEndpoint_Ledger{ Ledger: &orchestratorv1.LedgerEndpoint{ LedgerAccountRef: src.Ledger.LedgerAccountRef, ContraLedgerAccountRef: src.Ledger.ContraLedgerAccountRef, }, } } case model.EndpointTypeManagedWallet: if src.ManagedWallet != nil { endpoint.Endpoint = &orchestratorv1.PaymentEndpoint_ManagedWallet{ ManagedWallet: &orchestratorv1.ManagedWalletEndpoint{ ManagedWalletRef: src.ManagedWallet.ManagedWalletRef, Asset: assetToProto(src.ManagedWallet.Asset), }, } } case model.EndpointTypeExternalChain: if src.ExternalChain != nil { endpoint.Endpoint = &orchestratorv1.PaymentEndpoint_ExternalChain{ ExternalChain: &orchestratorv1.ExternalChainEndpoint{ Asset: assetToProto(src.ExternalChain.Asset), Address: src.ExternalChain.Address, Memo: src.ExternalChain.Memo, }, } } case model.EndpointTypeCard: if src.Card != nil { card := &orchestratorv1.CardEndpoint{ CardholderName: src.Card.Cardholder, CardholderSurname: src.Card.CardholderSurname, ExpMonth: src.Card.ExpMonth, ExpYear: src.Card.ExpYear, Country: src.Card.Country, MaskedPan: src.Card.MaskedPan, } if pan := strings.TrimSpace(src.Card.Pan); pan != "" { card.Card = &orchestratorv1.CardEndpoint_Pan{Pan: pan} } if token := strings.TrimSpace(src.Card.Token); token != "" { card.Card = &orchestratorv1.CardEndpoint_Token{Token: token} } endpoint.Endpoint = &orchestratorv1.PaymentEndpoint_Card{Card: card} } default: // leave unspecified } return endpoint } func protoFXIntentFromModel(src *model.FXIntent) *orchestratorv1.FXIntent { if src == nil { return nil } return &orchestratorv1.FXIntent{ Pair: pairToProto(src.Pair), Side: fxSideToProto(src.Side), Firm: src.Firm, TtlMs: src.TTLMillis, PreferredProvider: src.PreferredProvider, MaxAgeMs: src.MaxAgeMillis, } } func protoExecutionFromModel(src *model.ExecutionRefs) *orchestratorv1.ExecutionRefs { if src == nil { return nil } return &orchestratorv1.ExecutionRefs{ DebitEntryRef: src.DebitEntryRef, CreditEntryRef: src.CreditEntryRef, FxEntryRef: src.FXEntryRef, ChainTransferRef: src.ChainTransferRef, CardPayoutRef: src.CardPayoutRef, FeeTransferRef: src.FeeTransferRef, } } func protoExecutionStepFromModel(src *model.ExecutionStep) *orchestratorv1.ExecutionStep { if src == nil { return nil } return &orchestratorv1.ExecutionStep{ Code: src.Code, Description: src.Description, Amount: protoMoney(src.Amount), NetworkFee: protoMoney(src.NetworkFee), SourceWalletRef: src.SourceWalletRef, DestinationRef: src.DestinationRef, TransferRef: src.TransferRef, Metadata: cloneMetadata(src.Metadata), OperationRef: src.OperationRef, } } func protoExecutionPlanFromModel(src *model.ExecutionPlan) *orchestratorv1.ExecutionPlan { if src == nil { return nil } steps := make([]*orchestratorv1.ExecutionStep, 0, len(src.Steps)) for _, step := range src.Steps { if protoStep := protoExecutionStepFromModel(step); protoStep != nil { steps = append(steps, protoStep) } } if len(steps) == 0 { steps = nil } return &orchestratorv1.ExecutionPlan{ Steps: steps, TotalNetworkFee: protoMoney(src.TotalNetworkFee), } } func protoPaymentStepFromModel(src *model.PaymentStep) *orchestratorv1.PaymentStep { if src == nil { return nil } return &orchestratorv1.PaymentStep{ Rail: protoRailFromModel(src.Rail), GatewayId: strings.TrimSpace(src.GatewayID), Action: protoRailOperationFromModel(src.Action), Amount: protoMoney(src.Amount), StepId: strings.TrimSpace(src.StepID), InstanceId: strings.TrimSpace(src.InstanceID), DependsOn: cloneStringList(src.DependsOn), CommitPolicy: strings.TrimSpace(string(src.CommitPolicy)), CommitAfter: cloneStringList(src.CommitAfter), } } func protoPaymentPlanFromModel(src *model.PaymentPlan) *orchestratorv1.PaymentPlan { if src == nil { return nil } steps := make([]*orchestratorv1.PaymentStep, 0, len(src.Steps)) for _, step := range src.Steps { if protoStep := protoPaymentStepFromModel(step); protoStep != nil { steps = append(steps, protoStep) } } if len(steps) == 0 { steps = nil } plan := &orchestratorv1.PaymentPlan{ Id: strings.TrimSpace(src.ID), Steps: steps, IdempotencyKey: strings.TrimSpace(src.IdempotencyKey), FxQuote: fxQuoteToProto(src.FXQuote), Fees: feeLinesToProto(src.Fees), } if !src.CreatedAt.IsZero() { plan.CreatedAt = timestamppb.New(src.CreatedAt.UTC()) } return plan } func modelQuoteToProto(src *model.PaymentQuoteSnapshot) *orchestratorv1.PaymentQuote { if src == nil { return nil } return &orchestratorv1.PaymentQuote{ DebitAmount: protoMoney(src.DebitAmount), DebitSettlementAmount: protoMoney(src.DebitSettlementAmount), ExpectedSettlementAmount: protoMoney(src.ExpectedSettlementAmount), ExpectedFeeTotal: protoMoney(src.ExpectedFeeTotal), FeeLines: feeLinesToProto(src.FeeLines), FeeRules: feeRulesToProto(src.FeeRules), FxQuote: fxQuoteToProto(src.FXQuote), NetworkFee: networkFeeToProto(src.NetworkFee), QuoteRef: strings.TrimSpace(src.QuoteRef), } } func filterFromProto(req *orchestratorv1.ListPaymentsRequest) *model.PaymentFilter { if req == nil { return &model.PaymentFilter{} } filter := &model.PaymentFilter{ SourceRef: strings.TrimSpace(req.GetSourceRef()), DestinationRef: strings.TrimSpace(req.GetDestinationRef()), OrganizationRef: strings.TrimSpace(req.GetOrganizationRef()), } if req.GetPage() != nil { filter.Cursor = strings.TrimSpace(req.GetPage().GetCursor()) filter.Limit = req.GetPage().GetLimit() } if len(req.GetFilterStates()) > 0 { filter.States = make([]model.PaymentState, 0, len(req.GetFilterStates())) for _, st := range req.GetFilterStates() { filter.States = append(filter.States, modelStateFromProto(st)) } } return filter } func protoKindFromModel(kind model.PaymentKind) orchestratorv1.PaymentKind { switch kind { case model.PaymentKindPayout: return orchestratorv1.PaymentKind_PAYMENT_KIND_PAYOUT case model.PaymentKindInternalTransfer: return orchestratorv1.PaymentKind_PAYMENT_KIND_INTERNAL_TRANSFER case model.PaymentKindFXConversion: return orchestratorv1.PaymentKind_PAYMENT_KIND_FX_CONVERSION default: return orchestratorv1.PaymentKind_PAYMENT_KIND_UNSPECIFIED } } func modelKindFromProto(kind orchestratorv1.PaymentKind) model.PaymentKind { switch kind { case orchestratorv1.PaymentKind_PAYMENT_KIND_PAYOUT: return model.PaymentKindPayout case orchestratorv1.PaymentKind_PAYMENT_KIND_INTERNAL_TRANSFER: return model.PaymentKindInternalTransfer case orchestratorv1.PaymentKind_PAYMENT_KIND_FX_CONVERSION: return model.PaymentKindFXConversion default: return model.PaymentKindUnspecified } } func protoRailFromModel(rail model.Rail) gatewayv1.Rail { switch strings.ToUpper(strings.TrimSpace(string(rail))) { case string(model.RailCrypto): return gatewayv1.Rail_RAIL_CRYPTO case string(model.RailProviderSettlement): return gatewayv1.Rail_RAIL_PROVIDER_SETTLEMENT case string(model.RailLedger): return gatewayv1.Rail_RAIL_LEDGER case string(model.RailCardPayout): return gatewayv1.Rail_RAIL_CARD_PAYOUT case string(model.RailFiatOnRamp): return gatewayv1.Rail_RAIL_FIAT_ONRAMP default: return gatewayv1.Rail_RAIL_UNSPECIFIED } } func protoRailOperationFromModel(action model.RailOperation) gatewayv1.RailOperation { switch strings.ToUpper(strings.TrimSpace(string(action))) { case string(model.RailOperationDebit): return gatewayv1.RailOperation_RAIL_OPERATION_DEBIT case string(model.RailOperationCredit): return gatewayv1.RailOperation_RAIL_OPERATION_CREDIT case string(model.RailOperationExternalDebit): return gatewayv1.RailOperation_RAIL_OPERATION_DEBIT case string(model.RailOperationExternalCredit): return gatewayv1.RailOperation_RAIL_OPERATION_CREDIT case string(model.RailOperationMove): return gatewayv1.RailOperation_RAIL_OPERATION_MOVE case string(model.RailOperationSend): return gatewayv1.RailOperation_RAIL_OPERATION_SEND case string(model.RailOperationFee): return gatewayv1.RailOperation_RAIL_OPERATION_FEE case string(model.RailOperationObserveConfirm): return gatewayv1.RailOperation_RAIL_OPERATION_OBSERVE_CONFIRM case string(model.RailOperationFXConvert): return gatewayv1.RailOperation_RAIL_OPERATION_FX_CONVERT case string(model.RailOperationBlock): return gatewayv1.RailOperation_RAIL_OPERATION_BLOCK case string(model.RailOperationRelease): return gatewayv1.RailOperation_RAIL_OPERATION_RELEASE default: return gatewayv1.RailOperation_RAIL_OPERATION_UNSPECIFIED } } func protoStateFromModel(state model.PaymentState) orchestratorv1.PaymentState { switch state { case model.PaymentStateAccepted: return orchestratorv1.PaymentState_PAYMENT_STATE_ACCEPTED case model.PaymentStateFundsReserved: return orchestratorv1.PaymentState_PAYMENT_STATE_FUNDS_RESERVED case model.PaymentStateSubmitted: return orchestratorv1.PaymentState_PAYMENT_STATE_SUBMITTED case model.PaymentStateSettled: return orchestratorv1.PaymentState_PAYMENT_STATE_SETTLED case model.PaymentStateFailed: return orchestratorv1.PaymentState_PAYMENT_STATE_FAILED case model.PaymentStateCancelled: return orchestratorv1.PaymentState_PAYMENT_STATE_CANCELLED default: return orchestratorv1.PaymentState_PAYMENT_STATE_UNSPECIFIED } } func modelStateFromProto(state orchestratorv1.PaymentState) model.PaymentState { switch state { case orchestratorv1.PaymentState_PAYMENT_STATE_ACCEPTED: return model.PaymentStateAccepted case orchestratorv1.PaymentState_PAYMENT_STATE_FUNDS_RESERVED: return model.PaymentStateFundsReserved case orchestratorv1.PaymentState_PAYMENT_STATE_SUBMITTED: return model.PaymentStateSubmitted case orchestratorv1.PaymentState_PAYMENT_STATE_SETTLED: return model.PaymentStateSettled case orchestratorv1.PaymentState_PAYMENT_STATE_FAILED: return model.PaymentStateFailed case orchestratorv1.PaymentState_PAYMENT_STATE_CANCELLED: return model.PaymentStateCancelled default: return model.PaymentStateUnspecified } } func protoFailureFromModel(code model.PaymentFailureCode) orchestratorv1.PaymentFailureCode { switch code { case model.PaymentFailureCodeBalance: return orchestratorv1.PaymentFailureCode_FAILURE_BALANCE case model.PaymentFailureCodeLedger: return orchestratorv1.PaymentFailureCode_FAILURE_LEDGER case model.PaymentFailureCodeFX: return orchestratorv1.PaymentFailureCode_FAILURE_FX case model.PaymentFailureCodeChain: return orchestratorv1.PaymentFailureCode_FAILURE_CHAIN case model.PaymentFailureCodeFees: return orchestratorv1.PaymentFailureCode_FAILURE_FEES case model.PaymentFailureCodePolicy: return orchestratorv1.PaymentFailureCode_FAILURE_POLICY default: return orchestratorv1.PaymentFailureCode_FAILURE_UNSPECIFIED } } func settlementModeFromProto(mode orchestratorv1.SettlementMode) model.SettlementMode { switch mode { case orchestratorv1.SettlementMode_SETTLEMENT_FIX_SOURCE: return model.SettlementModeFixSource case orchestratorv1.SettlementMode_SETTLEMENT_FIX_RECEIVED: return model.SettlementModeFixReceived default: return model.SettlementModeUnspecified } } func settlementModeToProto(mode model.SettlementMode) orchestratorv1.SettlementMode { switch mode { case model.SettlementModeFixSource: return orchestratorv1.SettlementMode_SETTLEMENT_FIX_SOURCE case model.SettlementModeFixReceived: return orchestratorv1.SettlementMode_SETTLEMENT_FIX_RECEIVED default: return orchestratorv1.SettlementMode_SETTLEMENT_UNSPECIFIED } } func moneyFromProto(m *moneyv1.Money) *paymenttypes.Money { if m == nil { return nil } return &paymenttypes.Money{ Currency: m.GetCurrency(), Amount: m.GetAmount(), } } func protoMoney(m *paymenttypes.Money) *moneyv1.Money { if m == nil { return nil } return &moneyv1.Money{ Currency: m.GetCurrency(), Amount: m.GetAmount(), } } func feePolicyFromProto(src *feesv1.PolicyOverrides) *paymenttypes.FeePolicy { if src == nil { return nil } return &paymenttypes.FeePolicy{ InsufficientNet: insufficientPolicyFromProto(src.GetInsufficientNet()), } } func feePolicyToProto(src *paymenttypes.FeePolicy) *feesv1.PolicyOverrides { if src == nil { return nil } return &feesv1.PolicyOverrides{ InsufficientNet: insufficientPolicyToProto(src.InsufficientNet), } } func insufficientPolicyFromProto(policy feesv1.InsufficientNetPolicy) paymenttypes.InsufficientNetPolicy { switch policy { case feesv1.InsufficientNetPolicy_BLOCK_POSTING: return paymenttypes.InsufficientNetBlockPosting case feesv1.InsufficientNetPolicy_SWEEP_ORG_CASH: return paymenttypes.InsufficientNetSweepOrgCash case feesv1.InsufficientNetPolicy_INVOICE_LATER: return paymenttypes.InsufficientNetInvoiceLater default: return paymenttypes.InsufficientNetUnspecified } } func insufficientPolicyToProto(policy paymenttypes.InsufficientNetPolicy) feesv1.InsufficientNetPolicy { switch policy { case paymenttypes.InsufficientNetBlockPosting: return feesv1.InsufficientNetPolicy_BLOCK_POSTING case paymenttypes.InsufficientNetSweepOrgCash: return feesv1.InsufficientNetPolicy_SWEEP_ORG_CASH case paymenttypes.InsufficientNetInvoiceLater: return feesv1.InsufficientNetPolicy_INVOICE_LATER default: return feesv1.InsufficientNetPolicy_INSUFFICIENT_NET_UNSPECIFIED } } func pairFromProto(pair *fxv1.CurrencyPair) *paymenttypes.CurrencyPair { if pair == nil { return nil } return &paymenttypes.CurrencyPair{ Base: pair.GetBase(), Quote: pair.GetQuote(), } } func pairToProto(pair *paymenttypes.CurrencyPair) *fxv1.CurrencyPair { if pair == nil { return nil } return &fxv1.CurrencyPair{ Base: pair.GetBase(), Quote: pair.GetQuote(), } } func fxSideFromProto(side fxv1.Side) paymenttypes.FXSide { switch side { case fxv1.Side_BUY_BASE_SELL_QUOTE: return paymenttypes.FXSideBuyBaseSellQuote case fxv1.Side_SELL_BASE_BUY_QUOTE: return paymenttypes.FXSideSellBaseBuyQuote default: return paymenttypes.FXSideUnspecified } } func fxSideToProto(side paymenttypes.FXSide) fxv1.Side { switch side { case paymenttypes.FXSideBuyBaseSellQuote: return fxv1.Side_BUY_BASE_SELL_QUOTE case paymenttypes.FXSideSellBaseBuyQuote: return fxv1.Side_SELL_BASE_BUY_QUOTE default: return fxv1.Side_SIDE_UNSPECIFIED } } func fxQuoteFromProto(quote *oraclev1.Quote) *paymenttypes.FXQuote { if quote == nil { return nil } return &paymenttypes.FXQuote{ QuoteRef: strings.TrimSpace(quote.GetQuoteRef()), Pair: pairFromProto(quote.GetPair()), Side: fxSideFromProto(quote.GetSide()), Price: decimalFromProto(quote.GetPrice()), BaseAmount: moneyFromProto(quote.GetBaseAmount()), QuoteAmount: moneyFromProto(quote.GetQuoteAmount()), ExpiresAtUnixMs: quote.GetExpiresAtUnixMs(), Provider: strings.TrimSpace(quote.GetProvider()), RateRef: strings.TrimSpace(quote.GetRateRef()), Firm: quote.GetFirm(), } } func fxQuoteToProto(quote *paymenttypes.FXQuote) *oraclev1.Quote { if quote == nil { return nil } return &oraclev1.Quote{ QuoteRef: strings.TrimSpace(quote.QuoteRef), Pair: pairToProto(quote.Pair), Side: fxSideToProto(quote.Side), Price: decimalToProto(quote.Price), BaseAmount: protoMoney(quote.BaseAmount), QuoteAmount: protoMoney(quote.QuoteAmount), ExpiresAtUnixMs: quote.ExpiresAtUnixMs, Provider: strings.TrimSpace(quote.Provider), RateRef: strings.TrimSpace(quote.RateRef), Firm: quote.Firm, } } func decimalFromProto(value *moneyv1.Decimal) *paymenttypes.Decimal { if value == nil { return nil } return &paymenttypes.Decimal{Value: value.GetValue()} } func decimalToProto(value *paymenttypes.Decimal) *moneyv1.Decimal { if value == nil { return nil } return &moneyv1.Decimal{Value: value.GetValue()} } func assetFromProto(asset *chainv1.Asset) *paymenttypes.Asset { if asset == nil { return nil } return &paymenttypes.Asset{ Chain: chainasset.NetworkAlias(asset.GetChain()), TokenSymbol: asset.GetTokenSymbol(), ContractAddress: asset.GetContractAddress(), } } func assetToProto(asset *paymenttypes.Asset) *chainv1.Asset { if asset == nil { return nil } return &chainv1.Asset{ Chain: chainasset.NetworkFromString(asset.Chain), TokenSymbol: asset.TokenSymbol, ContractAddress: asset.ContractAddress, } } func networkFeeFromProto(resp *chainv1.EstimateTransferFeeResponse) *paymenttypes.NetworkFeeEstimate { if resp == nil { return nil } return &paymenttypes.NetworkFeeEstimate{ NetworkFee: moneyFromProto(resp.GetNetworkFee()), EstimationContext: strings.TrimSpace(resp.GetEstimationContext()), } } func networkFeeToProto(resp *paymenttypes.NetworkFeeEstimate) *chainv1.EstimateTransferFeeResponse { if resp == nil { return nil } return &chainv1.EstimateTransferFeeResponse{ NetworkFee: protoMoney(resp.NetworkFee), EstimationContext: strings.TrimSpace(resp.EstimationContext), } } func feeLinesFromProto(lines []*feesv1.DerivedPostingLine) []*paymenttypes.FeeLine { if len(lines) == 0 { return nil } result := make([]*paymenttypes.FeeLine, 0, len(lines)) for _, line := range lines { if line == nil { continue } result = append(result, &paymenttypes.FeeLine{ LedgerAccountRef: strings.TrimSpace(line.GetLedgerAccountRef()), Money: moneyFromProto(line.GetMoney()), LineType: postingLineTypeFromProto(line.GetLineType()), Side: entrySideFromProto(line.GetSide()), Meta: cloneMetadata(line.GetMeta()), }) } if len(result) == 0 { return nil } return result } func feeLinesToProto(lines []*paymenttypes.FeeLine) []*feesv1.DerivedPostingLine { if len(lines) == 0 { return nil } result := make([]*feesv1.DerivedPostingLine, 0, len(lines)) for _, line := range lines { if line == nil { continue } result = append(result, &feesv1.DerivedPostingLine{ LedgerAccountRef: strings.TrimSpace(line.LedgerAccountRef), Money: protoMoney(line.Money), LineType: postingLineTypeToProto(line.LineType), Side: entrySideToProto(line.Side), Meta: cloneMetadata(line.Meta), }) } if len(result) == 0 { return nil } return result } func feeRulesFromProto(rules []*feesv1.AppliedRule) []*paymenttypes.AppliedRule { if len(rules) == 0 { return nil } result := make([]*paymenttypes.AppliedRule, 0, len(rules)) for _, rule := range rules { if rule == nil { continue } result = append(result, &paymenttypes.AppliedRule{ RuleID: strings.TrimSpace(rule.GetRuleId()), RuleVersion: strings.TrimSpace(rule.GetRuleVersion()), Formula: strings.TrimSpace(rule.GetFormula()), Rounding: roundingModeFromProto(rule.GetRounding()), TaxCode: strings.TrimSpace(rule.GetTaxCode()), TaxRate: strings.TrimSpace(rule.GetTaxRate()), Parameters: cloneMetadata(rule.GetParameters()), }) } if len(result) == 0 { return nil } return result } func feeRulesToProto(rules []*paymenttypes.AppliedRule) []*feesv1.AppliedRule { if len(rules) == 0 { return nil } result := make([]*feesv1.AppliedRule, 0, len(rules)) for _, rule := range rules { if rule == nil { continue } result = append(result, &feesv1.AppliedRule{ RuleId: strings.TrimSpace(rule.RuleID), RuleVersion: strings.TrimSpace(rule.RuleVersion), Formula: strings.TrimSpace(rule.Formula), Rounding: roundingModeToProto(rule.Rounding), TaxCode: strings.TrimSpace(rule.TaxCode), TaxRate: strings.TrimSpace(rule.TaxRate), Parameters: cloneMetadata(rule.Parameters), }) } if len(result) == 0 { return nil } return result } func entrySideFromProto(side accountingv1.EntrySide) paymenttypes.EntrySide { switch side { case accountingv1.EntrySide_ENTRY_SIDE_DEBIT: return paymenttypes.EntrySideDebit case accountingv1.EntrySide_ENTRY_SIDE_CREDIT: return paymenttypes.EntrySideCredit default: return paymenttypes.EntrySideUnspecified } } func entrySideToProto(side paymenttypes.EntrySide) accountingv1.EntrySide { switch side { case paymenttypes.EntrySideDebit: return accountingv1.EntrySide_ENTRY_SIDE_DEBIT case paymenttypes.EntrySideCredit: return accountingv1.EntrySide_ENTRY_SIDE_CREDIT default: return accountingv1.EntrySide_ENTRY_SIDE_UNSPECIFIED } } func postingLineTypeFromProto(lineType accountingv1.PostingLineType) paymenttypes.PostingLineType { switch lineType { case accountingv1.PostingLineType_POSTING_LINE_FEE: return paymenttypes.PostingLineTypeFee case accountingv1.PostingLineType_POSTING_LINE_TAX: return paymenttypes.PostingLineTypeTax case accountingv1.PostingLineType_POSTING_LINE_SPREAD: return paymenttypes.PostingLineTypeSpread case accountingv1.PostingLineType_POSTING_LINE_REVERSAL: return paymenttypes.PostingLineTypeReversal default: return paymenttypes.PostingLineTypeUnspecified } } func postingLineTypeToProto(lineType paymenttypes.PostingLineType) accountingv1.PostingLineType { switch lineType { case paymenttypes.PostingLineTypeFee: return accountingv1.PostingLineType_POSTING_LINE_FEE case paymenttypes.PostingLineTypeTax: return accountingv1.PostingLineType_POSTING_LINE_TAX case paymenttypes.PostingLineTypeSpread: return accountingv1.PostingLineType_POSTING_LINE_SPREAD case paymenttypes.PostingLineTypeReversal: return accountingv1.PostingLineType_POSTING_LINE_REVERSAL default: return accountingv1.PostingLineType_POSTING_LINE_TYPE_UNSPECIFIED } } func roundingModeFromProto(mode moneyv1.RoundingMode) paymenttypes.RoundingMode { switch mode { case moneyv1.RoundingMode_ROUND_HALF_EVEN: return paymenttypes.RoundingModeHalfEven case moneyv1.RoundingMode_ROUND_HALF_UP: return paymenttypes.RoundingModeHalfUp case moneyv1.RoundingMode_ROUND_DOWN: return paymenttypes.RoundingModeDown default: return paymenttypes.RoundingModeUnspecified } } func roundingModeToProto(mode paymenttypes.RoundingMode) moneyv1.RoundingMode { switch mode { case paymenttypes.RoundingModeHalfEven: return moneyv1.RoundingMode_ROUND_HALF_EVEN case paymenttypes.RoundingModeHalfUp: return moneyv1.RoundingMode_ROUND_HALF_UP case paymenttypes.RoundingModeDown: return moneyv1.RoundingMode_ROUND_DOWN default: return moneyv1.RoundingMode_ROUNDING_MODE_UNSPECIFIED } }