mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-21 04:05:49 +00:00
Update convert-template Add basic page Add it to the sidebar Fix a broken link Fix translate usage and add linebreaks Fix indents Add basic sidebar Port over init button logic Migrate submit_and_notify and start dest addr Get the payment button working Componentize the Send XRP Payment button Add basic escrow button Componentize payment channel Migrate Trust For Migrate Send Issued Currency Add partial payment progres bar logic Use the component for the partial payment Add support for escrow finish Log transactions in sidebar Debugging partial payment setup Add support for changing destinationAddress Finish adding bootstrap growl notifications Use 'client' instead of 'api' Move DestinationAddressInput to component and remove ids Split the page into separate files Remove the old files for this page Update links Add space Add comment deprecating bootstrap-growl jquery Fix typing errors PR Comments Pt 1 Small PR fixes Encapsulate isValidDestinationAddress
200 lines
6.4 KiB
TypeScript
200 lines
6.4 KiB
TypeScript
import * as React from 'react';
|
|
import { useTranslate } from '@portal/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 { 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>)
|
|
}
|