diff --git a/examples/substrate/use-feeProxy/README.md b/examples/substrate/use-feeProxy/README.md index aa5246c..63a5324 100644 --- a/examples/substrate/use-feeProxy/README.md +++ b/examples/substrate/use-feeProxy/README.md @@ -31,4 +31,7 @@ pnpm call:callProxyExtrinsic # `feeProxy.callWithFeePreferences` that wraps around `futurepass.proxyExtrinsic` then `emv.call` pnpm call:callProxyExtrinsicEVMCall +# `feeProxy.callWithFeePreferences` that wraps around `xrplBridge.withdrawXrp` +pnpm call:callXRPLBridgeWithdraw + ``` diff --git a/examples/substrate/use-feeProxy/package.json b/examples/substrate/use-feeProxy/package.json index ed50513..32bbb60 100644 --- a/examples/substrate/use-feeProxy/package.json +++ b/examples/substrate/use-feeProxy/package.json @@ -5,6 +5,7 @@ "call:callProxyExtrinsic": "pnpm call src/callProxyExtrinsic.ts", "call:callBatchAll": "pnpm call src/callBatchAll.ts", "call:callEVMCall": "pnpm call src/callEVMCall.ts", - "call:callProxyExtrinsicEVMCall": "pnpm call src/callProxyExtrinsicEVMCall.ts" + "call:callProxyExtrinsicEVMCall": "pnpm call src/callProxyExtrinsicEVMCall.ts", + "call:callXRPLBridgeWithdraw": "pnpm call src/callXRPLBridgeWithdraw.ts" } } diff --git a/examples/substrate/use-feeProxy/src/callXRPLBridgeWithdraw.ts b/examples/substrate/use-feeProxy/src/callXRPLBridgeWithdraw.ts new file mode 100644 index 0000000..83a6535 --- /dev/null +++ b/examples/substrate/use-feeProxy/src/callXRPLBridgeWithdraw.ts @@ -0,0 +1,93 @@ +import { filterExtrinsicEvents } from "@trne/utils/filterExtrinsicEvents"; +import { formatEventData } from "@trne/utils/formatEventData"; +import { ROOT_ASSET_ID, XRP_ASSET_ID } from "@trne/utils/porcini-assets"; +import { sendExtrinsic } from "@trne/utils/sendExtrinsic"; +import { withChainApi } from "@trne/utils/withChainApi"; + +interface AmountsIn { + Ok: [number, number]; +} + +/** + * Use `feeProxy.callWithFeePreferences` to trigger `xrplBridge.withdrawXrp` call, and pay gas + * in ROOT token. + * + * Assumes the caller has ROOT balance. + */ +withChainApi("porcini", async (api, caller, logger) => { + /** + * 1. Create `xrplBridge.withdrawXrp` call + */ + // + logger.info( + { + parameters: { + amount: 1000000, + destination: "0x72ee785458b89d5ec64bec8410c958602e6f7673", + }, + }, + `create a "xrplBridge.withdrawXrp"` + ); + const bridgeWithdrawalCall = api.tx.xrplBridge.withdrawXrp(10, "0x72ee785458b89d5ec64bec8410c958602e6f7673"); + + /** + * 2. Determine the `maxPayment` in ROOT by estimate the gas cost and use `dex` to get a quote + */ + // we need a dummy feeProxy call (with maxPayment=0) to do a proper fee estimation + const feeProxyCallForEstimation = api.tx.feeProxy.callWithFeePreferences( + ROOT_ASSET_ID, + 0, + bridgeWithdrawalCall + ); + const paymentInfo = await feeProxyCallForEstimation.paymentInfo(caller.address); + const estimatedFee = paymentInfo.partialFee.toString(); + + // query the the `dex` to determine the `maxPayment` you are willing to pay + const { + Ok: [amountIn], + } = (await api.rpc.dex.getAmountsIn(estimatedFee, [ + ROOT_ASSET_ID, + XRP_ASSET_ID, + ])) as unknown as AmountsIn; + + // allow a buffer to avoid slippage, 5% + const maxPayment = Number(amountIn * 1.05).toFixed(); + + /** + * 3. Create and dispatch `feeProxy.callWithFeePreferences` extrinsic + */ + logger.info( + { + parameters: { + paymentAsset: ROOT_ASSET_ID, + maxPayment, + call: bridgeWithdrawalCall.toJSON(), + }, + }, + `create a "feeProxy.callWithFeePreferences"` + ); + const feeProxyCall = api.tx.feeProxy.callWithFeePreferences( + ROOT_ASSET_ID, + maxPayment, + bridgeWithdrawalCall + ); + + logger.info(`dispatch extrinsic from caller="${caller.address}"`); + const { result, extrinsicId } = await sendExtrinsic(feeProxyCall, caller, { log: logger }); + const [proxyEvent, withdrawalEvent] = filterExtrinsicEvents(result.events, [ + "FeeProxy.CallWithFeePreferences", + "XrplBridge.WithdrawRequest" + ]); + + logger.info( + { + result: { + extrinsicId, + blockNumber: result.blockNumber, + proxyEvent: formatEventData(proxyEvent.event), + xrplWithdrawlEvent: formatEventData(withdrawalEvent.event), + }, + }, + "receive result" + ); +}); diff --git a/packages/utils/src/porcini-assets.ts b/packages/utils/src/porcini-assets.ts index 233989e..c4a819f 100644 --- a/packages/utils/src/porcini-assets.ts +++ b/packages/utils/src/porcini-assets.ts @@ -2,3 +2,4 @@ export const SYLO_ASSET_ID = 3_172; export const ASTO_ASSET_ID = 17_508; export const XRP_ASSET_ID = 2; +export const ROOT_ASSET_ID = 1;