@@ -6,6 +6,7 @@ import { AmountData } from '@subwallet/extension-base/background/KoniTypes';
6
6
import { _SUPPORT_TOKEN_PAY_FEE_GROUP , XCM_FEE_RATIO } from '@subwallet/extension-base/constants' ;
7
7
import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser' ;
8
8
import { DEFAULT_CARDANO_TTL_OFFSET } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/consts' ;
9
+ import { createBitcoinTransaction } from '@subwallet/extension-base/services/balance-service/transfer/bitcoin-transfer' ;
9
10
import { createCardanoTransaction } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer' ;
10
11
import { getERC20TransactionObject , getEVMTransactionObject } from '@subwallet/extension-base/services/balance-service/transfer/smart-contract' ;
11
12
import { createSubstrateExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token' ;
@@ -21,11 +22,13 @@ import { calculateToAmountByReservePool, FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE }
21
22
import { getHydrationRate } from '@subwallet/extension-base/services/fee-service/utils/tokenPayFee' ;
22
23
import { isCardanoTransaction , isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers' ;
23
24
import { ValidateTransactionResponseInput } from '@subwallet/extension-base/services/transaction-service/types' ;
24
- import { EvmEIP1559FeeOption , FeeChainType , FeeDetail , FeeInfo , SubstrateTipInfo , TransactionFee } from '@subwallet/extension-base/types' ;
25
+ import { BitcoinFeeRate , DetermineUtxosForSpendArgs , EvmEIP1559FeeOption , FeeChainType , FeeDetail , FeeInfo , SubstrateTipInfo , TransactionFee } from '@subwallet/extension-base/types' ;
25
26
import { ResponseSubscribeTransfer } from '@subwallet/extension-base/types/balance/transfer' ;
26
- import { BN_ZERO } from '@subwallet/extension-base/utils' ;
27
+ import { BN_ZERO , combineBitcoinFee , determineUtxosForSpend , determineUtxosForSpendAll , filterUneconomicalUtxos , getSizeInfo , getTransferableBitcoinUtxos } from '@subwallet/extension-base/utils' ;
27
28
import { isCardanoAddress , isTonAddress } from '@subwallet/keyring' ;
29
+ import { isBitcoinAddress } from '@subwallet/keyring/utils/address/validate' ;
28
30
import BigN from 'bignumber.js' ;
31
+ import { bitcoin , testnet } from 'bitcoinjs-lib/src/networks' ;
29
32
import { TransactionConfig } from 'web3-core' ;
30
33
31
34
import { SubmittableExtrinsic } from '@polkadot/api/types' ;
@@ -36,6 +39,7 @@ import { combineEthFee, combineSubstrateFee } from './combine';
36
39
37
40
export interface CalculateMaxTransferable extends TransactionFee {
38
41
address : string ;
42
+ to ?: string ;
39
43
value : string ;
40
44
srcToken : _ChainAsset ;
41
45
destToken ?: _ChainAsset ;
@@ -101,7 +105,7 @@ export const calculateMaxTransferable = async (id: string, request: CalculateMax
101
105
} ;
102
106
103
107
export const calculateTransferMaxTransferable = async ( id : string , request : CalculateMaxTransferable , freeBalance : AmountData , fee : FeeInfo ) : Promise < ResponseSubscribeTransfer > => {
104
- const { address, bitcoinApi, cardanoApi, destChain, evmApi, feeCustom, feeOption, isTransferLocalTokenAndPayThatTokenAsFee, isTransferNativeTokenAndPayLocalTokenAsFee, nativeToken, srcChain, srcToken, substrateApi, tonApi, value } = request ;
108
+ const { address, bitcoinApi, cardanoApi, destChain, evmApi, feeCustom, feeOption, isTransferLocalTokenAndPayThatTokenAsFee, isTransferNativeTokenAndPayLocalTokenAsFee, nativeToken, srcChain, srcToken, substrateApi, to , tonApi, value } = request ;
105
109
const feeChainType = fee . type ;
106
110
let estimatedFee : string ;
107
111
let feeOptions : FeeDetail ;
@@ -170,7 +174,20 @@ export const calculateTransferMaxTransferable = async (id: string, request: Calc
170
174
cardanoApi,
171
175
nativeTokenInfo : nativeToken
172
176
} ) ;
173
- } else { // TODO: Support maxTransferable for bitcoin
177
+ } else if ( isBitcoinAddress ( address ) && _isTokenTransferredByBitcoin ( srcToken ) ) {
178
+ const network = srcChain . isTestnet ? testnet : bitcoin ;
179
+
180
+ [ transaction ] = await createBitcoinTransaction ( {
181
+ from : address ,
182
+ to : address ,
183
+ chain : srcChain . slug ,
184
+ value,
185
+ feeInfo : fee ,
186
+ transferAll : false ,
187
+ bitcoinApi,
188
+ network
189
+ } ) ;
190
+ } else {
174
191
[ transaction ] = await createSubstrateExtrinsic ( {
175
192
transferAll : false ,
176
193
value,
@@ -223,8 +240,98 @@ export const calculateTransferMaxTransferable = async (id: string, request: Calc
223
240
...fee ,
224
241
estimatedFee
225
242
} ;
243
+ } else if ( feeChainType === 'bitcoin' ) {
244
+ const _fee = fee ;
245
+ const _feeCustom = feeCustom as BitcoinFeeRate ;
246
+ const combineFee = combineBitcoinFee ( _fee , feeOption , _feeCustom ) ;
247
+ const utxos = await getTransferableBitcoinUtxos ( bitcoinApi , address ) ;
248
+ const determineUtxosArgs : DetermineUtxosForSpendArgs = {
249
+ amount : parseInt ( value || '0' ) ,
250
+ feeRate : combineFee . feeRate ,
251
+ recipient : to || address ,
252
+ sender : address ,
253
+ utxos
254
+ } ;
255
+
256
+ console . log ( 'maxTransfer, utxos' , utxos ) ;
257
+ console . log ( 'maxTransfer, determineUtxosArgs' , determineUtxosArgs ) ;
258
+
259
+ const fallbackCalculate = ( recipients : string [ ] ) => {
260
+ const utxos = filterUneconomicalUtxos ( {
261
+ utxos : determineUtxosArgs . utxos ,
262
+ feeRate : determineUtxosArgs . feeRate ,
263
+ recipients,
264
+ sender : determineUtxosArgs . sender
265
+ } ) ;
266
+
267
+ const { txVBytes : vSize } = getSizeInfo ( {
268
+ inputLength : utxos . length || 1 ,
269
+ sender : address ,
270
+ recipients
271
+ } ) ;
272
+
273
+ return {
274
+ vSize,
275
+ maxTransferable : utxos . reduce ( ( previous , input ) => previous . plus ( input . value ) , new BigN ( 0 ) ) ,
276
+ estimatedFee : Math . ceil ( determineUtxosArgs . feeRate * vSize ) . toString ( )
277
+ } ;
278
+ } ;
279
+
280
+ try {
281
+ const { fee : _estimatedFee , inputs } = false ? determineUtxosForSpendAll ( determineUtxosArgs ) : determineUtxosForSpend ( determineUtxosArgs ) ;
282
+
283
+ maxTransferable = inputs . reduce ( ( previous , input ) => previous . plus ( input . value ) , new BigN ( 0 ) ) ;
284
+
285
+ const { txVBytes : vSize } = getSizeInfo ( {
286
+ inputLength : inputs . length ,
287
+ sender : address ,
288
+ recipients
289
+ } ) ;
290
+
291
+ estimatedFee = new BigN ( _estimatedFee ) . toFixed ( 0 ) ;
292
+ feeOptions = {
293
+ ..._fee ,
294
+ estimatedFee,
295
+ vSize
296
+ } ;
297
+
298
+ if ( transferAll ) {
299
+ estimatedFeeMax = new BigN ( _estimatedFee ) . toFixed ( 0 ) ;
300
+ } else {
301
+ try {
302
+ const { fee : estimateFeeMax , inputs } = determineUtxosForSpendAll ( determineUtxosArgs ) ;
303
+
304
+ maxTransferable = inputs . reduce ( ( previous , input ) => previous . plus ( input . value ) , new BigN ( 0 ) ) ;
305
+ estimatedFeeMax = new BigN ( estimateFeeMax ) . toFixed ( 0 ) ;
306
+ } catch ( _e ) {
307
+ const fb = fallbackCalculate ( [ to || address ] ) ;
308
+
309
+ maxTransferable = fb . maxTransferable ;
310
+ estimatedFeeMax = fb . estimatedFee ;
311
+ }
312
+ }
313
+ } catch ( _e ) {
314
+ const fb = fallbackCalculate ( [ to || address ] ) ;
315
+
316
+ maxTransferable = fb . maxTransferable ;
317
+ estimatedFeeMax = fb . estimatedFee ;
318
+
319
+ if ( ! feeOptions ) {
320
+ const fb = fallbackCalculate ( [ address , to || address ] ) ;
321
+
322
+ estimatedFee = fb . estimatedFee ;
323
+
324
+ feeOptions = {
325
+ ..._fee ,
326
+ estimatedFee,
327
+ vSize : fb . vSize
328
+ } ;
329
+ }
330
+ }
226
331
} else {
227
332
if ( transaction ) {
333
+ console . log ( 'transaction' , transaction ) ;
334
+
228
335
if ( isTonTransaction ( transaction ) ) {
229
336
estimatedFee = transaction . estimateFee ;
230
337
feeOptions = {
0 commit comments