Skip to content

Commit

Permalink
feat: add cash check by tx id function (#33)
Browse files Browse the repository at this point in the history
* feat: add cash check by tx id function

* chore: bump package version

* feat: modify currency to dlcbtc, add functions to xrphandlers
  • Loading branch information
Polybius93 authored Oct 18, 2024
1 parent 3c40342 commit 9730076
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 58 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"type": "module",
"name": "dlc-btc-lib",
"version": "2.4.3",
"version": "2.4.5",
"description": "This library provides a comprehensive set of interfaces and functions for minting dlcBTC tokens on supported blockchains.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
3 changes: 3 additions & 0 deletions src/constants/ripple.constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
import { convertStringToHex } from 'xrpl';

export const TRANSACTION_SUCCESS_CODE = 'tesSUCCESS';
export const XRPL_DLCBTC_CURRENCY_HEX = convertStringToHex('dlcBTC').padEnd(40, '0');
5 changes: 5 additions & 0 deletions src/functions/attestor/attestor-request.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export async function submitSetupXRPLVaultRequest(
return sendRequest(`${coordinatorURL}/app/setup-xrpl-vault`, requestBody);
}

export async function submitXRPLCheckToCash(coordinatorURL: string, txHash: string): Promise<void> {
const requestBody = JSON.stringify({ tx_hash: txHash });
return sendRequest(`${coordinatorURL}/app/cash-xrpl-check`, requestBody);
}

export async function getAttestorExtendedGroupPublicKey(coordinatorURL: string): Promise<string> {
return sendGetRequest(`${coordinatorURL}/tss/get-extended-group-publickey`);
}
Expand Down
1 change: 1 addition & 0 deletions src/functions/attestor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export {
submitWithdrawDepositPSBT,
getAttestorExtendedGroupPublicKey,
submitSetupXRPLVaultRequest,
submitXRPLCheckToCash,
} from '../attestor/attestor-request.functions.js';
48 changes: 43 additions & 5 deletions src/functions/ripple/ripple.functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
AccountLinesResponse,
AccountNFToken,
AccountNFTsRequest,
AccountObjectsRequest,
CheckCreate,
Client,
LedgerEntry,
SubmittableTransaction,
Transaction,
TransactionMetadataBase,
Expand All @@ -17,7 +19,10 @@ import {
convertStringToHex,
} from 'xrpl';

import { TRANSACTION_SUCCESS_CODE } from '../../constants/ripple.constants.js';
import {
TRANSACTION_SUCCESS_CODE,
XRPL_DLCBTC_CURRENCY_HEX,
} from '../../constants/ripple.constants.js';
import { RippleError } from '../../models/errors.js';
import { RawVault } from '../../models/ethereum-models.js';
import { SignResponse } from '../../models/ripple.model.js';
Expand Down Expand Up @@ -165,7 +170,9 @@ export async function setTrustLine(
result: { lines },
}: AccountLinesResponse = await rippleClient.request(accountNonXRPBalancesRequest);

if (lines.some(line => line.currency === 'BTC' && line.account === issuerAddress)) {
if (
lines.some(line => line.currency === XRPL_DLCBTC_CURRENCY_HEX && line.account === issuerAddress)
) {
console.log(`Trust Line already exists for Issuer: ${issuerAddress}`);
return;
}
Expand All @@ -174,7 +181,7 @@ export async function setTrustLine(
TransactionType: 'TrustSet',
Account: ownerAddress,
LimitAmount: {
currency: 'BTC',
currency: XRPL_DLCBTC_CURRENCY_HEX,
issuer: issuerAddress,
value: '10000000000',
},
Expand Down Expand Up @@ -312,7 +319,7 @@ export async function getDLCBTCBalance(
}: AccountLinesResponse = await rippleClient.request(accountNonXRPBalancesRequest);

const dlcBTCBalance = lines.find(
line => line.currency === 'BTC' && line.account === issuerAddress
line => line.currency === XRPL_DLCBTC_CURRENCY_HEX && line.account === issuerAddress
);
if (!dlcBTCBalance) {
return 0;
Expand Down Expand Up @@ -346,7 +353,7 @@ export async function createCheck(
Destination: destinationAddress,
DestinationTag: destinationTag,
SendMax: {
currency: 'BTC',
currency: XRPL_DLCBTC_CURRENCY_HEX,
value: shiftedAmountAsNumber.toString(),
issuer: destinationAddress,
},
Expand All @@ -361,3 +368,34 @@ export async function createCheck(
throw new RippleError(`Error creating Check for Vault ${vaultUUID}: ${error}`);
}
}

export async function getCheckByTXHash(
rippleClient: Client,
issuerAddress: string,
txHash: string
): Promise<LedgerEntry.Check> {
try {
await connectRippleClient(rippleClient);

const getAccountObjectsRequest: AccountObjectsRequest = {
command: 'account_objects',
account: issuerAddress,
ledger_index: 'validated',
type: 'check',
};

const {
result: { account_objects },
} = await rippleClient.request(getAccountObjectsRequest);

const check = account_objects.find(accountObject => accountObject.PreviousTxnID === txHash);

if (!check) {
throw new RippleError(`Check with TX Hash: ${txHash} not found`);
}

return check as LedgerEntry.Check;
} catch (error) {
throw new RippleError(`Error getting Check by TX Hash: ${error}`);
}
}
79 changes: 34 additions & 45 deletions src/network-handlers/ripple-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ import xrpl, {
AccountObjectsResponse,
CheckCash,
IssuedCurrencyAmount,
LedgerEntry,
Payment,
Request,
SubmittableTransaction,
} from 'xrpl';
import { NFTokenMintMetadata } from 'xrpl/dist/npm/models/transactions/NFTokenMint.js';

import { decodeURI, encodeURI } from '../functions/ripple/ripple.functions.js';
import { XRPL_DLCBTC_CURRENCY_HEX } from '../constants/ripple.constants.js';
import {
connectRippleClient,
decodeURI,
encodeURI,
getCheckByTXHash,
} from '../functions/ripple/ripple.functions.js';
import { RippleError } from '../models/errors.js';
import { RawVault, SSFVaultUpdate, SSPVaultUpdate } from '../models/ethereum-models.js';
import { shiftValue, unshiftValue } from '../utilities/index.js';
Expand Down Expand Up @@ -130,6 +135,7 @@ export class RippleHandler {
const getNFTsTransaction: AccountNFTsRequest = {
command: 'account_nfts',
account: this.issuerAddress,
limit: 400,
};
let nftUUID = uuid.substring(0, 2) === '0x' ? uuid.slice(2) : uuid;
nftUUID = nftUUID.toUpperCase();
Expand Down Expand Up @@ -357,6 +363,7 @@ export class RippleHandler {
const getNFTsTransaction: AccountNFTsRequest = {
command: 'account_nfts',
account: this.issuerAddress,
limit: 400,
};

const nfts: xrpl.AccountNFTsResponse = await this.client.request(getNFTsTransaction);
Expand Down Expand Up @@ -506,55 +513,37 @@ export class RippleHandler {
return getAccountObjectsResponse.result.account_objects;
}

async getAndCashAllChecksAndUpdateNFT(): Promise<string[]> {
const allChecks = (await this.getAllChecks()) as LedgerEntry.Check[];
// console.log('All Checks:', allChecks);
const allVaults = await this.getContractVaults();
async getCashCheckAndWithdrawSignatures(txHash: string): Promise<string[]> {
try {
const check = await getCheckByTXHash(this.client, this.issuerAddress, txHash);
const invoiceID = check.InvoiceID;

for (const check of allChecks) {
try {
const checkSendMax = check.SendMax as IssuedCurrencyAmount;
if (!invoiceID) {
throw new RippleError(`Could not find Invoice ID for Check with TX Hash: ${txHash}`);
}

const my_check_cash_sig = await this.cashCheck(check.index, checkSendMax.value);
const vault = await this.getRawVault(`0x${invoiceID}`.toLowerCase());

const vault = allVaults.find(
vault => vault.uuid.toUpperCase().slice(2) === check.InvoiceID
);
if (!vault) {
throw new RippleError(
`Could not find Vault for Check with Invoice ID: ${check.InvoiceID}`
);
}
const two_more_sigs = await this.withdraw(
vault.uuid,
BigInt(shiftValue(Number(checkSendMax.value)))
);
return [my_check_cash_sig, ...two_more_sigs];
} catch (error) {
console.error(`Error cashing Check: ${error} \n continuing`);
if (!vault) {
throw new RippleError(`Could not find Vault for Check with Invoice ID: ${check.InvoiceID}`);
}

const checkSendMax = check.SendMax as IssuedCurrencyAmount;

const checkCashSignatures = await this.cashCheck(check.index, checkSendMax.value);

const mintAndBurnSignatures = await this.withdraw(
vault.uuid,
BigInt(shiftValue(Number(checkSendMax.value)))
);
return [checkCashSignatures, ...mintAndBurnSignatures];
} catch (error) {
throw new RippleError(`Could not get Cash Check and Withdraw Signatures: ${error}`);
}
return [];
}

async cashCheck(checkID: string, dlcBTCAmount: string): Promise<string> {
if (!this.client.isConnected()) {
await this.client.connect();
}

//what's
if (
[
'8FC923A16C90FB7316673D35CA228C82916B8E9F63EADC57BAA7C51C2E7716AA',
'AD2F46F345B07A070CBB0797D47D4D1A6CAA2BB541A0932014B909194665E4D5',
'DDF48640BF7DBC84FD08C1129999415CF5745095871FA6E50F1EAEB8AB032654',
'BA8B88BC1FD746F538AA6EFD1F1BFC982E3CCDD93EDDCFB4541EA608B355D778',
'48A7965799596CDA23C774778CD2D65E3E7C01648077539840A51ABD54791E32',
'93BAA031806AE4902933C1EE9B66E7EBAF0F7A182314085BEFF99DF080A1CBCB',
'F51C7E3CCFD2EC8CA9A460A34C5BC185E9466031865E76736C0A60BC3F7C7316',
].includes(checkID)
)
throw new Error('Invalid Check');
await connectRippleClient(this.client);

console.log(`Cashing Check of Check ID ${checkID} for an amount of ${dlcBTCAmount}`);

Expand All @@ -563,7 +552,7 @@ export class RippleHandler {
Account: this.issuerAddress,
CheckID: checkID,
Amount: {
currency: 'BTC',
currency: XRPL_DLCBTC_CURRENCY_HEX,
value: dlcBTCAmount,
issuer: this.issuerAddress,
},
Expand Down Expand Up @@ -616,7 +605,7 @@ export class RippleHandler {
Destination: destinationAddress,
DestinationTag: 1,
Amount: {
currency: 'BTC',
currency: XRPL_DLCBTC_CURRENCY_HEX,
value: dlcBTCAmount,
issuer: this.issuerAddress,
},
Expand Down
24 changes: 21 additions & 3 deletions src/network-handlers/xrp-gem-wallet-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getAddress, signTransaction } from '@gemwallet/api';
import { ResponseType } from '@gemwallet/api/_constants/index.js';
import { CheckCreate, Client, TrustSet } from 'xrpl';

import { submitXRPLCheckToCash } from '../functions/attestor/attestor-request.functions.js';
import {
checkRippleTransactionResult,
connectRippleClient,
Expand Down Expand Up @@ -73,7 +74,7 @@ export class GemXRPHandler {
}
}

public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<void> {
public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<CheckCreate> {
try {
const checkCreateRequest: CheckCreate = await createCheck(
this.xrpClient,
Expand All @@ -89,8 +90,16 @@ export class GemXRPHandler {
Flags: 2147483648,
};

return updatedCheckCreateRequest;
} catch (error) {
throw new Error(`Error creating Check: ${error}`);
}
}

public async signAndSubmitCheck(checkCreateRequest: CheckCreate): Promise<string> {
try {
const signCheckCreateResponse = await signTransaction({
transaction: updatedCheckCreateRequest,
transaction: checkCreateRequest,
});

if (
Expand All @@ -111,11 +120,20 @@ export class GemXRPHandler {
console.log(`Response for submitted Transaction Request:`, submitCheckCreateRequestResponse);

checkRippleTransactionResult(submitCheckCreateRequestResponse);

return submitCheckCreateRequestResponse.result.hash;
} catch (error) {
throw new Error(`Error creating Check: ${error}`);
throw new Error(`Error signing and submitting Check: ${error}`);
}
}

public async sendCheckTXHash(coordinatorURL: string, checkTXHash: string): Promise<void> {
try {
await submitXRPLCheckToCash(coordinatorURL, checkTXHash);
} catch (error) {
throw new Error(`Error sending Check TX Hash to Attestors: ${error}`);
}
}
public async getDLCBTCBalance(): Promise<number> {
try {
await connectRippleClient(this.xrpClient);
Expand Down
27 changes: 23 additions & 4 deletions src/network-handlers/xrp-ledger-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as Xrp from '@ledgerhq/hw-app-xrp';
import { encode } from 'ripple-binary-codec';
import { CheckCreate, Client, Transaction, TrustSet } from 'xrpl';

import { submitXRPLCheckToCash } from '../functions/attestor/attestor-request.functions.js';
import {
checkRippleTransactionResult,
connectRippleClient,
Expand Down Expand Up @@ -84,7 +85,7 @@ export class LedgerXRPHandler {
}
}

public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<void> {
public async createCheck(dlcBTCAmount: string, vaultUUID: string): Promise<CheckCreate> {
try {
const checkCreateRequest: CheckCreate = await createCheck(
this.xrpClient,
Expand All @@ -101,15 +102,23 @@ export class LedgerXRPHandler {
SigningPubKey: this.publicKey.toUpperCase(),
};

const encodedCheckCreateRequest = encode(updatedCheckCreateRequest);
return updatedCheckCreateRequest;
} catch (error) {
throw new Error(`Error creating Check: ${error}`);
}
}

public async signAndSubmitCheck(checkCreateRequest: CheckCreate): Promise<string> {
try {
const encodedCheckCreateRequest = encode(checkCreateRequest);

const signature = await this.ledgerApp.signTransaction(
this.derivationPath,
encodedCheckCreateRequest
);

const signedCheckCreateRequest: Transaction = {
...updatedCheckCreateRequest,
...checkCreateRequest,
TxnSignature: signature,
};

Expand All @@ -121,8 +130,18 @@ export class LedgerXRPHandler {
console.log(`Response for submitted Transaction Request:`, submitCheckCreateRequestResponse);

checkRippleTransactionResult(submitCheckCreateRequestResponse);

return submitCheckCreateRequestResponse.result.hash;
} catch (error) {
throw new Error(`Error creating Check: ${error}`);
throw new Error(`Error signing and submitting Check: ${error}`);
}
}

public async sendCheckTXHash(coordinatorURL: string, checkTXHash: string): Promise<void> {
try {
await submitXRPLCheckToCash(coordinatorURL, checkTXHash);
} catch (error) {
throw new Error(`Error sending Check TX Hash to Attestors: ${error}`);
}
}

Expand Down

0 comments on commit 9730076

Please sign in to comment.