diff --git a/go.mod b/go.mod index a7ee54c..8712355 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( filippo.io/edwards25519 v1.1.0 github.com/aws/aws-sdk-go-v2 v0.17.0 github.com/code-payments/code-vm-indexer v1.2.0 - github.com/code-payments/ocp-protobuf-api v0.11.0 + github.com/code-payments/ocp-protobuf-api v0.12.0 github.com/emirpasic/gods v1.12.0 github.com/envoyproxy/protoc-gen-validate v1.2.1 github.com/golang/protobuf v1.5.4 diff --git a/go.sum b/go.sum index 1539f5a..920617c 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/code-payments/code-vm-indexer v1.2.0 h1:rSHpBMiT9BKgmKcXg/VIoi/h0t7jNxGx07Qz59m+6Q0= github.com/code-payments/code-vm-indexer v1.2.0/go.mod h1:vn91YN2qNqb+gGJeZe2+l+TNxVmEEiRHXXnIn2Y40h8= -github.com/code-payments/ocp-protobuf-api v0.11.0 h1:Zq0H3tg+bjTuXF9T6kRXEX8sGXu1NQ0szvUD1MdVs4Q= -github.com/code-payments/ocp-protobuf-api v0.11.0/go.mod h1:tw6BooY5a8l6CtSZnKOruyKII0W04n89pcM4BizrgG8= +github.com/code-payments/ocp-protobuf-api v0.12.0 h1:X5lo7ABDYxsiC/D3viFuNJUhTWKISZBg6MzAy2PP10Y= +github.com/code-payments/ocp-protobuf-api v0.12.0/go.mod h1:tw6BooY5a8l6CtSZnKOruyKII0W04n89pcM4BizrgG8= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6 h1:NmTXa/uVnDyp0TY5MKi197+3HWcnYWfnHGyaFthlnGw= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= diff --git a/ocp/currency/time.go b/ocp/currency/time.go deleted file mode 100644 index b209889..0000000 --- a/ocp/currency/time.go +++ /dev/null @@ -1,26 +0,0 @@ -package currency - -import ( - "time" -) - -const ( - exchangeRateUpdatesPerHour = 4 - timePerExchangeRateUpdate = time.Hour / exchangeRateUpdatesPerHour -) - -// GetLatestExchangeRateTime gets the latest time for fetching an exchange rate. -// By synchronizing on a time, we can eliminate the amount of perceived volatility -// over short time spans. -// -// Deprecated: Use real-time data and favour volatility -func GetLatestExchangeRateTime() time.Time { - // Standardize to concrete 15 minute intervals to reduce perceived volatility. - // Notably, don't fall exactly on the 15 minute interval, so we remove 1 second. - // The way our postgres DB query is setup, the start of UTC day is unlikely to - // generate results. - secondsInUpdateInterval := int64(timePerExchangeRateUpdate / time.Second) - queryTimeUnix := time.Now().Unix() - queryTimeUnix = queryTimeUnix - (queryTimeUnix % secondsInUpdateInterval) - 1 - return time.Unix(queryTimeUnix, 0) -} diff --git a/ocp/currency/validation.go b/ocp/currency/validation.go index 4a29b5c..070dd93 100644 --- a/ocp/currency/validation.go +++ b/ocp/currency/validation.go @@ -1,7 +1,6 @@ package currency import ( - "context" "crypto/ed25519" "math" "math/big" @@ -9,13 +8,10 @@ import ( currencypb "github.com/code-payments/ocp-protobuf-api/generated/go/currency/v1" transactionpb "github.com/code-payments/ocp-protobuf-api/generated/go/transaction/v1" - "go.uber.org/zap" currency_lib "github.com/code-payments/ocp-server/currency" "github.com/code-payments/ocp-server/ocp/auth" "github.com/code-payments/ocp-server/ocp/common" - ocp_data "github.com/code-payments/ocp-server/ocp/data" - "github.com/code-payments/ocp-server/ocp/data/currency" "github.com/code-payments/ocp-server/solana/currencycreator" ) @@ -236,216 +232,3 @@ func validateLaunchpadCurrencyVerifiedExchangeData(proto *transactionpb.Verified return true, "" } - -// ValidateLegacyClientExchangeData validates legacy proto exchange data provided by a client -func ValidateLegacyClientExchangeData(ctx context.Context, log *zap.Logger, data ocp_data.Provider, proto *transactionpb.ExchangeData) (bool, string, error) { - mint, err := common.GetBackwardsCompatMint(proto.Mint) - if err != nil { - return false, "", err - } - - if common.IsCoreMint(mint) { - return validateCoreMintClientExchangeData(ctx, log, data, proto) - } - return validateCurrencyLaunchpadClientExchangeData(ctx, log, data, proto) -} - -func validateCoreMintClientExchangeData(ctx context.Context, log *zap.Logger, data ocp_data.Provider, proto *transactionpb.ExchangeData) (bool, string, error) { - latestExchangeRateTime := GetLatestExchangeRateTime() - - coreMintQuarksPerUnit := common.GetMintQuarksPerUnit(common.CoreMintAccount) - - clientRate := big.NewFloat(proto.ExchangeRate).SetPrec(defaultPrecision) - clientNativeAmount := big.NewFloat(proto.NativeAmount).SetPrec(defaultPrecision) - clientQuarks := big.NewFloat(float64(proto.Quarks)).SetPrec(defaultPrecision) - - currencyDecimals := currency_lib.GetDecimals(currency_lib.Code(proto.Currency)) - one := big.NewFloat(1.0).SetPrec(defaultPrecision) - minTransferValue := new(big.Float).Quo(one, big.NewFloat(math.Pow10(currencyDecimals))) - - rateErrorThreshold := big.NewFloat(0.001).SetPrec(defaultPrecision) - nativeAmountErrorThreshold := new(big.Float).Quo(minTransferValue, big.NewFloat(2.0)) - - nativeAmountLowerBound := new(big.Float).Sub(clientNativeAmount, nativeAmountErrorThreshold) - if nativeAmountLowerBound.Cmp(nativeAmountErrorThreshold) < 0 { - nativeAmountLowerBound = nativeAmountErrorThreshold - } - nativeAmountUpperBound := new(big.Float).Add(clientNativeAmount, nativeAmountErrorThreshold) - quarksLowerBound := new(big.Float).Mul(new(big.Float).Quo(nativeAmountLowerBound, clientRate), big.NewFloat(float64(coreMintQuarksPerUnit))) - quarksUpperBound := new(big.Float).Mul(new(big.Float).Quo(nativeAmountUpperBound, clientRate), big.NewFloat(float64(coreMintQuarksPerUnit))) - - log = log.With( - zap.String("currency", proto.Currency), - zap.String("client_native_amount", clientNativeAmount.Text('f', 10)), - zap.String("client_exchange_rate", clientRate.Text('f', 10)), - zap.Uint64("client_quarks", proto.Quarks), - zap.String("min_transfer_value", minTransferValue.Text('f', 10)), - zap.String("native_amount_lower_bound", nativeAmountLowerBound.Text('f', 10)), - zap.String("native_amount_upper_bound", nativeAmountUpperBound.Text('f', 10)), - zap.String("quarks_lower_bound", quarksLowerBound.Text('f', 10)), - zap.String("quarks_upper_bound", quarksUpperBound.Text('f', 10)), - ) - - if clientNativeAmount.Cmp(nativeAmountErrorThreshold) < 0 { - log.Info("native amount is less than minimum transfer value error threshold") - return false, "native amount is less than minimum transfer value error threshold", nil - } - - // Find an exchange rate that the client could have fetched from a RPC call - // within a reasonable time in the past - var isClientRateValid bool - for i := range 2 { - exchangeRateTime := latestExchangeRateTime.Add(time.Duration(-i) * timePerExchangeRateUpdate) - - exchangeRateRecord, err := data.GetExchangeRate(ctx, currency_lib.Code(proto.Currency), exchangeRateTime) - if err == currency.ErrNotFound { - continue - } else if err != nil { - return false, "", err - } - actualRate := big.NewFloat(exchangeRateRecord.Rate) - - percentDiff := new(big.Float).Quo(new(big.Float).Abs(new(big.Float).Sub(clientRate, actualRate)), actualRate) - if percentDiff.Cmp(rateErrorThreshold) < 0 { - isClientRateValid = true - break - } - - log.With(zap.String("found_rate", actualRate.Text('f', 10))).Info("exchange rate doesn't match") - } - - if !isClientRateValid { - log.Info("fiat exchange rate is stale or invalid") - return false, "fiat exchange rate is stale or invalid", nil - } - - // Validate that the native amount within half of the minimum transfer value - if clientQuarks.Cmp(quarksLowerBound) < 0 || clientQuarks.Cmp(quarksUpperBound) > 0 { - log.Info("native amount is outside error threshold") - return false, "payment native amount and quark value mismatch", nil - } - - return true, "", nil -} - -func validateCurrencyLaunchpadClientExchangeData(ctx context.Context, log *zap.Logger, data ocp_data.Provider, proto *transactionpb.ExchangeData) (bool, string, error) { - mintAccount, err := common.GetBackwardsCompatMint(proto.Mint) - if err != nil { - return false, "", err - } - - coreMintQuarksPerUnit := common.GetMintQuarksPerUnit(common.CoreMintAccount) - otherMintQuarksPerUnit := common.GetMintQuarksPerUnit(mintAccount) - - clientQuarks := big.NewFloat(float64(proto.Quarks)).SetPrec(defaultPrecision) - clientTokenUnits := new(big.Float).Quo( - clientQuarks, - big.NewFloat(float64(otherMintQuarksPerUnit)).SetPrec(defaultPrecision), - ) - clientRate := big.NewFloat(proto.ExchangeRate).SetPrec(defaultPrecision) - clientNativeAmount := big.NewFloat(proto.NativeAmount).SetPrec(defaultPrecision) - - currencyDecimals := currency_lib.GetDecimals(currency_lib.Code(proto.Currency)) - one := big.NewFloat(1.0).SetPrec(defaultPrecision) - minTransferValue := new(big.Float).Quo(one, big.NewFloat(math.Pow10(currencyDecimals))) - - rateErrorThreshold := big.NewFloat(0.001).SetPrec(defaultPrecision) - nativeAmountErrorThreshold := new(big.Float).Quo(minTransferValue, big.NewFloat(2.0)) - - nativeAmountLowerBound := new(big.Float).Sub(clientNativeAmount, nativeAmountErrorThreshold) - if nativeAmountLowerBound.Cmp(nativeAmountErrorThreshold) < 0 { - nativeAmountLowerBound = nativeAmountErrorThreshold - } - nativeAmountUpperBound := new(big.Float).Add(clientNativeAmount, nativeAmountErrorThreshold) - - log = log.With( - zap.String("currency", proto.Currency), - zap.String("client_native_amount", clientNativeAmount.Text('f', 10)), - zap.String("client_exchange_rate", clientRate.Text('f', 10)), - zap.String("client_token_units", clientTokenUnits.Text('f', 10)), - zap.Uint64("client_quarks", proto.Quarks), - zap.String("min_transfer_value", minTransferValue.Text('f', 10)), - zap.String("native_amount_lower_bound", nativeAmountLowerBound.Text('f', 10)), - zap.String("native_amount_upper_bound", nativeAmountUpperBound.Text('f', 10)), - zap.String("mint", mintAccount.PublicKey().ToBase58()), - ) - - if clientNativeAmount.Cmp(nativeAmountErrorThreshold) < 0 { - log.Info("native amount is less than minimum transfer value error threshold") - return false, "native amount is less than minimum transfer value error threshold", nil - } - - latestExchangeRateTime := GetLatestExchangeRateTime() - for i := range 2 { - exchangeRateTime := latestExchangeRateTime.Add(time.Duration(-i) * timePerExchangeRateUpdate) - - reserveRecord, err := data.GetCurrencyReserveAtTime(ctx, mintAccount.PublicKey().ToBase58(), exchangeRateTime) - if err == currency.ErrNotFound { - continue - } else if err != nil { - return false, "", err - } - - usdExchangeRateRecord, err := data.GetExchangeRate(ctx, currency_lib.USD, exchangeRateTime) - if err == currency.ErrNotFound { - continue - } else if err != nil { - return false, "", err - } - usdRate := big.NewFloat(usdExchangeRateRecord.Rate).SetPrec(defaultPrecision) - - var otherExchangeRateRecord *currency.ExchangeRateRecord - if proto.Currency == string(currency_lib.USD) { - otherExchangeRateRecord = usdExchangeRateRecord - } else { - otherExchangeRateRecord, err = data.GetExchangeRate(ctx, currency_lib.Code(proto.Currency), exchangeRateTime) - if err == currency.ErrNotFound { - continue - } else if err != nil { - return false, "", err - } - } - otherRate := big.NewFloat(otherExchangeRateRecord.Rate).SetPrec(defaultPrecision) - - // How much core mint would be received for a sell against the currency creator program? - coreMintSellValueInQuarks, _ := currencycreator.EstimateSell(¤cycreator.EstimateSellArgs{ - CurrentSupplyInQuarks: reserveRecord.SupplyFromBonding, - SellAmountInQuarks: proto.Quarks, - ValueMintDecimals: uint8(common.CoreMintDecimals), - SellFeeBps: 0, - }) - - // Given the sell value, does it align with the native amount in the target currency - // within half a minimum transfer unit? - coreMintSellValueInUnits := new(big.Float).Quo( - big.NewFloat(float64(coreMintSellValueInQuarks)).SetPrec(defaultPrecision), - big.NewFloat(float64(coreMintQuarksPerUnit)).SetPrec(defaultPrecision), - ) - potentialNativeAmount := new(big.Float).Mul(new(big.Float).Quo(otherRate, usdRate), coreMintSellValueInUnits) - - log := log.With( - zap.String("core_mint_sell_value", coreMintSellValueInUnits.Text('f', 10)), - zap.String("potential_native_amount", potentialNativeAmount.Text('f', 10)), - zap.String("found_usd_rate", usdRate.Text('f', 10)), - zap.String("found_other_rate", otherRate.Text('f', 10)), - ) - - if potentialNativeAmount.Cmp(nativeAmountLowerBound) < 0 || potentialNativeAmount.Cmp(nativeAmountUpperBound) > 0 { - log.Info("native amount is outside error threshold") - continue - } - - // For the valid native amount, is the exchange rate calculated correctly? - expectedRate := new(big.Float).Quo(clientNativeAmount, clientTokenUnits) - percentDiff := new(big.Float).Quo(new(big.Float).Abs(new(big.Float).Sub(clientRate, expectedRate)), expectedRate) - log = log.With(zap.String("potential_exchange_rate", expectedRate.Text('f', 10))) - if percentDiff.Cmp(rateErrorThreshold) > 0 { - log.Info("exchange rate is outside error threshold") - continue - } - - return true, "", nil - } - - return false, "fiat exchange data is stale or invalid", nil -} diff --git a/ocp/rpc/currency/server.go b/ocp/rpc/currency/server.go index d081a87..b6a26b0 100644 --- a/ocp/rpc/currency/server.go +++ b/ocp/rpc/currency/server.go @@ -7,7 +7,6 @@ import ( "time" "github.com/google/uuid" - "github.com/pkg/errors" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -23,7 +22,6 @@ import ( "github.com/code-payments/ocp-server/grpc/client" "github.com/code-payments/ocp-server/ocp/common" "github.com/code-payments/ocp-server/ocp/config" - currency_util "github.com/code-payments/ocp-server/ocp/currency" ocp_data "github.com/code-payments/ocp-server/ocp/data" "github.com/code-payments/ocp-server/ocp/data/currency" "github.com/code-payments/ocp-server/protoutil" @@ -69,47 +67,6 @@ func NewCurrencyServer( } } -func (s *currencyServer) GetAllRates(ctx context.Context, req *currencypb.GetAllRatesRequest) (resp *currencypb.GetAllRatesResponse, err error) { - log := s.log.With(zap.String("method", "GetAllRates")) - log = client.InjectLoggingMetadata(ctx, log) - - var record *currency.MultiRateRecord - if req.Timestamp != nil && req.Timestamp.AsTime().Before(time.Now().Add(-15*time.Minute)) { - record, err = s.loadExchangeRatesForTime(ctx, req.Timestamp.AsTime()) - } else if req.Timestamp == nil || req.Timestamp.AsTime().Sub(time.Now()) < time.Hour { - record, err = s.loadExchangeRatesLatest(ctx) - } else { - return nil, status.Error(codes.InvalidArgument, "timestamp too far in the future") - } - - if err != nil { - log.With(zap.Error(err)).Warn("failed to load latest rate") - return nil, status.Error(codes.Internal, err.Error()) - } - - protoTime := timestamppb.New(record.Time) - return ¤cypb.GetAllRatesResponse{ - AsOf: protoTime, - Rates: record.Rates, - }, nil -} - -func (s *currencyServer) loadExchangeRatesForTime(ctx context.Context, t time.Time) (*currency.MultiRateRecord, error) { - record, err := s.data.GetAllExchangeRates(ctx, t) - if err != nil { - return nil, errors.Wrap(err, "failed to get price record by date") - } - return record, nil -} - -func (s *currencyServer) loadExchangeRatesLatest(ctx context.Context) (*currency.MultiRateRecord, error) { - latest, err := s.data.GetAllExchangeRates(ctx, currency_util.GetLatestExchangeRateTime()) - if err != nil { - return nil, errors.Wrap(err, "failed to get latest price record") - } - return latest, nil -} - func (s *currencyServer) GetMints(ctx context.Context, req *currencypb.GetMintsRequest) (*currencypb.GetMintsResponse, error) { log := s.log.With(zap.String("method", "GetMints")) log = client.InjectLoggingMetadata(ctx, log) @@ -160,9 +117,15 @@ func (s *currencyServer) GetMints(ctx context.Context, req *currencypb.GetMintsR return nil, status.Error(codes.Internal, "") } - reserveRecord, err := s.data.GetCurrencyReserveAtTime(ctx, mintAccount.PublicKey().ToBase58(), currency_util.GetLatestExchangeRateTime()) + err = s.liveMintStateWorker.waitForData(ctx) + if err != nil { + log.With(zap.Error(err)).Warn("failed to wait for live mint data") + return nil, status.Error(codes.Internal, "") + } + + liveReserveState, err := s.liveMintStateWorker.getReserveState(mintAccount) if err != nil { - log.With(zap.Error(err)).Warn("failed to load currency reserve record") + log.With(zap.Error(err)).Warn("failed to get live mint reserve state") return nil, status.Error(codes.Internal, "") } @@ -223,7 +186,7 @@ func (s *currencyServer) GetMints(ctx context.Context, req *currencypb.GetMintsR Authority: currencyAuthorityAccount.ToProto(), MintVault: mintVaultAccount.ToProto(), CoreMintVault: coreMintVaultAccount.ToProto(), - SupplyFromBonding: reserveRecord.SupplyFromBonding, + SupplyFromBonding: liveReserveState.SupplyFromBonding, SellFeeBps: uint32(metadataRecord.SellFeeBps), }, CreatedAt: timestamppb.New(metadataRecord.CreatedAt), diff --git a/ocp/rpc/currency/worker.go b/ocp/rpc/currency/worker.go index 23e1079..44c8b96 100644 --- a/ocp/rpc/currency/worker.go +++ b/ocp/rpc/currency/worker.go @@ -1,6 +1,7 @@ package currency import ( + "bytes" "context" "crypto/ed25519" "sync" @@ -11,6 +12,7 @@ import ( commonpb "github.com/code-payments/ocp-protobuf-api/generated/go/common/v1" currencypb "github.com/code-payments/ocp-protobuf-api/generated/go/currency/v1" + "github.com/pkg/errors" "github.com/code-payments/ocp-server/ocp/auth" "github.com/code-payments/ocp-server/ocp/common" @@ -129,7 +131,7 @@ func (m *liveMintStateWorker) unregisterStream(id string) { } } -// WaitForData blocks until initial data is loaded or context is cancelled +// waitForData blocks until initial data is loaded or context is cancelled func (m *liveMintStateWorker) waitForData(ctx context.Context) error { select { case <-m.dataReady: @@ -139,7 +141,7 @@ func (m *liveMintStateWorker) waitForData(ctx context.Context) error { } } -// GetExchangeRates returns the current pre-signed exchange rate data +// getExchangeRates returns the current pre-signed exchange rate data func (m *liveMintStateWorker) getExchangeRates() *liveExchangeRateData { m.stateMu.RLock() defer m.stateMu.RUnlock() @@ -147,7 +149,7 @@ func (m *liveMintStateWorker) getExchangeRates() *liveExchangeRateData { return m.exchangeRates } -// GetReserveStates returns all current pre-signed launchpad currency reserve states +// getReserveStates returns all current pre-signed launchpad currency reserve states func (m *liveMintStateWorker) getReserveStates() []*liveReserveStateData { m.stateMu.RLock() defer m.stateMu.RUnlock() @@ -159,6 +161,19 @@ func (m *liveMintStateWorker) getReserveStates() []*liveReserveStateData { return result } +// getReserveState returns a current pre-signed launchpad currency reserve state for a mint +func (m *liveMintStateWorker) getReserveState(mint *common.Account) (*liveReserveStateData, error) { + m.stateMu.RLock() + defer m.stateMu.RUnlock() + + for _, data := range m.launchpadReserves { + if bytes.Equal(mint.PublicKey().ToBytes(), data.Mint.PublicKey().ToBytes()) { + return data, nil + } + } + return nil, errors.New("not found") +} + func (m *liveMintStateWorker) tryMarkDataReady() { m.initMu.Lock() defer m.initMu.Unlock() diff --git a/ocp/rpc/messaging/testutil.go b/ocp/rpc/messaging/testutil.go index 84c126a..405e7b5 100644 --- a/ocp/rpc/messaging/testutil.go +++ b/ocp/rpc/messaging/testutil.go @@ -22,7 +22,6 @@ import ( "github.com/code-payments/ocp-server/ocp/auth" "github.com/code-payments/ocp-server/ocp/common" - currency_util "github.com/code-payments/ocp-server/ocp/currency" ocp_data "github.com/code-payments/ocp-server/ocp/data" "github.com/code-payments/ocp-server/ocp/data/account" "github.com/code-payments/ocp-server/ocp/data/currency" @@ -70,7 +69,7 @@ func setup(t *testing.T, enableMultiServer bool) (env testEnv, cleanup func()) { subsidizer := testutil.SetupRandomSubsidizer(t, data) require.NoError(t, data.ImportExchangeRates(context.Background(), ¤cy.MultiRateRecord{ - Time: currency_util.GetLatestExchangeRateTime(), + Time: time.Now(), Rates: map[string]float64{ "usd": 0.1, }, diff --git a/ocp/rpc/transaction/airdrop.go b/ocp/rpc/transaction/airdrop.go index d9c9224..e84b6da 100644 --- a/ocp/rpc/transaction/airdrop.go +++ b/ocp/rpc/transaction/airdrop.go @@ -205,7 +205,7 @@ func (s *transactionServer) airdrop(ctx context.Context, intentId string, owner additionalQuarks = 1 } - exchangeRateRecord, err := s.data.GetExchangeRate(ctx, currencyCode, currency_util.GetLatestExchangeRateTime()) + exchangeRateRecord, err := s.data.GetExchangeRate(ctx, currencyCode, time.Now()) if err != nil { log.With(zap.Error(err)).Warn("failure getting other rate") return nil, err diff --git a/ocp/rpc/transaction/intent_handler.go b/ocp/rpc/transaction/intent_handler.go index 7fab4f2..7b840ba 100644 --- a/ocp/rpc/transaction/intent_handler.go +++ b/ocp/rpc/transaction/intent_handler.go @@ -415,15 +415,6 @@ func (h *SendPublicPaymentIntentHandler) PopulateMetadata(ctx context.Context, i if err != nil { return err } - case *transactionpb.SendPublicPaymentMetadata_ServerExchangeData: // todo: deprecate this flow - currencyCode = currency_lib.Code(typed.ServerExchangeData.Currency) - nativeAmount = typed.ServerExchangeData.NativeAmount - exchangeRate = typed.ServerExchangeData.ExchangeRate - quarks = typed.ServerExchangeData.Quarks - usdMarketValue, err = currency_util.CalculateUsdMarketValueFromTokenAmount(ctx, h.data, mint, quarks, currency_util.GetLatestExchangeRateTime()) - if err != nil { - return err - } default: return NewIntentDeniedError("client exchange data not provided") } @@ -619,10 +610,8 @@ func (h *SendPublicPaymentIntentHandler) AllowCreation(ctx context.Context, inte if err := validateExchangeDataWithinIntent(typedMetadata.Mint, typed.ClientExchangeData); err != nil { return err } - case *transactionpb.SendPublicPaymentMetadata_ServerExchangeData: - if err := validateLegacyExchangeDataWithinIntent(ctx, h.log, h.data, typedMetadata.Mint, typed.ServerExchangeData); err != nil { - return err - } + default: + return NewIntentDeniedError("client exchange data not provided") } // @@ -688,8 +677,8 @@ func (h *SendPublicPaymentIntentHandler) validateActions( switch typed := metadata.ExchangeData.(type) { case *transactionpb.SendPublicPaymentMetadata_ClientExchangeData: quarks = typed.ClientExchangeData.Quarks - case *transactionpb.SendPublicPaymentMetadata_ServerExchangeData: - quarks = typed.ServerExchangeData.Quarks + default: + return NewIntentDeniedError("client exchange data not provided") } // @@ -1837,33 +1826,6 @@ func validateExchangeDataWithinIntent(intentMint *commonpb.SolanaAccountId, prot return nil } -func validateLegacyExchangeDataWithinIntent(ctx context.Context, log *zap.Logger, data ocp_data.Provider, intentMint *commonpb.SolanaAccountId, proto *transactionpb.ExchangeData) error { - intentMintAccount, err := common.GetBackwardsCompatMint(intentMint) - if err != nil { - return err - } - - exchangeMintAccount, err := common.GetBackwardsCompatMint(proto.Mint) - if err != nil { - return err - } - - if !bytes.Equal(intentMintAccount.PublicKey().ToBytes(), exchangeMintAccount.PublicKey().ToBytes()) { - return NewIntentValidationErrorf("expected exchange data mint to be %s", intentMintAccount.PublicKey().ToBase58()) - } - - isValid, message, err := currency_util.ValidateLegacyClientExchangeData(ctx, log, data, proto) - if err != nil { - return err - } else if !isValid { - if strings.Contains(message, "stale") { - return NewStaleStateError(message) - } - return NewIntentValidationError(message) - } - return nil -} - func validateFeePayments( ctx context.Context, conf *conf, diff --git a/ocp/rpc/transaction/limits.go b/ocp/rpc/transaction/limits.go index e1bc64f..71a1fb3 100644 --- a/ocp/rpc/transaction/limits.go +++ b/ocp/rpc/transaction/limits.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "time" "go.uber.org/zap" "google.golang.org/grpc/codes" @@ -34,7 +35,7 @@ func (s *transactionServer) GetLimits(ctx context.Context, req *transactionpb.Ge return nil, err } - multiRateRecord, err := s.data.GetAllExchangeRates(ctx, currency_util.GetLatestExchangeRateTime()) + multiRateRecord, err := s.data.GetAllExchangeRates(ctx, time.Now()) if err != nil { log.With(zap.Error(err)).Warn("failure getting current exchange rates") return nil, status.Error(codes.Internal, "")