Skip to content

Commit 8b00772

Browse files
authored
Merge pull request #1190 from peanutprotocol/feat/manteca-qr
[TASK-12883] Add manteca QR payments
2 parents 0cdd610 + 4f53108 commit 8b00772

32 files changed

Lines changed: 803 additions & 193 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { generateMetadata } from '@/app/metadata'
2+
import PageContainer from '@/components/0_Bruddle/PageContainer'
3+
import React from 'react'
4+
5+
export const metadata = generateMetadata({
6+
title: 'QR Payment | Peanut',
7+
description: 'Use Peanut to pay Argentinian MercadoPago and Brazilian Pix QR codes',
8+
})
9+
10+
export default function QRPayLayout({ children }: { children: React.ReactNode }) {
11+
return <PageContainer>{children}</PageContainer>
12+
}

src/app/(mobile-ui)/qr-pay/page.tsx

Lines changed: 375 additions & 0 deletions
Large diffs are not rendered by default.

src/app/[...recipient]/client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ export default function PaymentPage({ recipient, flow = 'request_pay' }: Props)
497497
? {
498498
code: currencyCode,
499499
symbol: currencySymbol!,
500-
price: currencyPrice!,
500+
price: currencyPrice!.buy,
501501
}
502502
: undefined
503503
}

src/app/actions/currency.ts

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,45 @@
11
'use server'
22
import { unstable_cache } from 'next/cache'
3-
import { fetchWithSentry } from '@/utils'
43
import { getExchangeRate } from './exchange-rate'
54
import { AccountType } from '@/interfaces'
5+
import { mantecaApi } from '@/services/manteca'
6+
7+
const MANTECA_CURRENCIES = ['ARS', 'BRL', 'COP', 'CRC', 'PUSD', 'GTQ', 'PHP', 'BOB']
68

79
export const getCurrencyPrice = unstable_cache(
8-
async (currencyCode: string): Promise<number> => {
9-
let price: number
10+
async (currencyCode: string): Promise<{ buy: number; sell: number }> => {
11+
let buy: number
12+
let sell: number
1013
currencyCode = currencyCode.toUpperCase()
11-
switch (currencyCode) {
12-
case 'USD':
13-
price = 1
14-
break
15-
case 'EUR':
16-
case 'MXN':
17-
{
18-
let accountType: AccountType
19-
if (currencyCode === 'EUR') {
20-
accountType = AccountType.IBAN
21-
} else if (currencyCode === 'MXN') {
22-
accountType = AccountType.CLABE
23-
} else {
24-
throw new Error('Invalid currency code')
25-
}
26-
const { data, error } = await getExchangeRate(accountType)
27-
if (error) {
28-
throw new Error('Failed to fetch exchange rate from bridge')
29-
}
30-
if (!data) {
31-
throw new Error('No data returned from exchange rate API')
32-
}
33-
price = parseFloat(data.buy_rate)
34-
}
35-
break
36-
case 'ARS':
37-
{
38-
const response = await fetchWithSentry('https://dolarapi.com/v1/dolares/cripto')
39-
const data = await response.json()
40-
41-
if (!data.compra || !data.venta) {
42-
throw new Error('Invalid response from dolarapi')
43-
}
44-
45-
// Average between buy and sell price
46-
price = (data.compra + data.venta) / 2
47-
}
48-
break
49-
default:
50-
throw new Error('Unsupported currency')
14+
if (currencyCode === 'USD') {
15+
buy = 1
16+
sell = 1
17+
} else if (['EUR', 'MXN'].includes(currencyCode)) {
18+
let accountType: AccountType
19+
if (currencyCode === 'EUR') {
20+
accountType = AccountType.IBAN
21+
} else if (currencyCode === 'MXN') {
22+
accountType = AccountType.CLABE
23+
} else {
24+
throw new Error('Invalid currency code')
25+
}
26+
const { data, error } = await getExchangeRate(accountType)
27+
if (error) {
28+
throw new Error('Failed to fetch exchange rate from bridge')
29+
}
30+
if (!data) {
31+
throw new Error('No data returned from exchange rate API')
32+
}
33+
buy = parseFloat(data.buy_rate)
34+
sell = parseFloat(data.sell_rate)
35+
} else if (MANTECA_CURRENCIES.includes(currencyCode)) {
36+
const response = await mantecaApi.getPrices({ asset: 'USDC', against: currencyCode })
37+
buy = Number(response.effectiveBuy)
38+
sell = Number(response.effectiveSell)
39+
} else {
40+
throw new Error('Invalid currency code')
5141
}
52-
return price
42+
return { buy, sell }
5343
},
5444
['getCurrencyPrice'],
5545
{

src/app/actions/onramp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export async function createOnrampForGuest(
7878
try {
7979
const { currency, paymentRail } = getCurrencyConfig(params.country.id, 'onramp')
8080
const price = await getCurrencyPrice(currency)
81-
const amount = (Number(params.amount) * price).toFixed(2)
81+
const amount = (Number(params.amount) * price.buy).toFixed(2)
8282

8383
const response = await fetchWithSentry(`${apiUrl}/bridge/onramp/create-for-guest`, {
8484
method: 'POST',

src/assets/payment-apps/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export { default as GOOGLE_PAY } from './google-pay.svg'
33
export { default as MERCADO_PAGO } from './mercado-pago.svg'
44
export { default as PAYPAL } from './paypal.svg'
55
export { default as SATISPAY } from './satispay.svg'
6+
export { default as PIX } from './pix.svg'
67

src/assets/payment-apps/mercado-pago.svg

Lines changed: 1 addition & 8 deletions
Loading

src/assets/payment-apps/pix.svg

Lines changed: 1 addition & 0 deletions
Loading

src/components/0_Bruddle/Card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const Card = ({ children, className, shadowSize, color = 'primary', ...props }:
2929
<div
3030
// Tailwind merge makes sure classes added through className by component caller are merged and overrides the default classes
3131
className={twMerge(
32-
`flex flex-col border border-n-1 bg-white dark:border-white dark:bg-n-1`,
32+
`flex flex-col rounded-sm border border-n-1 bg-white dark:border-white dark:bg-n-1`,
3333
shadowClass,
3434
className
3535
)}

src/components/AddMoney/components/InputAmountStep.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const InputAmountStep = ({
5353
? {
5454
code: currencyData.code!,
5555
symbol: currencyData.symbol!,
56-
price: currencyData.price!,
56+
price: currencyData.price!.buy,
5757
}
5858
: undefined
5959
}

0 commit comments

Comments
 (0)