mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-08 22:05:50 +00:00
201 lines
6.5 KiB
TypeScript
201 lines
6.5 KiB
TypeScript
import * as React from 'react';
|
|
import { useThemeHooks } from '@redocly/theme/core/hooks';
|
|
import { clsx } from 'clsx'
|
|
|
|
import { Client, type Wallet, type TxResponse, dropsToXrp } from 'xrpl'
|
|
import { errorNotif, TESTNET_URL } from '../utils'
|
|
|
|
|
|
export interface InitializationProps {
|
|
existingClient: Client | undefined,
|
|
alert, // From useAlert()
|
|
setClient: React.Dispatch<React.SetStateAction<Client | undefined>>,
|
|
setBalance: React.Dispatch<React.SetStateAction<number>>,
|
|
setSendingWallet: React.Dispatch<React.SetStateAction<Wallet | undefined>>,
|
|
setIsInitEnabled: React.Dispatch<React.SetStateAction<boolean>>,
|
|
setConnectionReady: React.Dispatch<React.SetStateAction<boolean>>,
|
|
partialPaymentParams: {
|
|
setPpIssuerWallet: React.Dispatch<React.SetStateAction<Wallet | undefined>>,
|
|
setPpWidthPercent: React.Dispatch<React.SetStateAction<number>>,
|
|
ppCurrencyCode: string
|
|
}
|
|
}
|
|
|
|
async function setUpForPartialPayments
|
|
(
|
|
client: Client,
|
|
sendingWallet: Wallet,
|
|
setPpIssuerWallet: React.Dispatch<React.SetStateAction<Wallet | undefined>>,
|
|
setPpWidthPercent: React.Dispatch<React.SetStateAction<number>>,
|
|
ppCurrencyCode: string,
|
|
) {
|
|
console.debug("Starting partial payment setup...")
|
|
|
|
// Causing loader to appear because no longer 0%
|
|
setPpWidthPercent(1)
|
|
let ppIssuerWallet;
|
|
|
|
// 1. Get a funded address to use as issuer
|
|
try {
|
|
ppIssuerWallet = (await client.fundWallet()).wallet
|
|
setPpIssuerWallet(ppIssuerWallet)
|
|
} catch(error) {
|
|
console.log("Error getting issuer address for partial payments:", error)
|
|
return
|
|
}
|
|
|
|
setPpWidthPercent(20)
|
|
|
|
// 2. Set Default Ripple on issuer
|
|
let resp: TxResponse = await client.submitAndWait({
|
|
TransactionType: "AccountSet",
|
|
Account: ppIssuerWallet.address,
|
|
SetFlag: 8 // asfDefaultRipple
|
|
}, { wallet: ppIssuerWallet })
|
|
if (resp === undefined) {
|
|
console.log("Couldn't set Default Ripple for partial payment issuer")
|
|
return
|
|
}
|
|
setPpWidthPercent(40)
|
|
|
|
// 3. Make a trust line from sending address to issuer
|
|
resp = await client.submitAndWait({
|
|
TransactionType: "TrustSet",
|
|
Account: sendingWallet.address,
|
|
LimitAmount: {
|
|
currency: ppCurrencyCode,
|
|
value: "1000000000", // arbitrarily, 1 billion fake currency
|
|
issuer: ppIssuerWallet.address
|
|
}
|
|
}, { wallet: sendingWallet })
|
|
if (resp === undefined) {
|
|
console.log("Error making trust line to partial payment issuer")
|
|
return
|
|
}
|
|
setPpWidthPercent(60)
|
|
|
|
// 4. Issue fake currency to main sending address
|
|
resp = await client.submitAndWait({
|
|
TransactionType: "Payment",
|
|
Account: ppIssuerWallet.address,
|
|
Destination: sendingWallet.address,
|
|
Amount: {
|
|
currency: ppCurrencyCode,
|
|
value: "1000000000",
|
|
issuer: ppIssuerWallet.address
|
|
}
|
|
}, { wallet: ppIssuerWallet })
|
|
if (resp === undefined) {
|
|
console.log("Error sending fake currency from partial payment issuer")
|
|
return
|
|
}
|
|
setPpWidthPercent(80)
|
|
|
|
// 5. Place offer to buy issued currency for XRP
|
|
// When sending the partial payment, the sender consumes their own offer (!)
|
|
// so they end up paying themselves issued currency then delivering XRP.
|
|
resp = await client.submitAndWait({
|
|
TransactionType: "OfferCreate",
|
|
Account: sendingWallet.address,
|
|
TakerGets: "1000000000000000", // 1 billion XRP
|
|
TakerPays: {
|
|
currency: ppCurrencyCode,
|
|
value: "1000000000",
|
|
issuer: ppIssuerWallet.address
|
|
}
|
|
}, { wallet: sendingWallet })
|
|
if (resp === undefined) {
|
|
console.log("Error placing order to enable partial payments")
|
|
return
|
|
}
|
|
setPpWidthPercent(100)
|
|
|
|
// Done. Enable "Send Partial Payment" button
|
|
console.log("Done getting ready to send partial payments.")
|
|
}
|
|
|
|
async function onInitClick(
|
|
props: InitializationProps
|
|
): Promise<void> {
|
|
|
|
const {
|
|
existingClient,
|
|
alert, // From useAlert()
|
|
setClient,
|
|
setBalance,
|
|
setSendingWallet,
|
|
setIsInitEnabled,
|
|
setConnectionReady,
|
|
partialPaymentParams
|
|
} = {...props}
|
|
|
|
if(existingClient) {
|
|
console.log("Already initializing!")
|
|
return
|
|
}
|
|
|
|
console.log("Connecting to Testnet WebSocket...")
|
|
const client = new Client(TESTNET_URL)
|
|
client.on('connected', () => {
|
|
setConnectionReady(true)
|
|
})
|
|
|
|
client.on('disconnected', (code) => {
|
|
setConnectionReady(false)
|
|
})
|
|
setClient(client)
|
|
await client.connect()
|
|
|
|
console.debug("Getting a sending address from the faucet...")
|
|
try {
|
|
const fundResponse = await client.fundWallet()
|
|
const sendingWallet = fundResponse.wallet
|
|
setSendingWallet(sendingWallet)
|
|
// Using Number(...) can result in loss of precision since Number is smaller than the precision of XRP,
|
|
// but this shouldn't affect the learning tool as that much XRP is not given to any test account.
|
|
setBalance(Number(dropsToXrp(fundResponse.balance)))
|
|
setIsInitEnabled(false)
|
|
await setUpForPartialPayments(
|
|
client,
|
|
sendingWallet,
|
|
partialPaymentParams.setPpIssuerWallet,
|
|
partialPaymentParams.setPpWidthPercent,
|
|
partialPaymentParams.ppCurrencyCode,
|
|
)
|
|
} catch(error) {
|
|
console.error(error)
|
|
errorNotif(alert, "There was an error with the XRP Ledger Testnet Faucet. Reload this page to try again.")
|
|
return
|
|
}
|
|
}
|
|
|
|
export function InitButton({
|
|
isInitEnabled,
|
|
toInit
|
|
}: {
|
|
isInitEnabled: boolean,
|
|
toInit: InitializationProps
|
|
}): React.JSX.Element {
|
|
const { useTranslate } = useThemeHooks();
|
|
const { translate } = useTranslate()
|
|
|
|
return (<div className="form-group">
|
|
<button className={clsx("btn btn-primary form-control", isInitEnabled ? "" : "disabled")}
|
|
type="button" id="init_button"
|
|
onClick={() => {
|
|
onInitClick(
|
|
toInit,
|
|
)
|
|
}}
|
|
disabled={!isInitEnabled}
|
|
title={isInitEnabled ? "" : "done"}>
|
|
{translate("Initialize")}
|
|
</button>
|
|
{!isInitEnabled && (<div> <i className="fa fa-check-circle"></i></div>)}
|
|
|
|
<small className="form-text text-muted">
|
|
{translate("Set up the necessary Testnet XRP addresses to send test payments.")}
|
|
</small>
|
|
</div>)
|
|
}
|