@@ -35,6 +35,11 @@ import {
3535import { CallDryRunEffects , XcmDryRunApiError , XcmDryRunEffects } from "@polkadot/types/interfaces"
3636import { Result } from "@polkadot/types"
3737import { ensureValidationSuccess , padFeeByPercentage , u32ToLeBytes } from "./utils"
38+ import { addBreakdown , computeTotals , findInBreakdown , findInBreakdownOrZero , findTotal } from "./fees"
39+ import {
40+ checkDotKsmPoolLiquidityForKusamaToPolkadot ,
41+ checkKsmDotPoolLiquidityForPolkadotToKusama ,
42+ } from "./poolReserves"
3843import { resolveBeneficiary } from "./crypto"
3944import { TransferInterface as KusamaTransferInterface } from "./transfers/forKusama/transferInterface"
4045import { Context } from "."
@@ -264,13 +269,33 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
264269 totalXcmBridgeFee = padFeeByPercentage ( totalXcmBridgeFee , 33n )
265270
266271 let totalFee = totalXcmBridgeFee + bridgeHubDeliveryFee + destinationFee
272+ const sourceSymbol = this . #direction( ) === Direction . ToPolkadot ? "KSM" : "DOT"
273+ // destNativeSymbol is the asset coming OUT of the destination AH swap
274+ // (DOT for kusama→polkadot, KSM for polkadot→kusama).
275+ const destNativeSymbol = this . #direction( ) === Direction . ToPolkadot ? "DOT" : "KSM"
276+
277+ const breakdown : DeliveryFee [ "breakdown" ] = { }
278+ addBreakdown ( breakdown , "xcmBridge" , { amount : totalXcmBridgeFee , symbol : sourceSymbol } )
279+ addBreakdown ( breakdown , "bridgeHubDelivery" , {
280+ amount : bridgeHubDeliveryFee ,
281+ symbol : sourceSymbol ,
282+ } )
283+ addBreakdown ( breakdown , "destinationExecution" , {
284+ amount : destinationFee ,
285+ symbol : sourceSymbol ,
286+ } )
287+ addBreakdown ( breakdown , "destinationExecution" , {
288+ amount : destinationFeeInDestNative ,
289+ symbol : destNativeSymbol ,
290+ } )
291+
292+ const summary = [ { description : "Bridge fee" , amount : totalFee , symbol : sourceSymbol } ]
267293
268294 return {
269295 kind : this . from . kind === "kusama" ? "kusama->polkadot" : "polkadot->kusama" ,
270- xcmBridgeFee : totalXcmBridgeFee ,
271- destinationFee,
272- bridgeHubDeliveryFee,
273- totalFeeInNative : totalFee ,
296+ breakdown,
297+ summary,
298+ totals : computeTotals ( summary ) ,
274299 }
275300 }
276301
@@ -327,7 +352,11 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
327352 tokenLocationOnSource ,
328353 beneficiaryAddressHex ,
329354 amount ,
330- fee . destinationFee ,
355+ findInBreakdown (
356+ fee . breakdown ,
357+ "destinationExecution" ,
358+ fee . kind === "kusama->polkadot" ? "KSM" : "DOT" ,
359+ ) ,
331360 messageId ,
332361 )
333362 } else {
@@ -337,7 +366,11 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
337366 tokenLocationOnSource ,
338367 beneficiaryAddressHex ,
339368 amount ,
340- fee . destinationFee ,
369+ findInBreakdown (
370+ fee . breakdown ,
371+ "destinationExecution" ,
372+ fee . kind === "kusama->polkadot" ? "KSM" : "DOT" ,
373+ ) ,
341374 messageId ,
342375 )
343376 }
@@ -440,7 +473,10 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
440473 const paymentInfo = await tx . paymentInfo ( sourceAccountHex )
441474 const sourceExecutionFee = paymentInfo [ "partialFee" ] . toBigInt ( )
442475
443- if ( sourceExecutionFee + fee . totalFeeInNative > nativeBalance ) {
476+ if (
477+ sourceExecutionFee + findTotal ( fee , fee . kind === "kusama->polkadot" ? "KSM" : "DOT" ) >
478+ nativeBalance
479+ ) {
444480 logs . push ( {
445481 kind : ValidationKind . Error ,
446482 reason : ValidationReason . InsufficientFee ,
@@ -455,7 +491,11 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
455491 if ( this . #direction( ) == Direction . ToPolkadot ) {
456492 destAssetHubXCM = buildKusamaToPolkadotDestAssetHubXCM (
457493 destAssetHub . registry ,
458- fee . destinationFee ,
494+ findInBreakdown (
495+ fee . breakdown ,
496+ "destinationExecution" ,
497+ fee . kind === "kusama->polkadot" ? "KSM" : "DOT" ,
498+ ) ,
459499 registry . assetHubParaId ,
460500 tokenLocation ,
461501 transfer . input . amount ,
@@ -465,7 +505,11 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
465505 } else {
466506 destAssetHubXCM = buildPolkadotToKusamaDestAssetHubXCM (
467507 destAssetHub . registry ,
468- fee . destinationFee ,
508+ findInBreakdown (
509+ fee . breakdown ,
510+ "destinationExecution" ,
511+ fee . kind === "kusama->polkadot" ? "KSM" : "DOT" ,
512+ ) ,
469513 registry . assetHubParaId ,
470514 tokenLocation ,
471515 transfer . input . amount ,
@@ -512,6 +556,53 @@ export class KusamaTransfer<T extends EthereumProviderTypes> implements KusamaTr
512556 }
513557 }
514558
559+ const destAssetHubImpl = await this . context . paraImplementation ( destAssetHub )
560+ if ( this . #direction( ) === Direction . ToPolkadot ) {
561+ const requiredDotOut = findInBreakdownOrZero (
562+ fee . breakdown ,
563+ "destinationExecution" ,
564+ "DOT" ,
565+ )
566+ if ( requiredDotOut > 0n ) {
567+ const reserveCheck = await checkDotKsmPoolLiquidityForKusamaToPolkadot (
568+ destAssetHubImpl ,
569+ requiredDotOut ,
570+ )
571+ if ( ! reserveCheck . ok ) {
572+ logs . push ( {
573+ kind : ValidationKind . Error ,
574+ reason : ValidationReason . InsufficientPoolReserves ,
575+ message :
576+ reserveCheck . reason === "pool-missing"
577+ ? `${ reserveCheck . pool } pool does not exist on Asset Hub.`
578+ : `${ reserveCheck . pool } pool on Asset Hub has insufficient liquidity (need ${ reserveCheck . requiredOut } , have ${ reserveCheck . reserveOut } ).` ,
579+ } )
580+ }
581+ }
582+ } else {
583+ const requiredKsmOut = findInBreakdownOrZero (
584+ fee . breakdown ,
585+ "destinationExecution" ,
586+ "KSM" ,
587+ )
588+ if ( requiredKsmOut > 0n ) {
589+ const reserveCheck = await checkKsmDotPoolLiquidityForPolkadotToKusama (
590+ destAssetHubImpl ,
591+ requiredKsmOut ,
592+ )
593+ if ( ! reserveCheck . ok ) {
594+ logs . push ( {
595+ kind : ValidationKind . Error ,
596+ reason : ValidationReason . InsufficientPoolReserves ,
597+ message :
598+ reserveCheck . reason === "pool-missing"
599+ ? `${ reserveCheck . pool } pool does not exist on Asset Hub.`
600+ : `${ reserveCheck . pool } pool on Asset Hub has insufficient liquidity (need ${ reserveCheck . requiredOut } , have ${ reserveCheck . reserveOut } ).` ,
601+ } )
602+ }
603+ }
604+ }
605+
515606 const success = logs . find ( ( l ) => l . kind === ValidationKind . Error ) === undefined
516607
517608 return {
0 commit comments