Skip to content

Commit

Permalink
feat: modify dfns modal form and config
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed Dec 3, 2024
1 parent b8335b8 commit ada07dd
Show file tree
Hide file tree
Showing 15 changed files with 139 additions and 61 deletions.
10 changes: 10 additions & 0 deletions config.devnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"rippleIssuerAddress": "rLTBw1MEy45uE5qmkWseinbj7h4zmdQuR8",
"xrplWebsocket": "wss://s.altnet.rippletest.net:51233",
"ledgerApp": "Bitcoin Test",
"dfnsConfiguration": {
"dfnsBaseURL": "https://api.dfns.ninja",
"dfnsCustomerConfigurations": [
{
"name": "Tungsten",
"organizationID": "or-3pqgf-ugmhq-8969lp77c7f8uf81",
"applicationID": "ap-513sv-f5knb-811qggt4oh6hd5s9"
}
]
},
"merchants": [
{
"name": "Amber",
Expand Down
10 changes: 10 additions & 0 deletions config.mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"rippleIssuerAddress": "rGcyRGrZPaJAZbZDi4NqRFLA5GQH63iFpD",
"xrplWebsocket": "wss://xrpl.ws/",
"ledgerApp": "Bitcoin",
"dfnsConfiguration": {
"dfnsBaseURL": "https://api.dfns.ninja",
"dfnsCustomerConfigurations": [
{
"name": "Tungsten",
"organizationID": "or-3pqgf-ugmhq-8969lp77c7f8uf81",
"applicationID": "ap-513sv-f5knb-811qggt4oh6hd5s9"
}
]
},
"merchants": [
{
"name": "Amber",
Expand Down
12 changes: 10 additions & 2 deletions config.testnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,16 @@
"rippleIssuerAddress": "ra3oyRVfy4yD4NJPrVcewvDtisZ3FhkcYL",
"xrplWebsocket": "wss://testnet.xrpl-labs.com/",
"ledgerApp": "Bitcoin Test",
"dfnsAppID": "ap-7pvrc-mei7e-9u3pfedu9tidiq6p",
"dfnsBaseURL": "http://localhost:3000/dfns-proxy/",
"dfnsConfiguration": {
"dfnsBaseURL": "https://api.dfns.ninja",
"dfnsCustomerConfigurations": [
{
"name": "Tungsten",
"organizationID": "or-3pqgf-ugmhq-8969lp77c7f8uf81",
"applicationID": "ap-513sv-f5knb-811qggt4oh6hd5s9"
}
]
},
"merchants": [
{
"name": "Amber",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"concurrently": "^8.2.2",
"d3": "^7.9.0",
"decimal.js": "^10.4.3",
"dlc-btc-lib": "file:../dlc-btc-lib",
"dlc-btc-lib": "2.4.19-dfns-beta",
"dotenv": "^16.3.1",
"ethers": "5.7.2",
"formik": "^2.4.5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ interface DFNSModalErrorBoxProps {
export function DFNSModalErrorBox({ error }: DFNSModalErrorBoxProps): React.JSX.Element | false {
return (
!!error && (
<HStack p={'5%'} w={'375px'} spacing={4} bgColor={'red'} justifyContent={'center'}>
<HStack
p={'5%'}
w={'375px'}
spacing={4}
border={'1px solid'}
borderRadius={'md'}
borderColor={'red'}
justifyContent={'center'}
>
<Text fontFamily={'Inter'} fontSize={'xs'} fontWeight={'600'}>
{error}
</Text>
Expand Down
53 changes: 20 additions & 33 deletions src/app/components/modals/dfns-modal/components/dfns-modal-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@ import { Button, FormControl, FormErrorMessage, FormLabel, Input, VStack } from
import { useForm } from '@tanstack/react-form';

interface DFNSModalLoginFormProps {
onSubmit: (username: string, organizationID: string) => Promise<void>;
onSubmit: (email: string) => Promise<void>;
}

const validateEmail = (email: string) => {
if (!email) return 'Email address is required';

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) return 'Please enter a valid email address';

const [localPart] = email.split('@');
if (localPart.length > 64) return 'Local part of email cannot exceed 64 characters';
if (email.length > 254) return 'Email address cannot exceed 254 characters';

return undefined;
};

export function DFNSModalLoginForm({ onSubmit }: DFNSModalLoginFormProps): React.JSX.Element {
const formAPI = useForm({
defaultValues: {
username: '',
organizationId: '',
email: '',
},
onSubmit: async ({ value }) => {
await onSubmit(value.username, value.organizationId);
await onSubmit(value.email);
},
});

Expand All @@ -27,43 +39,18 @@ export function DFNSModalLoginForm({ onSubmit }: DFNSModalLoginFormProps): React
>
<VStack spacing={4} w={'100%'}>
<formAPI.Field
name="username"
name="email"
validators={{
onChange: ({ value }) => {
if (!value) return 'Username is required';
if (value.length < 3) return 'Username must be at least 3 characters';
return undefined;
},
onChange: ({ value }) => validateEmail(value),
}}
children={field => (
<FormControl isInvalid={!!field.state.meta.errorMap.onChange}>
<FormLabel>Username</FormLabel>
<FormLabel>E-Mail Address</FormLabel>
<Input
type="email"
value={field.state.value}
onChange={e => field.handleChange(e.target.value)}
placeholder="[email protected]"
/>
<FormErrorMessage>{field.state.meta.errorMap.onChange}</FormErrorMessage>
</FormControl>
)}
/>

<formAPI.Field
name="organizationId"
validators={{
onChange: ({ value }) => {
if (!value) return 'Organization ID is required';
return undefined;
},
}}
children={field => (
<FormControl isInvalid={!!field.state.meta.errorMap.onChange}>
<FormLabel>Organization ID</FormLabel>
<Input
value={field.state.value}
onChange={e => field.handleChange(e.target.value)}
placeholder="Enter organization ID"
placeholder="[email protected]"
/>
<FormErrorMessage>{field.state.meta.errorMap.onChange}</FormErrorMessage>
</FormControl>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export function DFNSModalLayout({
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack minHeight={'425px'}>{children}</VStack>
<VStack minHeight={'425px'} spacing={'25px'}>
{children}
</VStack>
</ModalBody>
</ModalContent>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export function DFNSModalNavigatorButton({
if (!isVisible) return false;

return (
<VStack w={'100%'}>
<VStack w={'100%'} spacing={'25px'}>
<Text fontSize="sm" color="gray.500">
{!isRegister
? 'New user? Click the button below to register with your DFNS credential code'
: 'Existing user? Sign in with your username and organization ID'}
? 'New user? Click the button below to register with your DFNS credential code.'
: 'Existing user? Sign in with your e-mail address.'}
</Text>
<Button variant={'dfns'} onClick={() => setIsRegister(!isRegister)}>
{isRegister ? 'Login' : 'Register'}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ButtonGroup, Text, VStack } from '@chakra-ui/react';
import { scrollBarDFNSAddressCSS } from '@styles/css-styles';

import { DFNSModalAddressButton } from './components/dfns-modal-address-button';

Expand All @@ -21,9 +22,16 @@ export function DFNSModalSelectAddressMenu({
!isLoading &&
!isSuccesful &&
!error && (
<VStack>
<Text fontSize={'lg'}>Select Wallet</Text>
<ButtonGroup orientation="vertical" w={'100%'} overflowY={'scroll'}>
<VStack w={'100%'} h={'100%'}>
<Text fontSize={'lg'}>Select Bitcoin Address</Text>
<ButtonGroup
orientation="vertical"
overflowY={'auto'}
overflowX={'hidden'}
w={'100%'}
css={scrollBarDFNSAddressCSS}
h={'350px'}
>
{taprootAddresses?.map(address => (
<DFNSModalAddressButton
key={address.address}
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/modals/dfns-modal/dfns-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ export function DFNSModal({ isOpen, handleClose }: ModalComponentProps): React.J
setDFNSError(undefined);
}

async function connectDFNSWalletAndGetAddresses(username: string, organizationID: string) {
async function connectDFNSWalletAndGetAddresses(username: string) {
try {
const taprootAddresses = await connectDFNSWallet(username, organizationID);
const taprootAddresses = await connectDFNSWallet(username);
setTaprootAddresses(taprootAddresses);
setIsLoadingAddressList(false);
} catch (error: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function SelectBitcoinWalletMenu({
return (
<Button variant={'wallet'} onClick={() => handleClick(id)}>
<HStack justifyContent={'space-evenly'} w={'250px'}>
<Image src={logo} alt={name} boxSize={'25px'} />
<Image src={logo} alt={name} boxSize={'25px'} objectFit={'contain'} />
<Text w={'150px'}>{name}</Text>
</HStack>
</Button>
Expand Down
40 changes: 30 additions & 10 deletions src/app/hooks/use-dfns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ const BITCOIN_NETWORK_DFNS_MAP = {

interface UseDFNSReturnType {
connectDFNSWallet: (
userName: string,
organizationID: string
userName: string
) => Promise<{ address: string | undefined; walletID: string }[]>;
registerCredentials: (code: string) => Promise<void>;
selectWallet: (walletId: string) => Promise<void>;
Expand Down Expand Up @@ -54,16 +53,26 @@ export function useDFNS(): UseDFNSReturnType {
const [isLoading, setIsLoading] = useState<[boolean, string]>([false, '']);

async function connectDFNSWallet(
userName: string,
organizationID: string
userName: string
): Promise<{ address: string | undefined; walletID: string }[]> {
try {
setIsLoading([true, 'Connecting to DFNS Wallet']);

const { dfnsBaseURL } = appConfiguration.dfnsConfiguration;
const dfnsConfiguration = appConfiguration.dfnsConfiguration.dfnsCustomerConfigurations.find(
({ name }) => name === 'Tungsten'
);

if (!dfnsConfiguration) {
throw new Error('DFNS Configuration not found');
}

const { applicationID, organizationID } = dfnsConfiguration;

const signer = new WebAuthnSigner();
const authApi = new DfnsAuthenticator({
appId: appConfiguration.dfnsAppID,
baseUrl: appConfiguration.dfnsBaseURL,
appId: applicationID,
baseUrl: dfnsBaseURL,
signer,
});

Expand All @@ -73,8 +82,8 @@ export function useDFNS(): UseDFNSReturnType {
});

const dfnsDLCHandler = new DFNSDLCHandler(
appConfiguration.dfnsAppID,
appConfiguration.dfnsBaseURL,
applicationID,
dfnsBaseURL,
token,
BITCOIN_NETWORK_MAP[appConfiguration.bitcoinNetwork],
appConfiguration.bitcoinBlockchainURL,
Expand Down Expand Up @@ -116,11 +125,22 @@ export function useDFNS(): UseDFNSReturnType {
}

async function registerCredentials(code: string): Promise<void> {
const { dfnsBaseURL } = appConfiguration.dfnsConfiguration;
const dfnsConfiguration = appConfiguration.dfnsConfiguration.dfnsCustomerConfigurations.find(
({ name }) => name === 'Tungsten'
);

if (!dfnsConfiguration) {
throw new Error('DFNS Configuration not found');
}

const { applicationID } = dfnsConfiguration;

const signer = new WebAuthnSigner();
const dfnsAPI = new DfnsApiClient({
appId: appConfiguration.dfnsAppID,
appId: applicationID,
authToken: undefined,
baseUrl: appConfiguration.dfnsBaseURL,
baseUrl: dfnsBaseURL,
signer,
});

Expand Down
14 changes: 12 additions & 2 deletions src/shared/models/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ enum AppEnvironment {
LOCALHOST = 'localhost',
}

interface DFNSCustomerConfiguration {
name: string;
organizationID: string;
applicationID: string;
}

interface DFNSConfiguration {
dfnsBaseURL: string;
dfnsCustomerConfigurations: DFNSCustomerConfiguration[];
}

type BitcoinNetworkPrefix = 'bc1' | 'tb1' | 'bcrt1';
export const ALL_SUPPORTED_BITCOIN_NETWORK_PREFIX: BitcoinNetworkPrefix[] = ['bc1', 'tb1', 'bcrt1'];

Expand All @@ -42,8 +53,7 @@ export interface Configuration {
bitcoinBlockchainFeeEstimateURL: string;
rippleIssuerAddress: string;
ledgerApp: string;
dfnsAppID: string;
dfnsBaseURL: string;
dfnsConfiguration: DFNSConfiguration;
merchants: Merchant[];
protocols: Protocol[];
}
13 changes: 13 additions & 0 deletions src/styles/css-styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ export const scrollBarCSS = {
},
};

export const scrollBarDFNSAddressCSS = {
'&::-webkit-scrollbar': {
background: 'rgba(255,255,255,0.25)',
width: '3.5px',
},
'&::-webkit-scrollbar-track': {
width: '2.5px',
},
'&::-webkit-scrollbar-thumb': {
background: '#E1FF0B',
},
};

export const boxShadowAnimation = keyframes`
0% { box-shadow: 0 0 5px rgba(255,255,255,0); }
25% { box-shadow: 0 0 10px rgba(255,255,255,0.5); }
Expand Down
6 changes: 4 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5220,8 +5220,10 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"

"dlc-btc-lib@file:../dlc-btc-lib":
version "2.4.10"
[email protected]:
version "2.4.19-dfns-beta"
resolved "https://registry.yarnpkg.com/dlc-btc-lib/-/dlc-btc-lib-2.4.19-dfns-beta.tgz#4d9ddb7591a0d3f5cc99d09a7e25cea7aece77e3"
integrity sha512-niqR5KixLyrxgR91DzcDfpb5sW7IEWtHqpsLRTFFI679hcPabglYI5l5NsNc6UZ08DHI7ecd2/ZKnEXlMMxCpg==
dependencies:
"@dfns/sdk" "^0.5.9"
"@dfns/sdk-browser" "^0.5.9"
Expand Down

0 comments on commit ada07dd

Please sign in to comment.