@@ -2,8 +2,22 @@ import { expect } from 'bun:test';
2
2
import { INITIAL_BALANCES } from '@/constants' ;
3
3
import type { PolimecManager } from '@/managers/PolimecManager' ;
4
4
import type { PolkadotHubManager } from '@/managers/PolkadotHubManager' ;
5
- import { Asset , type BalanceCheck , Chains , getVersionedAssets } from '@/types' ;
6
- import { createTransferData } from '@/utils' ;
5
+ import {
6
+ Asset ,
7
+ AssetSourceRelation ,
8
+ type BalanceCheck ,
9
+ Chains ,
10
+ ParaId ,
11
+ type PolimecBalanceCheck ,
12
+ getVersionedAssets ,
13
+ } from '@/types' ;
14
+ import { createTransferData , unwrap } from '@/utils' ;
15
+ import {
16
+ DispatchRawOrigin ,
17
+ XcmVersionedAssetId ,
18
+ type XcmVersionedLocation ,
19
+ type XcmVersionedXcm ,
20
+ } from '@polkadot-api/descriptors' ;
7
21
import { BaseTransferTest , type TransferOptions } from './BaseTransfer' ;
8
22
9
23
export class PolimecToHubTransfer extends BaseTransferTest {
@@ -14,7 +28,7 @@ export class PolimecToHubTransfer extends BaseTransferTest {
14
28
super ( sourceManager , destManager ) ;
15
29
}
16
30
17
- async executeTransfer ( { account, assets } : TransferOptions ) {
31
+ async executeTransfer ( { account, assets, fee_asset_item } : TransferOptions ) {
18
32
const [ sourceBlock , destBlock ] = await Promise . all ( [
19
33
this . sourceManager . getBlockNumber ( ) ,
20
34
this . destManager . getBlockNumber ( ) ,
@@ -25,12 +39,14 @@ export class PolimecToHubTransfer extends BaseTransferTest {
25
39
toChain : Chains . PolkadotHub ,
26
40
assets : versioned_assets ,
27
41
recv : account ,
42
+ fee_asset_item : fee_asset_item ?? 0 ,
28
43
} ) ;
29
44
30
45
const res = await this . sourceManager
31
46
. getXcmPallet ( )
32
47
. transfer_assets ( data )
33
48
. signAndSubmit ( this . sourceManager . getSigner ( account ) ) ;
49
+ console . dir ( res , { depth : null } ) ;
34
50
35
51
expect ( res . ok ) . toBeTrue ( ) ;
36
52
return { sourceBlock, destBlock } ;
@@ -48,23 +64,129 @@ export class PolimecToHubTransfer extends BaseTransferTest {
48
64
return { asset_balances : [ { source, destination } ] } ;
49
65
}
50
66
51
- verifyFinalBalances (
52
- initialBalances : BalanceCheck [ ] ,
53
- finalBalances : BalanceCheck [ ] ,
54
- options : TransferOptions ,
67
+ // verifyFinalBalances(
68
+ // initialBalances: BalanceCheck[],
69
+ // finalBalances: BalanceCheck[],
70
+ // options: TransferOptions,
71
+ // ) {
72
+ // // TODO: At the moment we exclude fees from the balance check since the PAPI team is wotking on some utilies to calculate fees.
73
+ // const initialBalance =
74
+ // options.assets[0][0] === Asset.DOT
75
+ // ? INITIAL_BALANCES.DOT
76
+ // : options.assets[0][0] === Asset.USDT
77
+ // ? INITIAL_BALANCES.USDT
78
+ // : INITIAL_BALANCES.USDC;
79
+ // for (let i = 0; i < options.assets.length; i++) {
80
+ // expect(initialBalances[i].destination).toBe(0n);
81
+ // expect(initialBalances[i].source).toBe(initialBalance);
82
+ // expect(finalBalances[i].source).toBeLessThan(initialBalances[i].source);
83
+ // expect(finalBalances[i].destination).toBeGreaterThan(initialBalances[i].destination);
84
+ // }
85
+ // }
86
+
87
+ async verifyFinalBalances (
88
+ assetInitialBalances : PolimecBalanceCheck [ ] ,
89
+ assetFinalBalances : PolimecBalanceCheck [ ] ,
90
+ transferOptions : TransferOptions ,
55
91
) {
56
- // TODO: At the moment we exclude fees from the balance check since the PAPI team is wotking on some utilies to calculate fees.
57
- const initialBalance =
58
- options . assets [ 0 ] [ 0 ] === Asset . DOT
59
- ? INITIAL_BALANCES . DOT
60
- : options . assets [ 0 ] [ 0 ] === Asset . USDT
61
- ? INITIAL_BALANCES . USDT
62
- : INITIAL_BALANCES . USDC ;
63
- for ( let i = 0 ; i < options . assets . length ; i ++ ) {
64
- expect ( initialBalances [ i ] . destination ) . toBe ( 0n ) ;
65
- expect ( initialBalances [ i ] . source ) . toBe ( initialBalance ) ;
66
- expect ( finalBalances [ i ] . source ) . toBeLessThan ( initialBalances [ i ] . source ) ;
67
- expect ( finalBalances [ i ] . destination ) . toBeGreaterThan ( initialBalances [ i ] . destination ) ;
92
+ const native_extrinsic_fee_amount = await this . sourceManager . getTransactionFee ( ) ;
93
+ const source_xcm_asset_fee_amount = await this . sourceManager . getXcmFee ( ) ;
94
+ const dest_xcm_asset_fee_amount = await this . calculatePolkadotHubXcmFee ( transferOptions ) ;
95
+
96
+ const fee_asset = transferOptions . assets [ 0 ] [ 0 ] ;
97
+
98
+ for ( let i = 0 ; i < transferOptions . assets . length ; i ++ ) {
99
+ const initialBalances = assetInitialBalances [ i ] ;
100
+ const finalBalances = assetFinalBalances [ i ] ;
101
+ const send_amount = transferOptions . assets [ i ] [ 1 ] ;
102
+ const asset = transferOptions . assets [ i ] [ 0 ] ;
103
+
104
+ let expectedSourceBalanceSpent = send_amount ;
105
+ let expectedDestBalanceSpent = 0n ;
106
+ let expectedTreasuryBalanceGained = 0n ;
107
+
108
+ if ( asset === Asset . PLMC ) {
109
+ expectedSourceBalanceSpent += native_extrinsic_fee_amount + source_xcm_asset_fee_amount ;
110
+ }
111
+ if ( asset === fee_asset ) {
112
+ expectedDestBalanceSpent += dest_xcm_asset_fee_amount ;
113
+ expectedTreasuryBalanceGained += dest_xcm_asset_fee_amount ;
114
+ }
115
+
116
+ expect ( finalBalances . source ) . toBe ( initialBalances . source - expectedSourceBalanceSpent ) ;
117
+ expect ( finalBalances . destination ) . toBe (
118
+ initialBalances . destination + send_amount - expectedDestBalanceSpent ,
119
+ ) ;
120
+ expect ( finalBalances . treasury ) . toBe ( initialBalances . treasury + expectedTreasuryBalanceGained ) ;
121
+ }
122
+ }
123
+
124
+ async calculatePolkadotHubXcmFee ( transferOptions : TransferOptions ) : Promise < bigint > {
125
+ let destinationExecutionFee : bigint ;
126
+
127
+ const sourceApi = this . sourceManager . getApi ( Chains . Polimec ) ;
128
+ const destApi = this . destManager . getApi ( Chains . PolkadotHub ) ;
129
+
130
+ const versioned_assets = getVersionedAssets ( transferOptions . assets ) ;
131
+ const transferData = createTransferData ( {
132
+ toChain : Chains . Polimec ,
133
+ assets : versioned_assets ,
134
+ recv : transferOptions . account ,
135
+ fee_asset_item : transferOptions . fee_asset_item ?? 0 ,
136
+ } ) ;
137
+
138
+ let remoteFeeAssetId : XcmVersionedAssetId ;
139
+ const feeAsset = unwrap ( transferOptions . assets . at ( transferData . fee_asset_item ) ) ;
140
+ if ( feeAsset [ 2 ] === AssetSourceRelation . Self ) {
141
+ feeAsset [ 2 ] = AssetSourceRelation . Sibling ;
142
+ }
143
+ const versioned_asset = getVersionedAssets ( [ feeAsset ] ) ;
144
+ if ( versioned_asset . type === 'V4' ) {
145
+ remoteFeeAssetId = XcmVersionedAssetId . V4 ( unwrap ( versioned_asset . value . at ( 0 ) ) . id ) ;
146
+ } else {
147
+ throw new Error ( 'Invalid versioned assets' ) ;
148
+ }
149
+
150
+ const localDryRunResult = await sourceApi . apis . DryRunApi . dry_run_call (
151
+ { type : 'system' , value : DispatchRawOrigin . Signed ( transferOptions . account ) } ,
152
+ { type : 'PolkadotXcm' , value : { type : 'transfer_assets' , value : transferData } } ,
153
+ ) ;
154
+
155
+ let forwardedXcms : [ XcmVersionedLocation , XcmVersionedXcm [ ] ] [ ] = [ ] ;
156
+ if ( localDryRunResult . success && localDryRunResult . value . forwarded_xcms ) {
157
+ forwardedXcms = localDryRunResult . value . forwarded_xcms ;
158
+ } else {
159
+ throw new Error ( 'Dry run failed' ) ;
160
+ }
161
+
162
+ const xcmsToPHub = forwardedXcms . find (
163
+ ( [ location , _ ] ) =>
164
+ location . type === 'V4' &&
165
+ location . value . parents === 1 &&
166
+ location . value . interior . type === 'X1' &&
167
+ location . value . interior . value . type === 'Parachain' &&
168
+ location . value . interior . value . value === ParaId [ Chains . PolkadotHub ] ,
169
+ ) ;
170
+ if ( ! xcmsToPHub ) {
171
+ throw new Error ( 'Could not find xcm to polimec' ) ;
172
+ }
173
+ const messages = xcmsToPHub [ 1 ] ;
174
+ const remoteXcm = messages [ 0 ] ;
175
+ const remoteXcmWeightResult = await destApi . apis . XcmPaymentApi . query_xcm_weight ( remoteXcm ) ;
176
+ if ( remoteXcmWeightResult . success ) {
177
+ const remoteExecutionFeesResult = await destApi . apis . XcmPaymentApi . query_weight_to_asset_fee (
178
+ remoteXcmWeightResult . value ,
179
+ remoteFeeAssetId ,
180
+ ) ;
181
+ if ( remoteExecutionFeesResult . success ) {
182
+ destinationExecutionFee = remoteExecutionFeesResult . value ;
183
+ } else {
184
+ throw new Error ( 'Could not calculate destination xcm fee' ) ;
185
+ }
186
+ } else {
187
+ throw new Error ( 'Could not calculate xcm weight' ) ;
68
188
}
189
+
190
+ return destinationExecutionFee ;
69
191
}
70
192
}
0 commit comments