mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-04 13:05:49 +00:00
feat: remove 3 http related polyfills (#2375)
Switch to using fetch for browser and `node-fetch` for node for the faucet calls. This reduces the webpack bundle by 3.2% or 16.5kb gzipped. The fundWallet code has been refactored to be much more straight forward due to not having to do such low level operations. This improves the frontend setup process by no longer requiring several polyfills such as `url`, `stream-http`, and `https-browserify`.
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
|
||||
77
package-lock.json
generated
77
package-lock.json
generated
@@ -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": "^5.0.0",
|
||||
"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"
|
||||
@@ -5491,6 +5488,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",
|
||||
@@ -6041,7 +6065,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"
|
||||
@@ -6051,7 +6074,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"
|
||||
@@ -10743,8 +10765,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",
|
||||
@@ -13119,7 +13140,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"
|
||||
}
|
||||
@@ -13961,7 +13981,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",
|
||||
@@ -15169,7 +15189,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"
|
||||
},
|
||||
@@ -15884,7 +15903,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"
|
||||
}
|
||||
@@ -16073,7 +16091,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",
|
||||
@@ -16518,7 +16535,7 @@
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip32": "^2.0.6",
|
||||
"bip39": "^3.0.4",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"ripple-address-codec": "^4.3.1",
|
||||
"ripple-binary-codec": "^1.11.0",
|
||||
"ripple-keypairs": "^1.3.1",
|
||||
@@ -20957,6 +20974,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",
|
||||
@@ -21393,7 +21428,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"
|
||||
@@ -21403,7 +21437,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"
|
||||
@@ -25062,8 +25095,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",
|
||||
@@ -26953,8 +26985,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.4",
|
||||
@@ -27589,7 +27620,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",
|
||||
@@ -28526,7 +28557,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"
|
||||
}
|
||||
@@ -29043,8 +29073,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.90.0",
|
||||
@@ -29163,7 +29192,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",
|
||||
@@ -29405,6 +29433,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",
|
||||
|
||||
@@ -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": "^5.0.0",
|
||||
"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"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"bignumber.js": "^9.0.0",
|
||||
"bip32": "^2.0.6",
|
||||
"bip39": "^3.0.4",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"cross-fetch": "^4.0.0",
|
||||
"ripple-address-codec": "^4.3.1",
|
||||
"ripple-binary-codec": "^1.11.0",
|
||||
"ripple-keypairs": "^1.3.1",
|
||||
|
||||
@@ -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, 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<void> {
|
||||
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<void> {
|
||||
): 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<never> {
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Client, ClientOptions } from '.'
|
||||
* @deprecated since version 2.2.0.
|
||||
* Will be deleted in version 3.0.0.
|
||||
*
|
||||
* Currently this implementation does not provide better reliability.
|
||||
* Currently, this implementation does not provide better reliability.
|
||||
* To get better reliability, implement reconnect/error handling logic
|
||||
* and choose a reliable endpoint.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,7 @@ export { default as ECDSA } from './ECDSA'
|
||||
|
||||
export * from './errors'
|
||||
|
||||
export { default as fundWallet, FundingOptions } from './Wallet/fundWallet'
|
||||
export { Wallet } from './Wallet'
|
||||
|
||||
export { walletFromSecretNumbers } from './Wallet/walletFromSecretNumbers'
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -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'),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user