store: refuse a card difference under 50 cents

This commit is contained in:
shum committed 2026-10-22 15:53:23 +00:00
1 parent 24d23d3fcd
commit fdab726490
2 files changed
+21 -1

No files matched your search

@@ -30,7 +30,7 @@ import Data.Word (Word32, Word64)
import Network.HTTP.Types (status200, status409, status503)
import Network.Wai (Request, Response, ResponseReceived)
import Simplex.Chat.Badges.Code (NameCode (..), parseNameCode)
import Simplex.Chat.PaymentService.Types (CurrencyAmount (..), InvoiceId (..), InvoiceStatus (..), ServicePaymentMethod)
import Simplex.Chat.PaymentService.Types (CurrencyAmount (..), InvoiceId (..), InvoiceStatus (..), ServicePaymentMethod (..))
import Simplex.Messaging.Agent.Store.Common (withTransaction)
import qualified Simplex.Messaging.Agent.Store.DB as DB
import Simplex.Messaging.Crypto.Secp256k1 (RecoverableSignature)
@@ -268,10 +268,16 @@ spendHandler env@OrdersEnv {oeStore, oeConfig, oeContracts, oeTurns, oeNow} cfg
placeOrder env order (maybeToList holder) (coveredOrderInsert spend new) >>= \case
Left refusal -> refuse refusal
Right closed -> pure Answer {aResponse = registrationAnswer rid, aAfter = announceClosed env providers waiters closed}
Just (SPMCard _)
| spPrice - spBalance < minCardChargeCents -> refuse ORBadRequest
Just method ->
createAtProvider env cfg providers waiters what $
InvoicedOrder {ivRequest = order, ivHolders = maybeToList holder, ivMethod = method, ivPrice = spPrice, ivAmount = fromIntegral (spPrice - spBalance), ivInsert = differenceOrderInsert spend}
-- | Stripe refuses a USD charge under 50 cents, so the page offers only crypto for a smaller difference.
minCardChargeCents :: Int
minCardChargeCents = 50
-- | Every format check, the method present exactly for a difference, then the length's range.
parseSpend :: RegistrationId -> J.Object -> Either OrderRefusal ((OrderFields, Word64, RecoverableSignature), Spend)
parseSpend spSource o = do
@@ -69,6 +69,7 @@ namesSpendTests = describe "StoreService names: spend" $ do
it "refuses another signer and a stale timestamp, and answers an unknown order 404" testSignerAndId
it "answers name_taken, catalog_changed, name_check_unavailable, provider_unavailable and order_exists, spending nothing" testOrderChecks
it "runs its checks in the contract's order" testCheckOrder
it "refuses a card difference below the card minimum after the price check, accepting it by crypto and at the minimum" testCardMinimum
it "refuses sealed missing or over 11095 characters and a body over 16384 bytes, accepting the longest" testSpendSizes
it "counts spends against the create limit" testSpendLimit
describe "holders" $ do
@@ -388,6 +389,19 @@ testCheckOrder = withSpend $ \ctx@Ctx {cNode = node, cStub} -> do
spend ctx src (covered 31000) {sbOrder = aliceOrder {oCommitment = commitmentOf 3}} `shouldReturn` refusedWith 409 "order_exists"
amountOf ctx src `shouldReturn` Just 20000
testCardMinimum :: IO ()
testCardMinimum = withSpend $ \ctx -> do
small <- sourceOf ctx "small" 9951
spend ctx small (difference 9951) {sbOrder = aliceOrder {oPrice = 9990}, sbMethod = Just "card"} `shouldReturn` (409, Just $ KM.fromList [("error", "catalog_changed"), ("price", J.Number 10000)])
spend ctx small (difference 9951) {sbMethod = Just "card"} `shouldReturn` refusedWith 400 "bad_request"
stubCalls (cStub ctx) `shouldReturn` []
amountOf ctx small `shouldReturn` Just 9951
fst <$> spend ctx small (difference 9951) `shouldReturn` 200
least <- sourceOf ctx "least" 19950
fst <$> spend ctx least (dynamis 19950 (Just "card")) `shouldReturn` 200
calls <- stubCalls (cStub ctx)
[odAmount d | StubCreate _ d <- calls] `shouldBe` [CurrencyAmount 49, CurrencyAmount 50]
testSpendSizes :: IO ()
testSpendSizes = withSpend $ \ctx -> do
src <- sourceOf ctx "src" 15000