feat: add starting balance to faucet wallet (#1702)

* refactor: add starting balance to faucet wallet and change `generateFaucetWallet()` to `fundWallet()`
This commit is contained in:
Mukul Jangid
2021-10-08 15:14:56 -04:00
committed by GitHub
parent 43c71f4d9b
commit cb55d2eacb
5 changed files with 49 additions and 36 deletions

View File

@@ -97,7 +97,7 @@ import {
submitSignedReliable,
} from '../sugar/submit'
import { ensureClassicAddress } from '../sugar/utils'
import generateFaucetWallet from '../wallet/generateFaucetWallet'
import fundWallet from '../wallet/fundWallet'
import {
Connection,
@@ -545,7 +545,7 @@ class Client extends EventEmitter {
public getBalances = getBalances
public getOrderbook = getOrderbook
public generateFaucetWallet = generateFaucetWallet
public fundWallet = fundWallet
}
export { Client }

View File

@@ -15,6 +15,11 @@ interface FaucetWallet {
balance: number
}
interface WalletWithStartingBalance {
wallet: Wallet
balance: number
}
enum FaucetNetwork {
Testnet = 'faucet.altnet.rippletest.net',
Devnet = 'faucet.devnet.rippletest.net',
@@ -33,16 +38,16 @@ const MAX_ATTEMPTS = 20
* @returns A Wallet on the Testnet or Devnet that contains some amount of XRP.
* @throws When either Client isn't connected or unable to fund wallet address.
*/
async function generateFaucetWallet(
async function fundWallet(
this: Client,
wallet?: Wallet,
): Promise<Wallet> {
): Promise<WalletWithStartingBalance> {
if (!this.isConnected()) {
throw new RippledError('Client not connected, cannot call faucet')
}
// Generate a new Wallet if no existing Wallet is provided or its address is invalid to fund
const fundWallet =
const walletToFund =
wallet && isValidClassicAddress(wallet.classicAddress)
? wallet
: Wallet.generate()
@@ -51,7 +56,7 @@ async function generateFaucetWallet(
const postBody = Buffer.from(
new TextEncoder().encode(
JSON.stringify({
destination: fundWallet.classicAddress,
destination: walletToFund.classicAddress,
}),
),
)
@@ -59,7 +64,7 @@ async function generateFaucetWallet(
let startingBalance = 0
try {
startingBalance = Number(
await getAddressXrpBalance(this, fundWallet.classicAddress),
await getAddressXrpBalance(this, walletToFund.classicAddress),
)
} catch {
/* startingBalance remains '0' */
@@ -68,7 +73,7 @@ async function generateFaucetWallet(
// Options to pass to https.request
const options = getOptions(this, postBody)
return returnPromise(options, this, startingBalance, fundWallet, postBody)
return returnPromise(options, this, startingBalance, walletToFund, postBody)
}
// eslint-disable-next-line max-params -- Helper function created for organizational purposes
@@ -76,9 +81,9 @@ async function returnPromise(
options: RequestOptions,
client: Client,
startingBalance: number,
fundWallet: Wallet,
walletToFund: Wallet,
postBody: Buffer,
): Promise<Wallet> {
): Promise<WalletWithStartingBalance> {
return new Promise((resolve, reject) => {
const request = httpsRequest(options, (response) => {
const chunks: Uint8Array[] = []
@@ -90,7 +95,7 @@ async function returnPromise(
chunks,
client,
startingBalance,
fundWallet,
walletToFund,
resolve,
reject,
),
@@ -126,8 +131,8 @@ async function onEnd(
chunks: Uint8Array[],
client: Client,
startingBalance: number,
fundWallet: Wallet,
resolve: (wallet: Wallet) => void,
walletToFund: Wallet,
resolve: (response: WalletWithStartingBalance) => void,
reject: (err: ErrorConstructor | Error | unknown) => void,
): Promise<void> {
const body = Buffer.concat(chunks).toString()
@@ -138,7 +143,7 @@ async function onEnd(
client,
body,
startingBalance,
fundWallet,
walletToFund,
resolve,
reject,
)
@@ -155,13 +160,13 @@ async function onEnd(
}
}
// eslint-disable-next-line max-params -- Only used as a helper function
// eslint-disable-next-line max-params, max-lines-per-function -- Only used as a helper function, lines inc due to added balance.
async function processSuccessfulResponse(
client: Client,
body: string,
startingBalance: number,
fundWallet: Wallet,
resolve: (wallet: Wallet) => void,
walletToFund: Wallet,
resolve: (response: WalletWithStartingBalance) => void,
reject: (err: ErrorConstructor | Error | unknown) => void,
): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- We know this is safe and correct
@@ -174,14 +179,21 @@ async function processSuccessfulResponse(
}
try {
// Check at regular interval if the address is enabled on the XRPL and funded
const isFunded = await hasAddressBalanceIncreased(
const updatedBalance = await getUpdatedBalance(
client,
classicAddress,
startingBalance,
)
if (isFunded) {
resolve(fundWallet)
if (updatedBalance > startingBalance) {
resolve({
wallet: walletToFund,
balance: await getUpdatedBalance(
client,
walletToFund.getClassicAddress(),
startingBalance,
),
})
} else {
reject(
new XRPLFaucetError(
@@ -237,18 +249,18 @@ async function getAddressXrpBalance(
* @param originalBalance - The initial balance before the funding.
* @returns A Promise boolean.
*/
async function hasAddressBalanceIncreased(
async function getUpdatedBalance(
client: Client,
address: string,
originalBalance: number,
): Promise<boolean> {
): Promise<number> {
return new Promise((resolve, reject) => {
let attempts = MAX_ATTEMPTS
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- Not actually misused here, different resolve
const interval = setInterval(async () => {
if (attempts < 0) {
clearInterval(interval)
resolve(false)
resolve(originalBalance)
} else {
attempts -= 1
}
@@ -263,7 +275,7 @@ async function hasAddressBalanceIncreased(
if (newBalance > originalBalance) {
clearInterval(interval)
resolve(true)
resolve(newBalance)
}
} catch (err) {
clearInterval(interval)
@@ -302,7 +314,7 @@ function getFaucetUrl(client: Client): FaucetNetwork | undefined {
throw new XRPLFaucetError('Faucet URL is not defined or inferrable.')
}
export default generateFaucetWallet
export default fundWallet
const _private = {
FaucetNetwork,

View File

@@ -6,14 +6,14 @@ import { Client, isValidClassicAddress, isValidXAddress } from 'xrpl-local'
// how long before each test case times out
const TIMEOUT = 60000
// This test is reliant on external networks, and as such may be flaky.
describe('generateFaucetWallet', function () {
describe('fundWallet', function () {
this.timeout(TIMEOUT)
it('submit generates a testnet wallet', async function () {
const api = new Client('wss://s.altnet.rippletest.net:51233')
await api.connect()
const wallet = await api.generateFaucetWallet()
const { wallet, balance } = await api.fundWallet()
assert.notEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
@@ -23,16 +23,16 @@ describe('generateFaucetWallet', function () {
command: 'account_info',
account: wallet.classicAddress,
})
assert.equal(info.result.account_data.Balance, '1000000000')
assert.equal(info.result.account_data.Balance, balance)
await api.generateFaucetWallet(wallet)
const { balance: newBalance } = await api.fundWallet(wallet)
const afterSent = await api.request({
command: 'account_info',
account: wallet.classicAddress,
})
assert.equal(afterSent.result.account_data.Balance, '2000000000')
assert.equal(afterSent.result.account_data.Balance, newBalance)
await api.disconnect()
})
@@ -40,7 +40,7 @@ describe('generateFaucetWallet', function () {
const api = new Client('wss://s.devnet.rippletest.net:51233')
await api.connect()
const wallet = await api.generateFaucetWallet()
const { wallet, balance } = await api.fundWallet()
assert.notEqual(wallet, undefined)
assert(isValidClassicAddress(wallet.classicAddress))
@@ -50,15 +50,16 @@ describe('generateFaucetWallet', function () {
command: 'account_info',
account: wallet.classicAddress,
})
assert.equal(info.result.account_data.Balance, '1000000000')
await api.generateFaucetWallet(wallet)
assert.equal(info.result.account_data.Balance, balance)
const { balance: newBalance } = await api.fundWallet(wallet)
const afterSent = await api.request({
command: 'account_info',
account: wallet.classicAddress,
})
assert.equal(afterSent.result.account_data.Balance, '2000000000')
assert.equal(afterSent.result.account_data.Balance, newBalance)
await api.disconnect()
})

View File

@@ -37,5 +37,5 @@ export * from './requests/submit'
export * from './requests/tx'
export * from './requests/utility'
export * from './generateFaucetWallet'
export * from './fundWallet'
export * from './integration'

View File

@@ -1,6 +1,6 @@
import { assert } from 'chai'
import { _private } from '../../src/wallet/generateFaucetWallet'
import { _private } from '../../src/wallet/fundWallet'
import { setupClient, teardownClient } from '../setupClient'
const { FaucetNetwork, getFaucetUrl } = _private