diff --git a/UNIQUE_SETUPS.md b/UNIQUE_SETUPS.md index bc45269cc5..f383f925c0 100644 --- a/UNIQUE_SETUPS.md +++ b/UNIQUE_SETUPS.md @@ -22,12 +22,8 @@ To use `xrpl.js` with React, you need to install shims for core NodeJS modules. assert \ buffer \ crypto-browserify \ - https-browserify \ - os-browserify \ process \ - stream-browserify \ - stream-http \ - url + stream-browserify ``` 2. Modify your webpack configuration @@ -48,11 +44,7 @@ To use `xrpl.js` with React, you need to install shims for core NodeJS modules. Object.assign(fallback, { assert: require.resolve("assert"), crypto: require.resolve("crypto-browserify"), - http: require.resolve("stream-http"), - https: require.resolve("https-browserify"), - os: require.resolve("os-browserify"), stream: require.resolve("stream-browserify"), - url: require.resolve("url"), ws: require.resolve("xrpl/dist/npm/client/WSWrapper"), }); config.resolve.fallback = fallback; @@ -141,7 +133,6 @@ export default defineConfig({ }, optimizeDeps: { esbuildOptions: { - define: { global: 'globalThis', }, @@ -165,8 +156,6 @@ resolve: { events: 'events', crypto: 'crypto-browserify', stream: 'stream-browserify', - http: 'stream-http', - https: 'https-browserify', ws: 'xrpl/dist/npm/client/WSWrapper', }, }}) @@ -181,8 +170,6 @@ npm install --save-dev @esbuild-plugins/node-globals-polyfill \ events \ crypto-browserify \ stream-browserify \ - stream-http \ - https-browserify \ xrpl ``` diff --git a/package-lock.json b/package-lock.json index b9c5f87aba..337f40f88a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,6 @@ "eslint-plugin-tsdoc": "^0.2.16", "eventemitter2": "^6.0.0", "expect": "^29.3.1", - "https-browserify": "^1.0.0", "jest": "^29.3.1", "jest-mock": "^29.3.1", "lerna": "^4.0.0", @@ -55,12 +54,10 @@ "source-map-loader": "^4.0.1", "source-map-support": "^0.5.16", "stream-browserify": "^3.0.0", - "stream-http": "3.2.0", "ts-jest": "^29.0.3", "ts-loader": "^9.2.5", "ts-node": "^10.2.1", "typescript": "^5.1.6", - "url": "^0.11.0", "webpack": "^5.81.0", "webpack-bundle-analyzer": "^4.1.0", "webpack-cli": "^5.0.1" @@ -5333,6 +5330,33 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5864,7 +5888,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -5874,7 +5897,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -10554,8 +10576,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash._reinterpolate": { "version": "3.0.0", @@ -12920,7 +12941,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, "engines": { "node": ">=6" } @@ -13762,7 +13782,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "node_modules/schema-utils": { "version": "3.3.0", @@ -14943,7 +14963,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, "dependencies": { "punycode": "^2.1.1" }, @@ -15633,7 +15652,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, "engines": { "node": ">=10.4" } @@ -15819,7 +15837,6 @@ "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, "dependencies": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -16264,6 +16281,7 @@ "bignumber.js": "^9.0.0", "bip32": "^2.0.6", "bip39": "^3.0.4", + "cross-fetch": "^4.0.0", "ripple-address-codec": "^4.3.0", "ripple-binary-codec": "^1.7.1", "ripple-keypairs": "^1.3.0", @@ -20581,6 +20599,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "requires": { + "node-fetch": "^2.6.12" + }, + "dependencies": { + "node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "requires": { + "whatwg-url": "^5.0.0" + } + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -21001,7 +21037,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -21011,7 +21046,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -24663,8 +24697,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -26544,8 +26577,7 @@ "punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" }, "pure-rand": { "version": "6.0.2", @@ -27180,7 +27212,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "schema-utils": { "version": "3.3.0", @@ -28096,7 +28128,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, "requires": { "punycode": "^2.1.1" } @@ -28599,8 +28630,7 @@ "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==" }, "webpack": { "version": "5.88.1", @@ -28716,7 +28746,6 @@ "version": "8.7.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, "requires": { "lodash": "^4.7.0", "tr46": "^2.1.0", @@ -28965,6 +28994,7 @@ "bip39": "^3.0.4", "browserify-fs": "^1.0.0", "constants-browserify": "^1.0.0", + "cross-fetch": "^4.0.0", "https-browserify": "^1.0.0", "https-proxy-agent": "^7.0.1", "karma": "^6.4.1", diff --git a/package.json b/package.json index ee49d30806..078df97b92 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "eslint-plugin-tsdoc": "^0.2.16", "eventemitter2": "^6.0.0", "expect": "^29.3.1", - "https-browserify": "^1.0.0", "jest": "^29.3.1", "jest-mock": "^29.3.1", "lerna": "^4.0.0", @@ -60,12 +59,10 @@ "source-map-loader": "^4.0.1", "source-map-support": "^0.5.16", "stream-browserify": "^3.0.0", - "stream-http": "3.2.0", "ts-jest": "^29.0.3", "ts-loader": "^9.2.5", "ts-node": "^10.2.1", "typescript": "^5.1.6", - "url": "^0.11.0", "webpack": "^5.81.0", "webpack-bundle-analyzer": "^4.1.0", "webpack-cli": "^5.0.1" diff --git a/packages/xrpl/package.json b/packages/xrpl/package.json index 3976df058b..60da5ee0e2 100644 --- a/packages/xrpl/package.json +++ b/packages/xrpl/package.json @@ -24,6 +24,7 @@ "bignumber.js": "^9.0.0", "bip32": "^2.0.6", "bip39": "^3.0.4", + "cross-fetch": "^4.0.0", "ripple-address-codec": "^4.3.0", "ripple-binary-codec": "^1.7.1", "ripple-keypairs": "^1.3.0", diff --git a/packages/xrpl/src/Wallet/fundWallet.ts b/packages/xrpl/src/Wallet/fundWallet.ts index c75b607ed6..6c7fd981f1 100644 --- a/packages/xrpl/src/Wallet/fundWallet.ts +++ b/packages/xrpl/src/Wallet/fundWallet.ts @@ -1,6 +1,4 @@ -import { IncomingMessage } from 'http' -import { request as httpsRequest, RequestOptions } from 'https' - +import fetch from 'cross-fetch' import { isValidClassicAddress } from 'ripple-address-codec' import type { Client } from '../client' @@ -19,6 +17,40 @@ const INTERVAL_SECONDS = 1 // Maximum attempts to retrieve a balance const MAX_ATTEMPTS = 20 +export interface FundingOptions { + /** + * A custom amount to fund, if undefined or null, the default amount will be 1000. + */ + amount?: string + /** + * A custom host for a faucet server. On devnet, testnet, AMM devnet, and HooksV3 testnet, `fundWallet` will + * attempt to determine the correct server automatically. In other environments, or if you would like to customize + * the faucet host in devnet or testnet, you should provide the host using this option. + */ + faucetHost?: string + /** + * A custom path for a faucet server. On devnet, + * testnet, AMM devnet, and HooksV3 testnet, `fundWallet` will + * attempt to determine the correct path automatically. In other environments, + * or if you would like to customize the faucet path in devnet or testnet, + * you should provide the path using this option. + * Ex: client.fundWallet(null,{'faucet.altnet.rippletest.net', '/accounts'}) + * specifies a request to 'faucet.altnet.rippletest.net/accounts' to fund a new wallet. + */ + faucetPath?: string + /** + * An optional field to indicate the use case context of the faucet transaction + * Ex: integration test, code snippets. + */ + usageContext?: string +} + +interface FaucetRequestBody { + destination?: string + xrpAmount?: string + usageContext?: string + userAgent: string +} /** * The fundWallet() method is used to send an amount of XRP (usually 1000) to a new (randomly generated) * or existing XRP Ledger wallet. @@ -65,36 +97,16 @@ const MAX_ATTEMPTS = 20 * * @param this - Client. * @param wallet - An existing XRPL Wallet to fund. If undefined or null, a new Wallet will be created. - * @param options - See below. - * @param options.faucetHost - A custom host for a faucet server. On devnet, - * testnet, AMM devnet, and HooksV3 testnet, `fundWallet` will - * attempt to determine the correct server automatically. In other environments, - * or if you would like to customize the faucet host in devnet or testnet, - * you should provide the host using this option. - * @param options.faucetPath - A custom path for a faucet server. On devnet, - * testnet, AMM devnet, and HooksV3 testnet, `fundWallet` will - * attempt to determine the correct path automatically. In other environments, - * or if you would like to customize the faucet path in devnet or testnet, - * you should provide the path using this option. - * Ex: client.fundWallet(null,{'faucet.altnet.rippletest.net', '/accounts'}) - * specifies a request to 'faucet.altnet.rippletest.net/accounts' to fund a new wallet. - * @param options.amount - A custom amount to fund, if undefined or null, the default amount will be 1000. - * @param options.usageContext - An optional field to indicate the use case context of the faucet transaction - * Ex: integration test, code snippets. + * @param options - FundingOptions + * @returns A Wallet on the Testnet or Devnet that contains some amount of XRP, * and that wallet's balance in XRP. * @throws When either Client isn't connected or unable to fund wallet address. */ -// eslint-disable-next-line max-lines-per-function -- All lines necessary async function fundWallet( this: Client, wallet?: Wallet | null, - options?: { - faucetHost?: string - faucetPath?: string - amount?: string - usageContext?: string - }, + options: FundingOptions = {}, ): Promise<{ wallet: Wallet balance: number @@ -102,6 +114,7 @@ async function fundWallet( if (!this.isConnected()) { throw new RippledError('Client not connected, cannot call faucet') } + const existingWallet = Boolean(wallet) // Generate a new Wallet if no existing Wallet is provided or its address is invalid to fund const walletToFund = @@ -110,151 +123,83 @@ async function fundWallet( : Wallet.generate() // Create the POST request body - const postBody = Buffer.from( - new TextEncoder().encode( - JSON.stringify({ - destination: walletToFund.classicAddress, - xrpAmount: options?.amount, - userAgent: 'xrpl.js', - usageContext: options?.usageContext, - }), - ), - ) + const postBody: FaucetRequestBody = { + destination: walletToFund.classicAddress, + xrpAmount: options.amount, + usageContext: options.usageContext, + userAgent: 'xrpl.js', + } let startingBalance = 0 - try { - startingBalance = Number( - await this.getXrpBalance(walletToFund.classicAddress), - ) - } catch { - /* startingBalance remains '0' */ + if (existingWallet) { + try { + startingBalance = Number( + await this.getXrpBalance(walletToFund.classicAddress), + ) + } catch { + /* startingBalance remains what it was previously */ + } } - // Options to pass to https.request - const httpOptions = getHTTPOptions(this, postBody, { - hostname: options?.faucetHost, - pathname: options?.faucetPath, - }) - return returnPromise( - httpOptions, - this, - startingBalance, - walletToFund, - postBody, - ) + return requestFunding(options, this, startingBalance, walletToFund, postBody) } // eslint-disable-next-line max-params -- Helper function created for organizational purposes -async function returnPromise( - options: RequestOptions, +async function requestFunding( + options: FundingOptions, client: Client, startingBalance: number, walletToFund: Wallet, - postBody: Buffer, + postBody: FaucetRequestBody, ): Promise<{ wallet: Wallet balance: number }> { - return new Promise((resolve, reject) => { - const request = httpsRequest(options, (response) => { - const chunks: Uint8Array[] = [] - response.on('data', (data) => chunks.push(data)) - // eslint-disable-next-line @typescript-eslint/no-misused-promises -- not actually misused, different resolve/reject - response.on('end', async () => - onEnd( - response, - chunks, - client, - startingBalance, - walletToFund, - resolve, - reject, - ), - ) - }) - // POST the body - request.write(postBody) - - request.on('error', (error) => { - reject(error) - }) - - request.end() - }) -} - -function getHTTPOptions( - client: Client, - postBody: Uint8Array, - options?: { - hostname?: string - pathname?: string - }, -): RequestOptions { - const finalHostname = options?.hostname ?? getFaucetHost(client) - const finalPathname = options?.pathname ?? getDefaultFaucetPath(finalHostname) - return { - hostname: finalHostname, - port: 443, - path: finalPathname, + const hostname = options.faucetHost ?? getFaucetHost(client) + if (!hostname) { + throw new XRPLFaucetError('No faucet hostname could be derived') + } + const pathname = options.faucetPath ?? getDefaultFaucetPath(hostname) + const response = await fetch(`https://${hostname}${pathname}`, { method: 'POST', headers: { 'Content-Type': 'application/json', - 'Content-Length': postBody.length, }, - } -} - -// eslint-disable-next-line max-params -- Helper function created for organizational purposes -async function onEnd( - response: IncomingMessage, - chunks: Uint8Array[], - client: Client, - startingBalance: number, - walletToFund: Wallet, - resolve: (response: { wallet: Wallet; balance: number }) => void, - reject: (err: ErrorConstructor | Error | unknown) => void, -): Promise { - const body = Buffer.concat(chunks).toString() + body: JSON.stringify(postBody), + }) + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- It's a FaucetWallet + const body = (await response.json()) as FaucetWallet // "application/json; charset=utf-8" - if (response.headers['content-type']?.startsWith('application/json')) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- We know this is safe and correct - const faucetWallet: FaucetWallet = JSON.parse(body) - const classicAddress = faucetWallet.account.classicAddress - await processSuccessfulResponse( + if ( + response.ok && + response.headers.get('Content-Type')?.startsWith('application/json') + ) { + const classicAddress = body.account.classicAddress + return processSuccessfulResponse( client, classicAddress, walletToFund, startingBalance, - resolve, - reject, - ) - } else { - reject( - new XRPLFaucetError( - `Content type is not \`application/json\`: ${JSON.stringify({ - statusCode: response.statusCode, - contentType: response.headers['content-type'], - body, - })}`, - ), ) } + return processError(response) } -// eslint-disable-next-line max-params, max-lines-per-function -- Only used as a helper function, lines inc due to added balance. +// eslint-disable-next-line max-params -- Only used as a helper function, lines inc due to added balance. async function processSuccessfulResponse( client: Client, classicAddress: string | undefined, walletToFund: Wallet, startingBalance: number, - resolve: (response: { wallet: Wallet; balance: number }) => void, - reject: (err: ErrorConstructor | Error | unknown) => void, -): Promise { +): Promise<{ + wallet: Wallet + balance: number +}> { if (!classicAddress) { - reject(new XRPLFaucetError(`The faucet account is undefined`)) - return + return Promise.reject( + new XRPLFaucetError(`The faucet account is undefined`), + ) } try { // Check at regular interval if the address is enabled on the XRPL and funded @@ -265,31 +210,37 @@ async function processSuccessfulResponse( ) if (updatedBalance > startingBalance) { - resolve({ + return { wallet: walletToFund, - balance: await getUpdatedBalance( - client, - walletToFund.classicAddress, - startingBalance, - ), - }) - } else { - reject( - new XRPLFaucetError( - `Unable to fund address with faucet after waiting ${ - INTERVAL_SECONDS * MAX_ATTEMPTS - } seconds`, - ), - ) + balance: updatedBalance, + } } + throw new XRPLFaucetError( + `Unable to fund address with faucet after waiting ${ + INTERVAL_SECONDS * MAX_ATTEMPTS + } seconds`, + ) } catch (err) { if (err instanceof Error) { - reject(new XRPLFaucetError(err.message)) + throw new XRPLFaucetError(err.message) } - reject(err) + throw err } } +async function processError(response: Response): Promise { + return Promise.reject( + new XRPLFaucetError( + `Request failed: ${JSON.stringify({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- json response could be anything + body: (await response.json()) || {}, + contentType: response.headers.get('Content-Type'), + statusCode: response.status, + })}`, + ), + ) +} + /** * Check at regular interval if the address is enabled on the XRPL and funded. * diff --git a/packages/xrpl/src/index.ts b/packages/xrpl/src/index.ts index 5f5e36b9b8..af3ac74a37 100644 --- a/packages/xrpl/src/index.ts +++ b/packages/xrpl/src/index.ts @@ -8,6 +8,7 @@ export { default as ECDSA } from './ECDSA' export * from './errors' +export { default as fundWallet, FundingOptions } from './Wallet/fundWallet' export { Wallet } from './Wallet' export { keyToRFC1751Mnemonic, rfc1751MnemonicToKey } from './Wallet/rfc1751' diff --git a/packages/xrpl/test/integration/fundWallet.test.ts b/packages/xrpl/test/integration/fundWallet.test.ts index 9b757f51ec..5b88cb1bf3 100644 --- a/packages/xrpl/test/integration/fundWallet.test.ts +++ b/packages/xrpl/test/integration/fundWallet.test.ts @@ -43,8 +43,8 @@ async function generate_faucet_wallet_and_fund_again( account: wallet.classicAddress, }) - assert.equal(dropsToXrp(afterSent.result.account_data.Balance), newBalance) assert(newBalance > balance) + assert.equal(dropsToXrp(afterSent.result.account_data.Balance), newBalance) await api.disconnect() } diff --git a/packages/xrpl/test/webpack.config.js b/packages/xrpl/test/webpack.config.js index eefe6a0c57..07b2a9d28e 100644 --- a/packages/xrpl/test/webpack.config.js +++ b/packages/xrpl/test/webpack.config.js @@ -104,12 +104,9 @@ function webpackForTest(testFileName) { fs: require.resolve('browserify-fs'), buffer: require.resolve('buffer/'), assert: require.resolve('assert/'), - url: require.resolve('url/'), stream: require.resolve('stream-browserify'), crypto: require.resolve('crypto-browserify'), path: require.resolve('path-browserify'), - http: require.resolve('stream-http'), - https: require.resolve('https-browserify'), }, }, } diff --git a/packages/xrpl/webpack.config.js b/packages/xrpl/webpack.config.js index 02f74e7fa3..e3cffc2d6c 100644 --- a/packages/xrpl/webpack.config.js +++ b/packages/xrpl/webpack.config.js @@ -65,11 +65,8 @@ function getDefaultConfiguration() { fallback: { buffer: require.resolve('buffer/'), assert: require.resolve('assert/'), - url: require.resolve('url/'), stream: require.resolve('stream-browserify'), crypto: require.resolve('crypto-browserify'), - https: require.resolve('https-browserify'), - http: require.resolve('stream-http'), }, }, }