Skip to content

Commit

Permalink
feat: add gem wallet xrp handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Polybius93 committed Oct 15, 2024
1 parent cfbd637 commit f73dc87
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 44 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"typescript-eslint": "^7.7.0"
},
"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",
Expand Down
33 changes: 4 additions & 29 deletions src/dlc-handlers/software-wallet-dlc-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Transaction, p2tr, p2wpkh } from '@scure/btc-signer';
import { P2Ret, P2TROut } from '@scure/btc-signer/payment';
import { Network } from 'bitcoinjs-lib';
import { bitcoin, regtest, testnet } from 'bitcoinjs-lib/src/networks.js';

import {
createTaprootMultisigPayment,
Expand Down Expand Up @@ -33,35 +32,11 @@ export class SoftwareWalletDLCHandler {
taprootDerivedPublicKey: string,
fundingPaymentType: 'wpkh' | 'tr',
bitcoinNetwork: Network,
bitcoinBlockchainAPI?: string,
bitcoinBlockchainFeeRecommendationAPI?: string
bitcoinBlockchainAPI: string,
bitcoinBlockchainFeeRecommendationAPI: string
) {
switch (bitcoinNetwork) {
case bitcoin:
this.bitcoinBlockchainAPI = 'https://mempool.space/api';
this.bitcoinBlockchainFeeRecommendationAPI =
'https://mempool.space/api/v1/fees/recommended';
break;
case testnet:
this.bitcoinBlockchainAPI = 'https://mempool.space/testnet/api';
this.bitcoinBlockchainFeeRecommendationAPI =
'https://mempool.space/testnet/api/v1/fees/recommended';
break;
case regtest:
if (
bitcoinBlockchainAPI === undefined ||
bitcoinBlockchainFeeRecommendationAPI === undefined
) {
throw new Error(
'Regtest requires a Bitcoin Blockchain API and a Bitcoin Blockchain Fee Recommendation API'
);
}
this.bitcoinBlockchainAPI = bitcoinBlockchainAPI;
this.bitcoinBlockchainFeeRecommendationAPI = bitcoinBlockchainFeeRecommendationAPI;
break;
default:
throw new Error('Invalid Bitcoin Network');
}
this.bitcoinBlockchainAPI = bitcoinBlockchainAPI;
this.bitcoinBlockchainFeeRecommendationAPI = bitcoinBlockchainFeeRecommendationAPI;
this.fundingPaymentType = fundingPaymentType;
this.bitcoinNetwork = bitcoinNetwork;
this.fundingDerivedPublicKey = fundingDerivedPublicKey;
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PrivateKeyDLCHandler } from './dlc-handlers/private-key-dlc-handler.js'
import { SoftwareWalletDLCHandler } from './dlc-handlers/software-wallet-dlc-handler.js';
import { EthereumHandler } from './network-handlers/ethereum-handler.js';
import { RippleHandler } from './network-handlers/ripple-handler.js';
import { GemXRPHandler } from './network-handlers/xrp-gem-wallet-handler.js';
import { LedgerXRPHandler } from './network-handlers/xrp-ledger-handler.js';
import { ProofOfReserveHandler } from './proof-of-reserve-handlers/proof-of-reserve-handler.js';

Expand All @@ -11,6 +12,7 @@ export {
LedgerDLCHandler,
SoftwareWalletDLCHandler,
LedgerXRPHandler,
GemXRPHandler,
EthereumHandler,
ProofOfReserveHandler,
RippleHandler,
Expand Down
136 changes: 136 additions & 0 deletions src/network-handlers/xrp-gem-wallet-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { getAddress, signTransaction } from '@gemwallet/api';
import { ResponseType } from '@gemwallet/api/_constants/index.js';
import { CheckCreate, Client, TrustSet } from 'xrpl';

import {
checkRippleTransactionResult,
connectRippleClient,
createCheck,
getDLCBTCBalance,
getLockedBTCBalance,
setTrustLine,
} from '../functions/ripple/ripple.functions.js';

export class GemXRPHandler {
private xrpClient: Client;
private issuerAddress: string;
private userAddress: string;

constructor(xrpClient: Client, issuerAddress: string, userAddress: string) {
this.xrpClient = xrpClient;
this.issuerAddress = issuerAddress;
this.userAddress = userAddress;
}

public async getAddress(): Promise<string> {
const getAddressResponse = await getAddress();

if (getAddressResponse.type === ResponseType.Reject || !getAddressResponse.result) {
throw new Error('Error getting Address');
}
return getAddressResponse.result.address;
}

public async setTrustLine(): Promise<void> {
try {
const trustLineRequest = await setTrustLine(
this.xrpClient,
this.userAddress,
this.issuerAddress
);

if (!trustLineRequest) {
console.error('TrustLine is already set');
return;
}
const updatedTrustLineRequest: TrustSet = {
...trustLineRequest,
Flags: 2147483648,
};

const signTrustLineResponse = await signTransaction({ transaction: updatedTrustLineRequest });

if (
signTrustLineResponse.type === ResponseType.Reject ||
!signTrustLineResponse.result ||
!signTrustLineResponse.result.signature
) {
throw new Error('Error signing Trust Line');
}

const signedTrustLineRequest = signTrustLineResponse.result.signature;

await connectRippleClient(this.xrpClient);

const submitTrustLineRequestResponse =
await this.xrpClient.submitAndWait(signedTrustLineRequest);

console.log(`Response for submitted Transaction Request:`, submitTrustLineRequestResponse);

checkRippleTransactionResult(submitTrustLineRequestResponse);
} catch (error) {
throw new Error(`Error setting Trust Line: ${error}`);
}
}

public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<void> {
try {
const checkCreateRequest: CheckCreate = await createCheck(
this.xrpClient,
this.userAddress,
this.issuerAddress,
undefined,
dlcBTCAmount,
vaultUUID
);

const updatedCheckCreateRequest: CheckCreate = {
...checkCreateRequest,
Flags: 2147483648,
};

const signCheckCreateResponse = await signTransaction({
transaction: updatedCheckCreateRequest,
});

if (
signCheckCreateResponse.type === ResponseType.Reject ||
!signCheckCreateResponse.result ||
!signCheckCreateResponse.result.signature
) {
throw new Error('Error signing Check Create');
}

const signedCheckCreateRequest = signCheckCreateResponse.result.signature;

await connectRippleClient(this.xrpClient);

const submitCheckCreateRequestResponse =
await this.xrpClient.submitAndWait(signedCheckCreateRequest);

console.log(`Response for submitted Transaction Request:`, submitCheckCreateRequestResponse);

checkRippleTransactionResult(submitCheckCreateRequestResponse);
} catch (error) {
throw new Error(`Error creating Check: ${error}`);
}
}

public async getDLCBTCBalance(): Promise<number> {
try {
await connectRippleClient(this.xrpClient);
return await getDLCBTCBalance(this.xrpClient, this.userAddress, this.issuerAddress);
} catch (error) {
throw new Error(`Error getting BTC Balance: ${error}`);
}
}

public async getLockedBTCBalance(): Promise<number> {
try {
await connectRippleClient(this.xrpClient);
return await getLockedBTCBalance(this.xrpClient, this.userAddress, this.issuerAddress);
} catch (error) {
throw new Error(`Error getting BTC Balance: ${error}`);
}
}
}
30 changes: 15 additions & 15 deletions src/network-handlers/xrp-ledger-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,23 @@ export class LedgerXRPHandler {
private derivationPath: string;
private xrpClient: Client;
private issuerAddress: string;
private userAddress: string;
private publicKey: string;

constructor(
ledgerApp: Xrp.default,
derivationPath: string,
xrpClient: Client,
issuerAddress: string
issuerAddress: string,
userAddress: string,
publicKey: string
) {
this.ledgerApp = ledgerApp;
this.derivationPath = derivationPath;
this.xrpClient = xrpClient;
this.issuerAddress = issuerAddress;
this.userAddress = userAddress;
this.publicKey = publicKey;
}

public async getAddress(): Promise<string> {
Expand All @@ -36,11 +42,9 @@ export class LedgerXRPHandler {

public async setTrustLine(): Promise<void> {
try {
const deviceData = await this.ledgerApp.getAddress(this.derivationPath);

const trustLineRequest = await setTrustLine(
this.xrpClient,
deviceData.address,
this.userAddress,
this.issuerAddress
);

Expand All @@ -51,7 +55,7 @@ export class LedgerXRPHandler {
const updatedTrustLineRequest: TrustSet = {
...trustLineRequest,
Flags: 2147483648,
SigningPubKey: deviceData.publicKey.toUpperCase(),
SigningPubKey: this.publicKey.toUpperCase(),
};

const encodedTrustLineRequest = encode(updatedTrustLineRequest);
Expand Down Expand Up @@ -82,11 +86,9 @@ export class LedgerXRPHandler {

public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<void> {
try {
const deviceData = await this.ledgerApp.getAddress(this.derivationPath);

const checkCreateRequest: CheckCreate = await createCheck(
this.xrpClient,
deviceData.address,
this.userAddress,
this.issuerAddress,
undefined,
dlcBTCAmount,
Expand All @@ -96,7 +98,7 @@ export class LedgerXRPHandler {
const updatedCheckCreateRequest: CheckCreate = {
...checkCreateRequest,
Flags: 2147483648,
SigningPubKey: deviceData.publicKey.toUpperCase(),
SigningPubKey: this.publicKey.toUpperCase(),
};

const encodedCheckCreateRequest = encode(updatedCheckCreateRequest);
Expand Down Expand Up @@ -126,19 +128,17 @@ export class LedgerXRPHandler {

public async getDLCBTCBalance(): Promise<number> {
try {
const deviceData = await this.ledgerApp.getAddress(this.derivationPath);

return await getDLCBTCBalance(this.xrpClient, deviceData.address, this.issuerAddress);
await connectRippleClient(this.xrpClient);
return await getDLCBTCBalance(this.xrpClient, this.userAddress, this.issuerAddress);
} catch (error) {
throw new Error(`Error getting BTC Balance: ${error}`);
}
}

public async getLockedBTCBalance(): Promise<number> {
try {
const deviceData = await this.ledgerApp.getAddress(this.derivationPath);

return await getLockedBTCBalance(this.xrpClient, deviceData.address, this.issuerAddress);
await connectRippleClient(this.xrpClient);
return await getLockedBTCBalance(this.xrpClient, this.userAddress, this.issuerAddress);
} catch (error) {
throw new Error(`Error getting BTC Balance: ${error}`);
}
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,11 @@
"@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.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.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
Expand Down

0 comments on commit f73dc87

Please sign in to comment.