diff --git a/config.testnet.json b/config.testnet.json
index 87c431c6..8eac2541 100644
--- a/config.testnet.json
+++ b/config.testnet.json
@@ -1,6 +1,6 @@
{
"appEnvironment": "testnet",
- "coordinatorURL": "http://localhost:8811",
+ "coordinatorURL": "https://testnet-ripple.dlc.link/attestor-1",
"enabledEthereumNetworkIDs": ["421614", "84532", "11155111"],
"enabledRippleNetworkIDs": ["1"],
"bitcoinNetwork": "testnet",
@@ -10,7 +10,7 @@
"bitcoinBlockchainExplorerURL": "https://mempool.space/testnet",
"bitcoinBlockchainFeeEstimateURL": "https://mempool.space/testnet/api/v1/fees/recommended",
"rippleIssuerAddress": "ra9epzthPkNXykgfadCwu8D7mtajj8DVCP",
- "xrplWebsocket": "wss://s.altnet.rippletest.net:51233",
+ "xrplWebsocket": "wss://testnet.xrpl-labs.com/",
"ledgerApp": "Bitcoin Test",
"merchants": [
{
diff --git a/package.json b/package.json
index 57ee10a7..caa9c316 100644
--- a/package.json
+++ b/package.json
@@ -30,6 +30,7 @@
"@fontsource/inter": "^5.0.18",
"@fontsource/onest": "^5.0.3",
"@fontsource/poppins": "^5.0.8",
+ "@gemwallet/api": "^3.8.0",
"@ledgerhq/hw-app-xrp": "^6.29.4",
"@ledgerhq/hw-transport-webusb": "^6.28.6",
"@netlify/functions": "^2.8.1",
@@ -45,7 +46,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.0",
"dotenv": "^16.3.1",
"ethers": "5.7.2",
"formik": "^2.4.5",
diff --git a/public/images/logos/gem-wallet-logo.svg b/public/images/logos/gem-wallet-logo.svg
new file mode 100644
index 00000000..592bf617
--- /dev/null
+++ b/public/images/logos/gem-wallet-logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/images/logos/xpr-logo.svg b/public/images/logos/xrp-logo.svg
similarity index 100%
rename from public/images/logos/xpr-logo.svg
rename to public/images/logos/xrp-logo.svg
diff --git a/src/app/components/mint-unmint/components/burn-transaction-screen/burn-transaction-screen.tsx b/src/app/components/mint-unmint/components/burn-transaction-screen/burn-transaction-screen.tsx
index b77930db..9712f304 100644
--- a/src/app/components/mint-unmint/components/burn-transaction-screen/burn-transaction-screen.tsx
+++ b/src/app/components/mint-unmint/components/burn-transaction-screen/burn-transaction-screen.tsx
@@ -5,17 +5,14 @@ import { VStack, useToast } from '@chakra-ui/react';
import { VaultTransactionForm } from '@components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/transaction-screen.transaction-form';
import { Vault } from '@components/vault/vault';
import { useEthersSigner } from '@functions/configuration.functions';
-import { useXRPLLedger } from '@hooks/use-xrpl-ledger';
+import { useXRPWallet } from '@hooks/use-xrp-wallet';
import { BitcoinWalletContext } from '@providers/bitcoin-wallet-context-provider';
import { EthereumNetworkConfigurationContext } from '@providers/ethereum-network-configuration.provider';
import { NetworkConfigurationContext } from '@providers/network-configuration.provider';
import { ProofOfReserveContext } from '@providers/proof-of-reserve-context-provider';
-import { XRPWalletContext } from '@providers/xrp-wallet-context-provider';
-// import { XRPWalletContext } from '@providers/xrp-wallet-context-provider';
import { RootState } from '@store/index';
import { mintUnmintActions } from '@store/slices/mintunmint/mintunmint.actions';
import { withdraw } from 'dlc-btc-lib/ethereum-functions';
-import { getRippleClient, getRippleVault } from 'dlc-btc-lib/ripple-functions';
import { shiftValue } from 'dlc-btc-lib/utilities';
interface BurnTokenTransactionFormProps {
@@ -36,8 +33,7 @@ export function BurnTokenTransactionForm({
const { networkType } = useContext(NetworkConfigurationContext);
const { bitcoinWalletContextState } = useContext(BitcoinWalletContext);
- const { xrpHandler } = useContext(XRPWalletContext);
- const { handleCreateCheck, connectLedgerWallet, isLoading } = useXRPLLedger();
+ const { handleCreateCheck, isLoading } = useXRPWallet();
const { bitcoinPrice, depositLimit } = useContext(ProofOfReserveContext);
@@ -55,16 +51,7 @@ export function BurnTokenTransactionForm({
if (!currentVault) return;
setIsSubmitting(true);
if (networkType === 'xrpl') {
- const rippleClient = getRippleClient(appConfiguration.xrplWebsocket);
- const vault = await getRippleVault(
- rippleClient,
- appConfiguration.rippleIssuerAddress,
- currentVault.uuid
- );
- await connectLedgerWallet("44'/144'/0'/0/0");
-
- if (!xrpHandler) throw new Error('No XRP Handler');
- await handleCreateCheck(xrpHandler, vault, withdrawAmount);
+ await handleCreateCheck(currentVault.uuid, withdrawAmount);
} else if (networkType === 'evm') {
const currentRisk = await fetchUserEthereumAddressRiskLevel();
if (currentRisk === 'High') throw new Error('Risk Level is too high');
diff --git a/src/app/components/mint-unmint/components/mint/mint.tsx b/src/app/components/mint-unmint/components/mint/mint.tsx
index be8944d3..3d24aeb6 100644
--- a/src/app/components/mint-unmint/components/mint/mint.tsx
+++ b/src/app/components/mint-unmint/components/mint/mint.tsx
@@ -1,8 +1,10 @@
+import { useContext } from 'react';
import { useSelector } from 'react-redux';
import { HStack } from '@chakra-ui/react';
import { usePSBT } from '@hooks/use-psbt';
import { useRisk } from '@hooks/use-risk';
+import { NetworkConfigurationContext } from '@providers/network-configuration.provider';
import { RootState } from '@store/index';
import { DepositTransactionScreen } from '../deposit-transaction-screen/deposit-transaction-screen';
@@ -13,6 +15,7 @@ import { MintLayout } from './components/mint.layout';
export function Mint(): React.JSX.Element {
const { handleSignFundingTransaction, isLoading: isBitcoinWalletLoading } = usePSBT();
+ const { networkType } = useContext(NetworkConfigurationContext);
const { mintStep } = useSelector((state: RootState) => state.mintunmint);
const { risk, fetchUserAddressRisk, isLoading } = useRisk();
@@ -21,7 +24,7 @@ export function Mint(): React.JSX.Element {
-
+
{[0].includes(mintStep[0]) && }
{[1, 2].includes(mintStep[0]) && (
state.mintunmint);
const { risk, fetchUserAddressRisk, isLoading } = useRisk();
@@ -21,7 +24,7 @@ export function Unmint(): React.JSX.Element {
-
+
{[0].includes(unmintStep[0]) && (
-
- Initiate a Vault on the blockchain and confirm it in your{' '}
-
- Ethereum Wallet
-
- .
-
+ {networkType === 'evm' ? (
+
+ Initiate a Vault on the blockchain and confirm it in your{' '}
+
+ Ethereum Wallet
+
+ .
+
+ ) : (
+
+ Initiate a Setup Vault request. If the TrustLine is not yet established, sign the
+ Set TrustLine Transaction in your wallet. Then, wait for the Attestors to confirm
+ your request and set up the Vault on the blockchain.
+
+ )}
);
@@ -49,16 +62,8 @@ export function Walkthrough({ flow, currentStep }: WalkthroughProps): React.JSX.
/>
Enter the Bitcoin amount you wish to deposit into the vault, then verify the
- transaction through your{' '}
-
- Bitcoin Wallet{' '}
-
- which will lock your Bitcoin on-chain. You will receive equivalent amount of dlcBTC.
+ transaction through your Bitcoin Wallet which will lock your Bitcoin on-chain. You
+ will receive equivalent amount of dlcBTC.
);
@@ -68,32 +73,33 @@ export function Walkthrough({ flow, currentStep }: WalkthroughProps): React.JSX.
- Wait for Bitcoin to get locked on chain{' '}
-
- (~1 hour)
-
- . After 6 confirmations, dlcBTC tokens will appear in your Ethereum Wallet.
-
-
- To ensure your dlcBTC tokens
- are visible
- simply add them
- to your Ethereum Wallet.
+ Wait for Bitcoin to get locked on chain (~1 hour). After 6 confirmations, dlcBTC
+ tokens will appear in your Wallet.
-
+ {networkType === 'evm' && (
+ <>
+
+ To ensure your dlcBTC tokens
+ are visible
+ simply add them
+ to your Ethereum Wallet.
+
+
+
+ >
+ )}
);
default:
@@ -102,7 +108,7 @@ export function Walkthrough({ flow, currentStep }: WalkthroughProps): React.JSX.
);
@@ -115,12 +121,19 @@ export function Walkthrough({ flow, currentStep }: WalkthroughProps): React.JSX.
-
- Select the dlcBTC vault you would like to withdraw from. Burn the desired amount of
- dlcBTC to receive the equivalent amount of BTC.
-
+ {networkType === 'evm' ? (
+
+ Select the dlcBTC vault you would like to withdraw from. Burn the desired amount
+ of dlcBTC to receive the equivalent amount of BTC.
+
+ ) : (
+
+ Select the dlcBTC vault you would like to withdraw from. Sign a check with the
+ desired amount of dlcBTC to receive the equivalent amount of BTC.
+
+ )}
);
case 1:
@@ -161,7 +174,7 @@ export function Walkthrough({ flow, currentStep }: WalkthroughProps): React.JSX.
);
diff --git a/src/app/components/modals/select-wallet-modal/components/select-ripple-wallet-menu.tsx b/src/app/components/modals/select-wallet-modal/components/select-ripple-wallet-menu.tsx
index 30d30acc..f9c35fa1 100644
--- a/src/app/components/modals/select-wallet-modal/components/select-ripple-wallet-menu.tsx
+++ b/src/app/components/modals/select-wallet-modal/components/select-ripple-wallet-menu.tsx
@@ -1,9 +1,9 @@
import { Box, Button, HStack, Image, Text } from '@chakra-ui/react';
-import { XRPWallet } from '@models/wallet';
+import { XRPWallet, XRPWalletType } from '@models/wallet';
interface SelectRippleWalletMenuProps {
rippleWallet: XRPWallet;
- handleConnectWallet: (id: string) => void;
+ handleConnectWallet: (xrpWalletType: XRPWalletType) => void;
}
export function SelectRippleWalletMenu({
diff --git a/src/app/components/modals/select-wallet-modal/select-wallet-modal.tsx b/src/app/components/modals/select-wallet-modal/select-wallet-modal.tsx
index 0048f65e..022c04cf 100644
--- a/src/app/components/modals/select-wallet-modal/select-wallet-modal.tsx
+++ b/src/app/components/modals/select-wallet-modal/select-wallet-modal.tsx
@@ -1,14 +1,15 @@
import { useContext, useEffect, useState } from 'react';
import { CheckIcon } from '@chakra-ui/icons';
-import { HStack, ScaleFade, Tab, TabList, Tabs, Text, VStack } from '@chakra-ui/react';
+import { HStack, ScaleFade, Tab, TabList, Tabs, Text, VStack, useToast } from '@chakra-ui/react';
import { ModalComponentProps } from '@components/modals/components/modal-container';
import { ModalLayout } from '@components/modals/components/modal.layout';
import { SelectNetworkButton } from '@components/select-network-button/select-network-button';
import { TransactionScreenWalletInformation } from '@components/transaction-screen/transaction-screen.transaction-form/components/transaction-screen.transaction-form/components/transaction-screen.transaction-form.wallet-information';
+import { useGemWallet } from '@hooks/use-xrpl-gem';
import { useXRPLLedger } from '@hooks/use-xrpl-ledger';
import { RippleNetworkID } from '@models/ripple.models';
-import { xrpWallets } from '@models/wallet';
+import { XRPWalletType, xrpWallets } from '@models/wallet';
import { NetworkConfigurationContext } from '@providers/network-configuration.provider';
import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
import { XRPWalletContext, XRPWalletContextState } from '@providers/xrp-wallet-context-provider';
@@ -19,7 +20,18 @@ import { Connector, useConfig, useConnect } from 'wagmi';
import { SelectEthereumWalletMenu } from './components/select-ethereum-wallet-menu';
import { SelectRippleWalletMenu } from './components/select-ripple-wallet-menu';
+function formatErrorMessage(error: string): string {
+ if (error.includes('0x6985')) {
+ return 'Action Rejected by User';
+ } else if (error.includes('0x5515')) {
+ return 'Locked Device';
+ } else {
+ return error;
+ }
+}
+
export function SelectWalletModal({ isOpen, handleClose }: ModalComponentProps): React.JSX.Element {
+ const toast = useToast();
const { connect, isPending, isSuccess, connectors } = useConnect();
const { chains: ethereumNetworks } = useConfig();
@@ -32,6 +44,7 @@ export function SelectWalletModal({ isOpen, handleClose }: ModalComponentProps):
setXRPHandler,
} = useContext(XRPWalletContext);
const { connectLedgerWallet, isLoading } = useXRPLLedger();
+ const { connectGemWallet } = useGemWallet();
const { enabledRippleNetworks } = useContext(RippleNetworkConfigurationContext);
const ethereumNetworkIDs = ethereumNetworks.map(
@@ -76,17 +89,51 @@ export function SelectWalletModal({ isOpen, handleClose }: ModalComponentProps):
}
}
- async function handleConnectRippleWallet() {
+ async function handleConnectGemWallet() {
setNetworkType('xrpl');
- setXRPWalletType(xrpWallets[0].id);
+ setXRPWalletType(XRPWalletType.Gem);
- const { xrpHandler, userAddress } = await connectLedgerWallet("44'/144'/0'/0/1");
+ const { xrpHandler, userAddress } = await connectGemWallet();
setXRPHandler(xrpHandler);
setUserAddress(userAddress);
setXRPWalletContextState(XRPWalletContextState.READY);
}
+ async function handleConnectLedgerWallet() {
+ try {
+ setNetworkType('xrpl');
+ setXRPWalletType(XRPWalletType.Ledger);
+
+ const { xrpHandler, userAddress } = await connectLedgerWallet("44'/144'/0'/0/0");
+
+ setXRPHandler(xrpHandler);
+ setUserAddress(userAddress);
+ setXRPWalletContextState(XRPWalletContextState.READY);
+ } catch (error: any) {
+ toast({
+ title: 'Failed to connect Ledger Wallet',
+ description: error instanceof Error ? formatErrorMessage(error.message) : '',
+ status: 'error',
+ duration: 9000,
+ isClosable: true,
+ });
+ }
+ }
+
+ async function handleConnectRippleWallet(xrpWalletType: XRPWalletType) {
+ switch (xrpWalletType) {
+ case XRPWalletType.Gem:
+ await handleConnectGemWallet();
+ break;
+ case XRPWalletType.Ledger:
+ await handleConnectLedgerWallet();
+ break;
+ default:
+ break;
+ }
+ }
+
const handleChangeNetwork = (networkID: EthereumNetworkID | RippleNetworkID) => {
setSelectedNetworkID(networkID);
};
diff --git a/src/app/functions/attestor-request.functions.ts b/src/app/functions/attestor-request.functions.ts
index 3ca4e673..bca47d69 100644
--- a/src/app/functions/attestor-request.functions.ts
+++ b/src/app/functions/attestor-request.functions.ts
@@ -26,6 +26,6 @@ export async function submitSetupXRPLVaultRequest(userAddress: string): Promise<
throw new Error(`HTTP Error: ${errorMessage}`);
}
} catch (error: any) {
- throw new Error(`Failed to get Attestor Group Public Key: ${error.message}`);
+ throw new Error(`Failed to submit Setup XRPL Vault Request: ${error.message}`);
}
}
diff --git a/src/app/hooks/use-psbt.ts b/src/app/hooks/use-psbt.ts
index d4431934..7068b852 100644
--- a/src/app/hooks/use-psbt.ts
+++ b/src/app/hooks/use-psbt.ts
@@ -7,6 +7,7 @@ import { bytesToHex } from '@noble/hashes/utils';
import { BitcoinWalletContext } from '@providers/bitcoin-wallet-context-provider';
import { EthereumNetworkConfigurationContext } from '@providers/ethereum-network-configuration.provider';
import { NetworkConfigurationContext } from '@providers/network-configuration.provider';
+import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
import { XRPWalletContext } from '@providers/xrp-wallet-context-provider';
import { LedgerDLCHandler, SoftwareWalletDLCHandler } from 'dlc-btc-lib';
import {
@@ -15,7 +16,7 @@ import {
} from 'dlc-btc-lib/attestor-request-functions';
import { getAttestorGroupPublicKey, getRawVault } from 'dlc-btc-lib/ethereum-functions';
import { AttestorChainID, RawVault, Transaction, VaultState } from 'dlc-btc-lib/models';
-import { getRippleClient, getRippleVault } from 'dlc-btc-lib/ripple-functions';
+import { getRippleVault } from 'dlc-btc-lib/ripple-functions';
import { useAccount } from 'wagmi';
import { useLeather } from './use-leather';
@@ -35,6 +36,7 @@ export function usePSBT(): UsePSBTReturnType {
} = useContext(EthereumNetworkConfigurationContext);
const { address: ethereumUserAddress } = useAccount();
const { userAddress: rippleUserAddress } = useContext(XRPWalletContext);
+ const { rippleClient } = useContext(RippleNetworkConfigurationContext);
const { bitcoinWalletType, dlcHandler, resetBitcoinWalletContext } =
useContext(BitcoinWalletContext);
@@ -74,14 +76,12 @@ export function usePSBT(): UsePSBTReturnType {
return { userAddress: ethereumUserAddress, vault, attestorGroupPublicKey };
} else if (networkType === 'xrpl') {
if (!rippleUserAddress) throw new Error('User Address is not setup');
- const rippleClient = getRippleClient(appConfiguration.xrplWebsocket);
const vault = await getRippleVault(
rippleClient,
appConfiguration.rippleIssuerAddress,
vaultUUID
);
const attestorGroupPublicKey = await getAttestorExtendedGroupPublicKey();
- console.log('attestorGroupPublicKey', attestorGroupPublicKey);
return {
userAddress: rippleUserAddress,
vault,
diff --git a/src/app/hooks/use-xrp-wallet.ts b/src/app/hooks/use-xrp-wallet.ts
new file mode 100644
index 00000000..7686212a
--- /dev/null
+++ b/src/app/hooks/use-xrp-wallet.ts
@@ -0,0 +1,89 @@
+import { useContext } from 'react';
+
+import { BitcoinError } from '@models/error-types';
+import { XRPWalletType } from '@models/wallet';
+import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
+import { XRPWalletContext } from '@providers/xrp-wallet-context-provider';
+import { GemXRPHandler } from 'dlc-btc-lib';
+import { getRippleVault } from 'dlc-btc-lib/ripple-functions';
+
+import { useGemWallet } from './use-xrpl-gem';
+import { useXRPLLedger } from './use-xrpl-ledger';
+
+interface UseXRPWalletReturnType {
+ handleCreateCheck: (vaultUUID: string, withdrawAmount: number) => Promise;
+ handleSetTrustLine: () => Promise;
+ isLoading: [boolean, string];
+}
+
+export function useXRPWallet(): UseXRPWalletReturnType {
+ const { rippleClient } = useContext(RippleNetworkConfigurationContext);
+ const { xrpWalletType, xrpHandler } = useContext(XRPWalletContext);
+
+ const {
+ handleCreateCheck: handleCreateCheckWithLedger,
+ handleSetTrustLine: handleSetTrustLineWithLedger,
+ isLoading: isLedgerLoading,
+ } = useXRPLLedger();
+
+ const {
+ handleCreateCheck: handleCreateCheckWithGem,
+ handleSetTrustLine: handleSetTrustLineWithGem,
+ isLoading: isGemLoading,
+ } = useGemWallet();
+
+ async function handleCreateCheck(vaultUUID: string, withdrawAmount: number): Promise {
+ try {
+ if (!xrpHandler) throw new Error('XRP Handler is not setup');
+
+ const vault = await getRippleVault(
+ rippleClient,
+ appConfiguration.rippleIssuerAddress,
+ vaultUUID
+ );
+
+ switch (xrpWalletType) {
+ case 'Ledger':
+ await handleCreateCheckWithLedger(vault, withdrawAmount);
+ break;
+ case 'Gem':
+ await handleCreateCheckWithGem(xrpHandler as GemXRPHandler, vault, withdrawAmount);
+ break;
+ default:
+ throw new Error('Invalid XRP Wallet Type');
+ }
+ } catch (error) {
+ throw new BitcoinError(`Error signing Funding Transaction: ${error}`);
+ }
+ }
+
+ async function handleSetTrustLine(): Promise {
+ try {
+ if (!xrpHandler) throw new Error('XRP Handler is not setup');
+
+ switch (xrpWalletType) {
+ case 'Ledger':
+ await handleSetTrustLineWithLedger();
+ break;
+ case 'Gem':
+ await handleSetTrustLineWithGem(xrpHandler as GemXRPHandler);
+ break;
+ default:
+ throw new Error('Invalid XRP Wallet Type');
+ }
+ } catch (error) {
+ throw new BitcoinError(`Error signing Withdraw Transaction: ${error}`);
+ }
+ }
+
+ const loadingStates = {
+ [XRPWalletType.Ledger]: isLedgerLoading,
+ [XRPWalletType.Gem]: isGemLoading,
+ };
+
+ return {
+ handleCreateCheck,
+ handleSetTrustLine,
+ isLoading: xrpWalletType ? loadingStates[xrpWalletType] : [false, ''],
+ };
+}
diff --git a/src/app/hooks/use-xrpl-gem.ts b/src/app/hooks/use-xrpl-gem.ts
new file mode 100644
index 00000000..a5a7412f
--- /dev/null
+++ b/src/app/hooks/use-xrpl-gem.ts
@@ -0,0 +1,91 @@
+import { useContext, useState } from 'react';
+
+import { getAddress, isInstalled } from '@gemwallet/api';
+import { GemError } from '@models/error-types';
+import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
+import { GemXRPHandler } from 'dlc-btc-lib';
+import { RawVault } from 'dlc-btc-lib/models';
+import { shiftValue } from 'dlc-btc-lib/utilities';
+
+interface useXRPLGemReturnType {
+ isLoading: [boolean, string];
+ connectGemWallet: () => Promise<{ xrpHandler: GemXRPHandler; userAddress: string }>;
+ handleCreateCheck: (
+ xrpHandler: GemXRPHandler,
+ vault: RawVault,
+ withdrawAmount: number
+ ) => Promise;
+ handleSetTrustLine: (xrpHandler: GemXRPHandler) => Promise;
+}
+
+export function useGemWallet(): useXRPLGemReturnType {
+ const { rippleClient } = useContext(RippleNetworkConfigurationContext);
+
+ const [isLoading, setIsLoading] = useState<[boolean, string]>([false, '']);
+
+ async function connectGemWallet() {
+ try {
+ setIsLoading([true, 'Connecting To Gem Wallet']);
+
+ const isGemWalletInstalled = await isInstalled();
+ if (!isGemWalletInstalled.result.isInstalled) {
+ throw new GemError('Gem Wallet is not Installed');
+ }
+
+ const getAddressResponse = await getAddress();
+
+ if (!getAddressResponse.result) {
+ throw new GemError('No User Address Found');
+ }
+
+ const xrpHandler = new GemXRPHandler(
+ rippleClient,
+ appConfiguration.rippleIssuerAddress,
+ getAddressResponse.result.address
+ );
+
+ return { xrpHandler, userAddress: getAddressResponse.result.address };
+ } catch (error) {
+ throw new GemError(`Error connecting to Gem Wallet: ${error}`);
+ } finally {
+ setIsLoading([false, '']);
+ }
+ }
+
+ async function handleCreateCheck(
+ xrpHandler: GemXRPHandler,
+ vault: RawVault,
+ withdrawAmount: number
+ ) {
+ try {
+ setIsLoading([true, 'Sign Check in your Gem Wallet']);
+
+ const formattedWithdrawAmount = BigInt(shiftValue(withdrawAmount));
+
+ return await xrpHandler.createCheck(formattedWithdrawAmount.toString(), vault.uuid.slice(2));
+ } catch (error) {
+ throw new GemError(`Error creating Check: ${error}`);
+ } finally {
+ setIsLoading([false, '']);
+ }
+ }
+
+ async function handleSetTrustLine(xrpHandler: GemXRPHandler) {
+ try {
+ setIsLoading([true, 'Set Trust Line in your Gem Wallet']);
+
+ return await xrpHandler.setTrustLine();
+ } catch (error) {
+ throw new GemError(`Error setting Trust Line: ${error}`);
+ } finally {
+ setIsLoading([false, '']);
+ }
+ }
+
+ return {
+ isLoading,
+ connectGemWallet,
+ handleCreateCheck,
+ handleSetTrustLine,
+ };
+}
diff --git a/src/app/hooks/use-xrpl-ledger.ts b/src/app/hooks/use-xrpl-ledger.ts
index 97e77850..03a6d7c2 100644
--- a/src/app/hooks/use-xrpl-ledger.ts
+++ b/src/app/hooks/use-xrpl-ledger.ts
@@ -14,12 +14,8 @@ interface useXRPLLedgerReturnType {
connectLedgerWallet: (
derivationPath: string
) => Promise<{ xrpHandler: LedgerXRPHandler; userAddress: string }>;
- handleCreateCheck: (
- xrpHandler: LedgerXRPHandler,
- vault: RawVault,
- withdrawAmount: number
- ) => Promise;
- handleSetTrustLine: (xrpHandler: LedgerXRPHandler) => Promise;
+ handleCreateCheck: (vault: RawVault, withdrawAmount: number) => Promise;
+ handleSetTrustLine: () => Promise;
}
type TransportInstance = Awaited>;
@@ -99,7 +95,9 @@ export function useXRPLLedger(): useXRPLLedgerReturnType {
xrplWallet,
derivationPath,
rippleClient,
- appConfiguration.rippleIssuerAddress
+ appConfiguration.rippleIssuerAddress,
+ xrplAddress.address,
+ xrplAddress.publicKey
);
return { xrpHandler, userAddress: xrplAddress.address };
@@ -110,34 +108,34 @@ export function useXRPLLedger(): useXRPLLedgerReturnType {
}
}
- async function handleCreateCheck(
- xrpHandler: LedgerXRPHandler,
- vault: RawVault,
- withdrawAmount: number
- ) {
+ async function handleCreateCheck(vault: RawVault, withdrawAmount: number) {
try {
+ const { xrpHandler: currentXRPHandler } = await connectLedgerWallet("44'/144'/0'/0/0");
+
setIsLoading([true, 'Sign Check on your Ledger Device']);
const formattedWithdrawAmount = BigInt(shiftValue(withdrawAmount));
- return await xrpHandler.createCheck(formattedWithdrawAmount.toString(), vault.uuid.slice(2));
+ return await currentXRPHandler.createCheck(
+ formattedWithdrawAmount.toString(),
+ vault.uuid.slice(2)
+ );
} catch (error) {
- throw new LedgerError(`Error creating check: ${error}`);
+ throw new LedgerError(`Error creating Check: ${error}`);
} finally {
setIsLoading([false, '']);
}
}
- async function handleSetTrustLine(xrpHandler: LedgerXRPHandler) {
+ async function handleSetTrustLine() {
try {
+ const { xrpHandler: currentXRPHandler } = await connectLedgerWallet("44'/144'/0'/0/0");
+
setIsLoading([true, 'Set Trust Line on your Ledger Device']);
- console.log('Setting trust line');
- const trustLine = await xrpHandler.setTrustLine();
- console.log('Trust line set');
- return trustLine;
+ return await currentXRPHandler.setTrustLine();
} catch (error) {
- throw new LedgerError(`Error setting trust line: ${error}`);
+ throw new LedgerError(`Error setting Trust Line: ${error}`);
} finally {
setIsLoading([false, '']);
}
diff --git a/src/app/hooks/use-xrpl-vaults.ts b/src/app/hooks/use-xrpl-vaults.ts
index 4d535de9..b8c56361 100644
--- a/src/app/hooks/use-xrpl-vaults.ts
+++ b/src/app/hooks/use-xrpl-vaults.ts
@@ -4,17 +4,14 @@ import { useDispatch } from 'react-redux';
import { formatVault } from '@functions/vault.functions';
import { Vault } from '@models/vault';
import { NetworkConfigurationContext } from '@providers/network-configuration.provider';
+import { RippleNetworkConfigurationContext } from '@providers/ripple-network-configuration.provider';
import { XRPWalletContext } from '@providers/xrp-wallet-context-provider';
import { mintUnmintActions } from '@store/slices/mintunmint/mintunmint.actions';
import { modalActions } from '@store/slices/modal/modal.actions';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import Decimal from 'decimal.js';
import { VaultState } from 'dlc-btc-lib/models';
-import {
- connectRippleClient,
- getAllRippleVaults,
- getRippleClient,
-} from 'dlc-btc-lib/ripple-functions';
+import { connectRippleClient, getAllRippleVaults } from 'dlc-btc-lib/ripple-functions';
const INITIAL_VAULT_UUID = '0x0000000000000000000000000000000000000000000000000000000000000000';
@@ -61,28 +58,31 @@ export function useXRPLVaults(): useXRPLVaultsReturnType {
const [isLoading, setIsLoading] = useState(true);
const { networkType } = useContext(NetworkConfigurationContext);
- const { userAddress: rippleUserAddress } = useContext(XRPWalletContext);
+ const { userAddress: xrpUserAddress } = useContext(XRPWalletContext);
+ const { rippleClient } = useContext(RippleNetworkConfigurationContext);
const issuerAddress = appConfiguration.rippleIssuerAddress;
- const xrplClient = getRippleClient('wss://s.altnet.rippletest.net:51233');
const { data: xrplVaults } = useQuery({
- queryKey: ['xrpl-vaults'],
+ queryKey: ['xrpl-vaults', xrpUserAddress],
initialData: [],
queryFn: fetchXRPLVaults,
- refetchInterval: 10000,
- enabled: networkType === 'xrpl' && !!rippleUserAddress,
+ refetchInterval: 20000,
+ enabled: networkType === 'xrpl' && !!xrpUserAddress,
});
async function fetchXRPLVaults(): Promise {
setIsLoading(true);
- const previousVaults: Vault[] | undefined = queryClient.getQueryData(['xrpl-vaults']);
+ const previousVaults: Vault[] | undefined = queryClient.getQueryData([
+ 'xrpl-vaults',
+ xrpUserAddress,
+ ]);
try {
- await connectRippleClient(xrplClient);
+ await connectRippleClient(rippleClient);
- const xrplRawVaults = await getAllRippleVaults(xrplClient, issuerAddress, rippleUserAddress);
+ const xrplRawVaults = await getAllRippleVaults(rippleClient, issuerAddress, xrpUserAddress);
const xrplVaults = xrplRawVaults.map(formatVault);
if (
@@ -105,7 +105,6 @@ export function useXRPLVaults(): useXRPLVaultsReturnType {
const previousVault = previousVaults?.find(
previousVault => previousVault.uuid === vault.uuid
);
-
handleVaultStateChange(previousVault, vault);
});
diff --git a/src/app/providers/balance-context-provider.tsx b/src/app/providers/balance-context-provider.tsx
index b270c29e..fb660264 100644
--- a/src/app/providers/balance-context-provider.tsx
+++ b/src/app/providers/balance-context-provider.tsx
@@ -48,7 +48,6 @@ export function BalanceContextProvider({ children }: HasChildren): React.JSX.Ele
const fetchXRPLBalances = async () => {
const dlcBTCBalance = await xrpHandler?.getDLCBTCBalance();
const lockedBTCBalance = await xrpHandler?.getLockedBTCBalance();
- console.log('lockedBTCBalance', lockedBTCBalance);
return { dlcBTCBalance, lockedBTCBalance };
};
diff --git a/src/app/providers/network-configuration.provider.tsx b/src/app/providers/network-configuration.provider.tsx
index d192c9ac..d65381c8 100644
--- a/src/app/providers/network-configuration.provider.tsx
+++ b/src/app/providers/network-configuration.provider.tsx
@@ -1,4 +1,4 @@
-import React, { createContext, useEffect, useState } from 'react';
+import React, { createContext, useState } from 'react';
import { HasChildren } from '@models/has-children';
@@ -14,10 +14,6 @@ export const NetworkConfigurationContext = createContext('evm');
- useEffect(() => {
- console.log('networkType in provioder', networkType);
- }, [networkType]);
-
return (
>;
xrpWalletContextState: XRPWalletContextState;
setXRPWalletContextState: React.Dispatch>;
- xrpHandler: LedgerXRPHandler | undefined;
- setXRPHandler: React.Dispatch>;
+ xrpHandler: LedgerXRPHandler | GemXRPHandler | undefined;
+ setXRPHandler: React.Dispatch>;
setUserAddress: React.Dispatch>;
userAddress: string | undefined;
resetXRPWalletContext: () => void;
@@ -41,7 +41,7 @@ export function XRPWalletContextProvider({ children }: HasChildren): React.JSX.E
const [xrpWalletType, setXRPWalletType] = useState(
XRPWalletType.Ledger
);
- const [xrpHandler, setXRPHandler] = useState();
+ const [xrpHandler, setXRPHandler] = useState();
const [userAddress, setUserAddress] = useState(undefined);
function resetXRPWalletContext() {
diff --git a/src/shared/models/error-types.ts b/src/shared/models/error-types.ts
index de18f5a3..cd0dd7a5 100644
--- a/src/shared/models/error-types.ts
+++ b/src/shared/models/error-types.ts
@@ -25,3 +25,10 @@ export class UnisatError extends Error {
this.name = 'UnisatError';
}
}
+
+export class GemError extends Error {
+ constructor(message: string) {
+ super(message);
+ this.name = 'GemError';
+ }
+}
diff --git a/src/shared/models/wallet.ts b/src/shared/models/wallet.ts
index 83cfd917..40bff0d4 100644
--- a/src/shared/models/wallet.ts
+++ b/src/shared/models/wallet.ts
@@ -45,11 +45,11 @@ const ledgerXRP: XRPWallet = {
icon: './images/logos/ledger-logo.svg',
};
-// const gemXRP: XRPWallet = {
-// id: XRPWalletType.Gem,
-// name: 'Gem',
-// icon: '/images/logos/gem-logo.svg',
-// };
+const gemXRP: XRPWallet = {
+ id: XRPWalletType.Gem,
+ name: 'Gem',
+ icon: '/images/logos/gem-wallet-logo.svg',
+};
-export const xrpWallets: XRPWallet[] = [ledgerXRP];
+export const xrpWallets: XRPWallet[] = [ledgerXRP, gemXRP];
export const bitcoinWallets: BitcoinWallet[] = [leather, ledger, unisat];
diff --git a/yarn.lock b/yarn.lock
index a03ab7cf..ec2b78e8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1875,6 +1875,11 @@
resolved "https://registry.npmjs.org/@fontsource/poppins/-/poppins-5.0.12.tgz"
integrity sha512-0qzBxtIJLh82iMJ9pCXKYwGs1zyS+jyUmwVJ59+JdYnEaFVkDsxVOk9yDWfVOs14ALUneodU2m5YSGma6dCYCw==
+"@gemwallet/api@3.8.0", "@gemwallet/api@^3.8.0":
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@gemwallet/api/-/api-3.8.0.tgz#46bc47789848c7ac9cc620613e0a1757dc8668a1"
+ integrity sha512-hZ6XC0mVm3Q54cgonrzk6tHS/wUMjtPHyqsqbtlnNGPouCR7OIfEDo5Y802qLZ5ah6PskhsK0DouVnwUykEM8Q==
+
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
@@ -5190,9 +5195,12 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
-"dlc-btc-lib@file:../dlc-btc-lib":
- version "2.3.0"
+dlc-btc-lib@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/dlc-btc-lib/-/dlc-btc-lib-2.4.0.tgz#715a309baa6829451668dfe65f635f1299b4909b"
+ integrity sha512-1xYVd2fwb+AVhfC/fd8eArFkdyEJS7uwxnUQOcmBmfNPk/ElUI+U2nfOtfwgv73svZTEU/RMaPQR6psFimI3UQ==
dependencies:
+ "@gemwallet/api" "3.8.0"
"@ledgerhq/hw-app-btc" "10.4.1"
"@ledgerhq/hw-app-xrp" "6.29.4"
"@noble/hashes" "1.4.0"
@@ -5207,7 +5215,7 @@ dir-glob@^3.0.1:
ledger-bitcoin "0.2.3"
prompts "2.4.2"
ramda "0.30.1"
- ripple-binary-codec "^2.1.0"
+ ripple-binary-codec "2.1.0"
scure "1.6.0"
tiny-secp256k1 "2.2.3"
xrpl "4.0.0"
@@ -7117,9 +7125,9 @@ multiformats@^9.4.2:
integrity sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==
nan@^2.13.2:
- version "2.21.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.21.0.tgz#203ab765a02e6676c8cb92e1cad9503e7976d55b"
- integrity sha512-MCpOGmdWvAOMi4RWnpxS5G24l7dVMtdSHtV87I3ltjaLdFOTO74HVJ+DfYiAXjxGKsYR/UCmm1rBwhMN7KqS1A==
+ version "2.22.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3"
+ integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==
nanoid@^3.3.7:
version "3.3.7"
@@ -8004,7 +8012,7 @@ ripple-address-codec@^5.0.0:
"@scure/base" "^1.1.3"
"@xrplf/isomorphic" "^1.0.0"
-ripple-binary-codec@^2.1.0:
+ripple-binary-codec@2.1.0, ripple-binary-codec@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ripple-binary-codec/-/ripple-binary-codec-2.1.0.tgz#f1ef81f8d1f05a6cecc06fc6d9b13456569cafda"
integrity sha512-q0GAx+hj3UVcDbhXVjk7qeNfgUMehlElYJwiCuIBwqs/51GVTOwLr39Ht3eNsX5ow2xPRaC5mqHwcFDvLRm6cA==