Skip to content

Commit

Permalink
Merge branch 'polygon-prototype-staging' into improve-feedback-on-login
Browse files Browse the repository at this point in the history
  • Loading branch information
gianfra-t committed Jan 21, 2025
2 parents c80dbdf + a20a037 commit c18b9db
Show file tree
Hide file tree
Showing 23 changed files with 314 additions and 73 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

---

PendulumPay is a gateway for cross-border payments. It is built on top of the Pendulum blockchain.
Vortex is a gateway for cross-border payments. It is built on top of the Pendulum blockchain.

## Run

Expand Down
2 changes: 2 additions & 0 deletions signer-service/src/api/routes/v1/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,6 @@ router.use('/rating', ratingRoutes);
*/
router.use('/siwe', siweRoutes);

router.use('/ip', (request, response) => response.send(request.ip));

module.exports = router;
14 changes: 13 additions & 1 deletion signer-service/src/config/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,19 @@ app.use(

// enable rate limiting
// Set number of expected proxies
app.set('trust proxy', rateLimitNumberOfProxies);
app.set('trust proxy', true);

app.use((req, res, next) => {
console.log({
'Raw Socket IP': req.socket.remoteAddress,
'Express req.ip': req.ip,
'X-Forwarded-For': req.headers['x-forwarded-for'],
'X-Real-IP': req.headers['x-real-ip'],
'Trust Proxy Setting': app.get('trust proxy'),
});
next();
});

// Define rate limiter
const limiter = rateLimit({
windowMs: rateLimitWindowMinutes * 60 * 1000,
Expand Down
7 changes: 6 additions & 1 deletion src/assets/payments/sepa.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/wallet-bifold-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 0 additions & 7 deletions src/assets/wallet.svg

This file was deleted.

2 changes: 1 addition & 1 deletion src/components/FeeCollapse/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const FeeCollapse: FC<CollapseProps> = ({ toAmount = Big(0), toToken, exc
<p>Details</p>
</div>
</div>
<div className="collapse-content">
<div className="text-[15px] collapse-content">
<div className="flex justify-between mt-2 ">
<p>Your quote ({exchangeRate})</p>
<div className="flex">
Expand Down
8 changes: 2 additions & 6 deletions src/components/Navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ const MobileMenuList: FC<MobileMenuListProps> = ({ showMenu, closeMenu }) => (
const Links = () => (
<ul className="lg:flex lg:items-center lg:justify-around">
{links.map((link) => (
<li key={link.title} className="mb-9 lg:mb-0">
<li key={link.title} className="mr-4 mb-9 lg:mb-0">
<a
href={link.href}
target={link.href.startsWith('https') ? '_blank' : ''}
rel={link.href.startsWith('https') ? 'noreferrer' : ''}
className="px-3 text-lg font-thin text-white lg:px-4 xl:px-7 hover:text-amber-500 hover:underline"
className="px-3 text-lg font-thin text-white hover:text-amber-500 hover:underline lg:px-0"
>
{link.title}
</a>
Expand All @@ -103,10 +103,6 @@ export const Navbar = () => {
return (
<header className="flex items-center justify-between px-4 py-4 bg-blue-950 md:py-5 md:px-10">
<div className="flex">
<a href="https://www.vortexfinance.co/" target="_blank" rel="noreferrer" className="flex text-slate-400">
<img src={whiteLogo} alt="Vortex Logo" className="mr-1 max-h-6 lg:max-h-8 xl:max-h-12" />
Alpha
</a>
<nav className="hidden m-auto lg:block">
<Links />
</nav>
Expand Down
2 changes: 1 addition & 1 deletion src/components/NetworkSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface NetworkButtonProps {

const NetworkButton = ({ selectedNetwork, isOpen, onClick, disabled }: NetworkButtonProps) => (
<motion.button
className={`flex items-center gap-2 px-2 sm:px-4 py-2 rounded-full bg-base-100 ${
className={`flex items-center gap-2 px-2 sm:px-4 py-3 rounded-full bg-base-100 ${
disabled ? 'opacity-50 cursor-not-allowed' : ''
}`}
onClick={onClick}
Expand Down
56 changes: 50 additions & 6 deletions src/components/PoweredBy/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,56 @@
import satoshipayLogo from '../../assets/logo/satoshipay.svg';
import MASTERCARD from '../../assets/payments/mastercard.svg';
import SEPA from '../../assets/payments/sepa.svg';
import VISA from '../../assets/payments/visa.svg';
import vortexLogo from '../../assets/logo/blue.svg';
interface ImageProps {
src: string;
alt: string;
additionalClass?: string;
comingSoon?: boolean;
}

const paymentImages = [
{ src: SEPA, alt: 'SEPA logo', additionalClass: 'h-6' },
{ src: MASTERCARD, alt: 'Mastercard logo', comingSoon: true },
{ src: VISA, alt: 'Visa logo', comingSoon: true },
];

const Image = ({ src, alt, comingSoon, additionalClass }: ImageProps) => (
<div className="relative">
<img src={src} alt={alt} className={`h-[18px] ${additionalClass}`} />
{comingSoon && (
<div className="absolute bottom-[-10px] right-[-8px] text-[8px] w-12 text-blue-700">Coming soon</div>
)}
</div>
);

const ImageList = ({ images }: { images: ImageProps[] }) => (
<div className="flex flex-wrap items-start justify-center gap-x-6">
{images.map((img) => (
<Image key={img.alt} {...img} />
))}
</div>
);

export function PoweredBy() {
return (
<div className="flex items-center justify-center">
<p className="mr-1 text-sm text-gray-500">Powered by</p>
<a href="https://satoshipay.io" target="_blank" rel="noopener noreferrer" className="transition hover:opacity-80">
<img src={satoshipayLogo} alt="Satoshipay" />
</a>
</div>
<section>
<ImageList images={paymentImages} />
<div className="flex items-center justify-center mt-3">
<p className="mr-1 text-sm text-gray-500">Powered by</p>
<Image src={vortexLogo} alt="Satoshipay" />
</div>
<p className="flex items-center justify-center mt-3 mr-1 text-sm text-gray-500">
<a
href="https://satoshipay.io"
target="_blank"
rel="noopener noreferrer"
className="flex gap-1 text-xs transition hover:opacity-80"
>
A <img src={satoshipayLogo} alt="Satoshipay" /> Company
</a>
</p>
</section>
);
}
39 changes: 23 additions & 16 deletions src/components/TrustedBy/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import POLKADOT from '../../assets/trustedby/polkadot.svg';
import STELLAR from '../../assets/trustedby/stellar.svg';
import NABLA from '../../assets/trustedby/nabla.svg';
import WEB3 from '../../assets/trustedby/web3.svg';

import MASTERCARD from '../../assets/payments/mastercard.svg';
import SEPA from '../../assets/payments/sepa.svg';
import VISA from '../../assets/payments/visa.svg';
import { motion } from 'framer-motion';

interface ImageProps {
src: string;
Expand All @@ -16,15 +13,32 @@ interface ImageProps {

const Image = ({ src, alt, comingSoon }: ImageProps) => (
<div className="relative flex items-center pt-4">
<img src={src} alt={alt} className="max-w-[150px] h-[48px]" />
<motion.img
src={src}
alt={alt}
className="max-w-[150px] h-[48px]"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
whileHover={{ scale: 1.02 }}
transition={{ duration: 0.2 }}
/>
{comingSoon && <div className="absolute top-0 right-0 text-xs text-right text-blue-700">Coming soon</div>}
</div>
);

const ImageList = ({ images }: { images: ImageProps[] }) => (
<div className="flex flex-wrap items-center justify-center gap-y-4 gap-x-12">
{images.map((img) => (
<Image key={img.alt} {...img} />
{images.map((img, index) => (
<motion.div
key={img.alt}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Image {...img} />
</motion.div>
))}
</div>
);
Expand All @@ -38,18 +52,11 @@ export const TrustedBy = () => {
{ src: WEB3, alt: 'Web3 Foundation logo' },
];

const paymentImages = [
{ src: SEPA, alt: 'SEPA logo' },
{ src: MASTERCARD, alt: 'Mastercard logo', comingSoon: true },
{ src: VISA, alt: 'Visa logo', comingSoon: true },
];

return (
<section className="container mt-12 mx-auto">
<h1 className="mb-4 text-4xl text-center text-black">Trusted by</h1>
<section className="container mx-auto mt-12">
<motion.h1 className="mb-4 text-4xl text-center text-black">Trusted by</motion.h1>
<div className="flex flex-wrap items-center justify-center gap-y-4 gap-x-12">
<ImageList images={trustedByImages} />
<ImageList images={paymentImages} />
</div>
</section>
);
Expand Down
38 changes: 17 additions & 21 deletions src/components/UserBalance/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { InputTokenDetails } from '../../constants/tokenConfig';
import { useInputTokenBalance } from '../../hooks/useInputTokenBalance';
import { useVortexAccount } from '../../hooks/useVortexAccount';
import wallet from '../../assets/wallet.svg';
import wallet from '../../assets/wallet-bifold-outline.svg';

interface UserBalanceProps {
token: InputTokenDetails;
Expand All @@ -13,30 +13,26 @@ export const UserBalance = ({ token, onClick }: UserBalanceProps) => {
const inputTokenBalance = useInputTokenBalance({ fromToken: token });

if (isDisconnected || inputTokenBalance === undefined) {
return <></>;
return <div className="h-6 mt-1" />;
}

const showMaxButton = Number(inputTokenBalance) !== 0;

return (
<p className="flex items-end justify-end mt-1">
<>
<div className="flex align-center font-medium transition">
<img src={wallet} alt="Available" className="w-5 h-5 mr-1" />
<span>
{inputTokenBalance} {token.assetSymbol}
</span>
{showMaxButton && (
<button
className="text-primary hover:underline rounded-md ml-1 bg-base-100 px-1"
type="button"
onClick={() => onClick(inputTokenBalance)}
>
Max
</button>
)}
</div>
</>
</p>
<div className="flex items-center justify-end mt-1 mr-0.5">
<img src={wallet} alt="Available" className="w-5 h-5 mr-0.5" />
<p>
{inputTokenBalance} {token.assetSymbol}
</p>
{showMaxButton && (
<button
className="px-1 ml-1 bg-blue-100 rounded-md text-primary hover:underline"
type="button"
onClick={() => onClick(inputTokenBalance)}
>
Max
</button>
)}
</div>
);
};
2 changes: 1 addition & 1 deletion src/components/WhyVortex/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const features: Feature[] = [
{
icon: DOLLAR,
title: 'Lower Fees',
description: 'Offramping fees at just 0.5%, well below market average.',
description: 'Offramping fees as low as 0.25%.',
subtext: 'Keep more of what you earn.',
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/components/buttons/AssetButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export function AssetButton({ assetIcon, tokenSymbol, onClick }: AssetButtonProp

return (
<button
className="hover:bg-blue-200 rounded-full min-h-none h-8 flex items-center mt-0.5 border border-blue-700 px-2 py-1 pr-3"
className="hover:bg-blue-200 rounded-full h-8 flex items-center mt-0.5 border border-blue-700 px-2 py-1 pr-3"
onClick={onClick}
type="button"
>
<span className="h-full p-px mr-1 rounded-full">
<img src={icon} alt={assetIcon} className="w-auto h-full" />
<img src={icon} alt={assetIcon} className="h-full min-h-5 max-w-min" />
</span>
<strong className="font-bold text-black">{tokenSymbol}</strong>
<ChevronDownIcon className="w-6" />
Expand Down
2 changes: 1 addition & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const config = {
},
walletConnect: {
url: 'wss://relay.walletconnect.com',
projectId: '299fda67fbf3b60a31ba8695524534cd',
projectId: '495a5f574d57e27fd65caa26d9ea4f10',
},
test: {
mockSep24: false,
Expand Down
2 changes: 1 addition & 1 deletion src/constants/tokenConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ export const OUTPUT_TOKEN_CONFIG: Record<OutputTokenType, OutputTokenDetails> =
erc20WrapperAddress: '6eNUvRWCKE3kejoyrJTXiSM7NxtWi37eRXTnKhGKPsJevAj5',
minWithdrawalAmountRaw: '10000000000000',
maxWithdrawalAmountRaw: '10000000000000000',
offrampFeesBasisPoints: 125,
offrampFeesBasisPoints: 25,
usesMemo: false,
supportsClientDomain: true,
},
Expand Down
7 changes: 6 additions & 1 deletion src/hooks/useInputTokenBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,15 @@ const useAssetHubBalance = (assetId?: number): string | undefined => {
const getBalance = async () => {
try {
const { api } = assetHubNode;
const assetInfo = await api.query.assets.asset(assetId);
const { minBalance: rawMinBalance } = assetInfo.toJSON() as { minBalance: number };

const accountInfo = await api.query.assets.account(assetId, walletAccount.address);

const rawBalance = (accountInfo.toJSON() as { balance?: number })?.balance ?? 0;
const formattedBalance = nativeToDecimal(rawBalance, USDC_DECIMALS).toFixed(2, 0).toString();

const offrampableBalance = rawBalance > 0 ? rawBalance - rawMinBalance : 0;
const formattedBalance = nativeToDecimal(offrampableBalance, USDC_DECIMALS).toFixed(2, 0).toString();
setBalance(formattedBalance);
} catch (error) {
console.error('Failed to fetch AssetHub balance:', error);
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useSignChallenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ export function useSiweSignature() {
const errorMessage = error instanceof Error ? error.message : String(error);
setOfframpSigningPhase?.(undefined);

// First case Assethub, second case EVM
if (
(error as Error).message.includes('User rejected the request') ||
(error as Error).message.includes('Signing failed: Cancelled')
(error as Error).message.includes('Cancelled')
) {
// First case Assethub, second case EVM
return signPromise.reject(new Error('Signing failed: User rejected sign request'));
}
return signPromise.reject(new Error('Signing failed: Failed to sign login challenge. ' + errorMessage));
Expand Down
11 changes: 9 additions & 2 deletions src/pages/swap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Big from 'big.js';
import { useEffect, useMemo, useRef, useState, useCallback } from 'preact/hooks';
import { ApiPromise } from '@polkadot/api';
import { Fragment } from 'preact';
import { motion } from 'framer-motion';

import { calculateTotalReceive, FeeCollapse } from '../../components/FeeCollapse';
import { PoolSelectorModal } from '../../components/InputKeys/SelectionModal';
Expand Down Expand Up @@ -372,7 +373,13 @@ export const SwapPage = () => {
const main = (
<main ref={formRef}>
<SigningBox step={offrampSigningPhase} />
<form className="px-4 py-4 mx-4 my-8 rounded-lg shadow-custom md:mx-auto md:w-96" onSubmit={onSwapConfirm}>
<motion.form
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.3 }}
className="px-4 py-4 mx-4 my-8 rounded-lg shadow-custom md:mx-auto md:w-96"
onSubmit={onSwapConfirm}
>
<h1 className="mt-2 mb-5 text-3xl font-bold text-center text-blue-700">Sell Crypto</h1>
<LabeledInput label="You sell" htmlFor="fromAmount" Input={WithdrawNumericInput} />
<div className="my-10" />
Expand Down Expand Up @@ -449,7 +456,7 @@ export const SwapPage = () => {
</div>
<hr className="mt-6 mb-3" />
<PoweredBy />
</form>
</motion.form>
{showCompareFees && fromToken && fromAmount && toToken && (
<FeeComparison
sourceAssetSymbol={fromToken.assetSymbol}
Expand Down
Loading

0 comments on commit c18b9db

Please sign in to comment.