@@ -5,47 +5,30 @@ import {
55 evmSerial ,
66 UnsignedTx ,
77 Credential ,
8- BigIntPr ,
9- Int ,
10- Id ,
11- TransferableOutput ,
128 Address ,
139 TransferOutput ,
14- OutputOwners ,
1510 utils as FlareUtils ,
11+ evm ,
1612} from '@flarenetwork/flarejs' ;
1713import utils from './utils' ;
18- import { DecodedUtxoObj , Tx , FlareTransactionType } from './iface' ;
14+ import { Tx , FlareTransactionType , ExportEVMOptions } from './iface' ;
1915
2016export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
21- private _amount : bigint ;
2217 private _nonce : bigint ;
2318
2419 constructor ( _coinConfig : Readonly < CoinConfig > ) {
2520 super ( _coinConfig ) ;
2621 }
2722
2823 /**
29- * Utxos are not required in Export Tx in C-Chain.
30- * Override utxos to prevent used by throwing a error.
24+ * UTXOs are not required for Export Tx from C-Chain (uses EVM balance instead) .
25+ * Override to prevent usage by throwing an error.
3126 *
32- * @param {DecodedUtxoObj[] } value ignored
27+ * @param {string[] } _utxoHexStrings - ignored, UTXOs not used for C-chain exports
28+ * @throws {BuildTransactionError } always throws as UTXOs are not applicable
3329 */
34- utxos ( value : DecodedUtxoObj [ ] ) : this {
35- throw new BuildTransactionError ( 'utxos are not required in Export Tx in C-Chain' ) ;
36- }
37-
38- /**
39- * Amount is a bigint that specifies the quantity of the asset that this output owns. Must be positive.
40- * The transaction output amount add a fixed fee that will be paid upon import.
41- *
42- * @param {bigint | string } amount The withdrawal amount
43- */
44- amount ( amount : bigint | string ) : this {
45- const amountBigInt = typeof amount === 'string' ? BigInt ( amount ) : amount ;
46- this . validateAmount ( amountBigInt ) ;
47- this . _amount = amountBigInt ;
48- return this ;
30+ utxos ( _utxoHexStrings : string [ ] ) : this {
31+ throw new BuildTransactionError ( 'UTXOs are not required for Export Tx from C-Chain' ) ;
4932 }
5033
5134 /**
@@ -81,8 +64,6 @@ export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
8164 throw new NotSupported ( 'Transaction cannot be parsed or has an unsupported transaction type' ) ;
8265 }
8366
84- // The outputs is a multisign P-Chain address result.
85- // It's expected to have only one output to the destination P-Chain address.
8667 const outputs = baseTx . exportedOutputs ;
8768 if ( outputs . length !== 1 ) {
8869 throw new BuildTransactionError ( 'Transaction can have one output' ) ;
@@ -93,8 +74,6 @@ export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
9374 throw new BuildTransactionError ( 'AssetID mismatch' ) ;
9475 }
9576
96- // The inputs is not an utxo.
97- // It's expected to have only one input from C-Chain address.
9877 const inputs = baseTx . ins ;
9978 if ( inputs . length !== 1 ) {
10079 throw new BuildTransactionError ( 'Transaction can have one input' ) ;
@@ -107,27 +86,17 @@ export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
10786 const inputAmount = input . amount . value ( ) ;
10887 const outputAmount = transferOutput . amount ( ) ;
10988 const fee = inputAmount - outputAmount ;
110- this . _amount = outputAmount ;
111- // Subtract fixedFee from total fee to get the gas-based feeRate
112- // buildFlareTransaction will add fixedFee back when building the transaction
113- this . transaction . _fee . feeRate = Number ( fee ) - Number ( this . fixedFee ) ;
89+ this . transaction . _amount = outputAmount ;
11490 this . transaction . _fee . fee = fee . toString ( ) ;
115- this . transaction . _fee . size = 1 ;
11691 this . transaction . _fromAddresses = [ Buffer . from ( input . address . toBytes ( ) ) ] ;
11792 this . transaction . _locktime = transferOutput . getLocktime ( ) ;
118-
11993 this . _nonce = input . nonce . value ( ) ;
120-
121- // Use credentials passed from TransactionBuilderFactory (properly extracted using codec)
12294 const credentials = parsedCredentials || [ ] ;
12395 const hasCredentials = credentials . length > 0 ;
124-
125- // If it's a signed transaction, store the original raw bytes to preserve exact format
12696 if ( hasCredentials && rawBytes ) {
12797 this . transaction . _rawSignedBytes = rawBytes ;
12898 }
12999
130- // Create proper UnsignedTx wrapper with credentials
131100 const fromAddress = new Address ( this . transaction . _fromAddresses [ 0 ] ) ;
132101 const addressMap = new FlareUtils . AddressMap ( [
133102 [ fromAddress , 0 ] ,
@@ -160,80 +129,52 @@ export class ExportInCTxBuilder extends AtomicInCTransactionBuilder {
160129 */
161130 protected buildFlareTransaction ( ) : void {
162131 if ( this . transaction . hasCredentials ) return ;
163- if ( this . _amount === undefined ) {
164- throw new Error ( 'amount is required' ) ;
132+ if ( this . transaction . _amount === undefined ) {
133+ throw new BuildTransactionError ( 'amount is required' ) ;
165134 }
166135 if ( this . transaction . _fromAddresses . length !== 1 ) {
167- throw new Error ( 'sender is one and required' ) ;
136+ throw new BuildTransactionError ( 'sender is one and required' ) ;
168137 }
169138 if ( this . transaction . _to . length === 0 ) {
170- throw new Error ( 'to is required' ) ;
139+ throw new BuildTransactionError ( 'to is required' ) ;
171140 }
172- if ( ! this . transaction . _fee . feeRate ) {
173- throw new Error ( 'fee rate is required' ) ;
141+ if ( ! this . transaction . _fee . fee ) {
142+ throw new BuildTransactionError ( 'fee rate is required' ) ;
174143 }
175144 if ( this . _nonce === undefined ) {
176- throw new Error ( 'nonce is required' ) ;
145+ throw new BuildTransactionError ( 'nonce is required' ) ;
146+ }
147+ if ( ! this . transaction . _context ) {
148+ throw new BuildTransactionError ( 'context is required' ) ;
177149 }
178150
179- // For EVM exports, total fee = feeRate (gas-based fee) + fixedFee (P-chain import fee)
180- // This matches the AVAX implementation where fixedFee covers the import cost
181- const txFee = BigInt ( this . fixedFee ) ;
182- const fee = BigInt ( this . transaction . _fee . feeRate ) + txFee ;
183- this . transaction . _fee . fee = fee . toString ( ) ;
184- this . transaction . _fee . size = 1 ;
185-
151+ const fee = BigInt ( this . transaction . _fee . fee ) ;
186152 const fromAddressBytes = this . transaction . _fromAddresses [ 0 ] ;
187- const fromAddress = new Address ( fromAddressBytes ) ;
188- const assetId = utils . flareIdString ( this . transaction . _assetId ) ;
189- const amount = new BigIntPr ( this . _amount + fee ) ;
190- const nonce = new BigIntPr ( this . _nonce ) ;
191- const input = new evmSerial . Input ( fromAddress , amount , assetId , nonce ) ;
192- // Map all destination P-chain addresses for multisig support
193- // Sort addresses alphabetically by hex representation (required by Avalanche/Flare protocol)
194153 const sortedToAddresses = [ ...this . transaction . _to ] . sort ( ( a , b ) => {
195154 const aHex = Buffer . from ( a ) . toString ( 'hex' ) ;
196155 const bHex = Buffer . from ( b ) . toString ( 'hex' ) ;
197156 return aHex . localeCompare ( bHex ) ;
198157 } ) ;
199158 const toAddresses = sortedToAddresses . map ( ( addr ) => new Address ( addr ) ) ;
200159
201- const exportTx = new evmSerial . ExportTx (
202- new Int ( this . transaction . _networkID ) ,
203- utils . flareIdString ( this . transaction . _blockchainID ) ,
204- new Id ( new Uint8Array ( this . _externalChainId ) ) ,
205- [ input ] ,
206- [
207- new TransferableOutput (
208- assetId ,
209- new TransferOutput (
210- new BigIntPr ( this . _amount ) ,
211- new OutputOwners (
212- new BigIntPr ( this . transaction . _locktime ) ,
213- new Int ( this . transaction . _threshold ) ,
214- toAddresses
215- )
216- )
217- ) ,
218- ]
219- ) ;
220-
221- // Create address maps with proper EVM address format
222- const addressMap = new FlareUtils . AddressMap ( [
223- [ fromAddress , 0 ] ,
224- [ fromAddress , 1 ] , // Map the same address to both indices since it's used in both places
225- ] ) ;
226- const addressMaps = new FlareUtils . AddressMaps ( [ addressMap ] ) ; // Single map is sufficient
227-
228- // Create unsigned transaction with proper address mapping
229- const unsignedTx = new UnsignedTx (
230- exportTx ,
231- [ ] , // Empty UTXOs array, will be filled during processing
232- addressMaps ,
233- [ new Credential ( [ utils . createNewSig ( '' ) ] ) ] // Empty credential for signing
160+ const exportEVMOptions : ExportEVMOptions = {
161+ threshold : this . transaction . _threshold ,
162+ locktime : this . transaction . _locktime ,
163+ } ;
164+
165+ const exportTx = evm . newExportTxFromBaseFee (
166+ this . transaction . _context ,
167+ fee / BigInt ( 1e9 ) ,
168+ this . transaction . _amount ,
169+ this . transaction . _context . pBlockchainID ,
170+ fromAddressBytes ,
171+ toAddresses . map ( ( addr ) => Buffer . from ( addr . toBytes ( ) ) ) ,
172+ BigInt ( this . _nonce ) ,
173+ utils . flareIdString ( this . transaction . _assetId ) . toString ( ) ,
174+ exportEVMOptions
234175 ) ;
235176
236- this . transaction . setTransaction ( unsignedTx ) ;
177+ this . transaction . setTransaction ( exportTx ) ;
237178 }
238179
239180 /**
0 commit comments