@@ -10,7 +10,7 @@ import {
1010 TransactionType ,
1111 UtilsError ,
1212} from '@bitgo/sdk-core' ;
13- import { Asset , Transaction , TransactionInput , TransactionOutput , Withdrawal } from './transaction' ;
13+ import { Asset , Transaction , TransactionInput , TransactionOutput , Withdrawal , SponsorshipInfo } from './transaction' ;
1414import { KeyPair } from './keyPair' ;
1515import util , { MIN_ADA_FOR_ONE_ASSET } from './utils' ;
1616import * as CardanoWasm from '@emurgo/cardano-serialization-lib-nodejs' ;
@@ -46,6 +46,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
4646 protected _recipientAddress : string ;
4747 /** Map of sender's assets by asset name */
4848 protected _senderAssetList : Record < string , any > = { } ;
49+ protected _sponsorshipInfo : SponsorshipInfo | undefined ; // Enriched for sponsored transactions
4950 private _fee : BigNum ;
5051 /** Flag indicating if this is a token transaction */
5152 private _isTokenTransaction = false ;
@@ -113,6 +114,11 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
113114 return this ;
114115 }
115116
117+ sponsorshipInfo ( info : SponsorshipInfo ) : this {
118+ this . _sponsorshipInfo = info ;
119+ return this ;
120+ }
121+
116122 /**
117123 * Initialize the transaction builder fields using the decoded transaction data
118124 *
@@ -219,10 +225,19 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
219225 * @param outputs - The outputs collection to add to
220226 */
221227 private addOutputs ( outputs ) {
222- const utxoBalance = CardanoWasm . BigNum . from_str ( this . _senderBalance ) ; // Total UTXO balance
223- const change = utxoBalance . checked_sub ( this . _fee ) ;
224- const changeAfterReceiverDeductions = this . addReceiverOutputs ( outputs , change ) ;
225- this . addChangeOutput ( changeAfterReceiverDeductions , outputs ) ;
228+ if ( this . _sponsorshipInfo ) {
229+ const feeAddressUtxoBalance = CardanoWasm . BigNum . from_str ( this . _sponsorshipInfo . feeAddressInputBalance ) ;
230+ const feeAddressChange = feeAddressUtxoBalance . checked_sub ( this . _fee ) ;
231+ const senderAddressUtxoBalance = CardanoWasm . BigNum . from_str ( this . _senderBalance ) ;
232+ const senderChangeAfterReceiverDeductions = this . addReceiverOutputs ( outputs , senderAddressUtxoBalance ) ;
233+ this . addChangeOutput ( senderChangeAfterReceiverDeductions , outputs , this . _changeAddress ) ; // Change address is the sender address
234+ this . addChangeOutput ( feeAddressChange , outputs , this . _sponsorshipInfo . feeAddress ) ;
235+ } else {
236+ const utxoBalance = CardanoWasm . BigNum . from_str ( this . _senderBalance ) ; // Total UTXO balance
237+ const change = utxoBalance . checked_sub ( this . _fee ) ;
238+ const changeAfterReceiverDeductions = this . addReceiverOutputs ( outputs , change ) ;
239+ this . addChangeOutput ( changeAfterReceiverDeductions , outputs , this . _changeAddress ) ;
240+ }
226241 }
227242
228243 /**
@@ -250,6 +265,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
250265 ) ;
251266 }
252267
268+ // output.multiAssets is set when there are token assets to send
253269 const multiAssets = output . multiAssets as Asset ;
254270 if ( multiAssets ) {
255271 const policyId = multiAssets . policy_id ;
@@ -273,6 +289,12 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
273289 } ) ;
274290
275291 change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
292+ } else {
293+ // Native coin send
294+ const amount = CardanoWasm . BigNum . from_str ( receiverAmount ) ;
295+ outputs . add (
296+ CardanoWasm . TransactionOutput . new ( util . getWalletAddress ( receiverAddress ) , CardanoWasm . Value . new ( amount ) )
297+ ) ;
276298 }
277299 } catch ( e ) {
278300 if ( e instanceof BuildTransactionError ) {
@@ -337,26 +359,32 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
337359 * @param change - The change amount in Lovelace
338360 * @param outputs - The outputs collection to add to
339361 */
340- private addChangeOutput ( change , outputs ) {
341- const changeAddress = util . getWalletAddress ( this . _changeAddress ) ;
342- Object . keys ( this . _mutableSenderAssetList ) . forEach ( ( fingerprint ) => {
343- const asset = this . _mutableSenderAssetList [ fingerprint ] ;
344- const changeQty = asset . quantity ;
345- const policyId = asset . policy_id ;
346- const assetName = asset . asset_name ;
347-
348- if ( CardanoWasm . BigNum . from_str ( changeQty ) . is_zero ( ) ) {
349- return ;
350- }
362+ private addChangeOutput ( change , outputs , outputAddress ) {
363+ const changeAddress = util . getWalletAddress ( outputAddress ) ;
364+ /**
365+ * this.mutableSenderAssetList is the list of assets from the sender address
366+ * As ada only utxos are picked for fee address, the assets by default are sent to the sender address
367+ */
368+ if ( ! this . _sponsorshipInfo || this . _sponsorshipInfo . feeAddress !== outputAddress ) {
369+ Object . keys ( this . _mutableSenderAssetList ) . forEach ( ( fingerprint ) => {
370+ const asset = this . _mutableSenderAssetList [ fingerprint ] ;
371+ const changeQty = asset . quantity ;
372+ const policyId = asset . policy_id ;
373+ const assetName = asset . asset_name ;
374+
375+ if ( CardanoWasm . BigNum . from_str ( changeQty ) . is_zero ( ) ) {
376+ return ;
377+ }
351378
352- const minAmountNeededForAssetOutput = this . addTokensToOutput ( change , outputs , this . _changeAddress , {
353- policy_id : policyId ,
354- asset_name : assetName ,
355- quantity : changeQty ,
356- fingerprint,
379+ const minAmountNeededForAssetOutput = this . addTokensToOutput ( change , outputs , outputAddress , {
380+ policy_id : policyId ,
381+ asset_name : assetName ,
382+ quantity : changeQty ,
383+ fingerprint,
384+ } ) ;
385+ change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
357386 } ) ;
358- change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
359- } ) ;
387+ }
360388 if ( ! change . is_zero ( ) ) {
361389 const changeOutput = CardanoWasm . TransactionOutput . new ( changeAddress , CardanoWasm . Value . new ( change ) ) ;
362390 outputs . add ( changeOutput ) ;
@@ -436,7 +464,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
436464
437465 /** @inheritdoc */
438466 protected async buildImplementation ( ) : Promise < Transaction > {
439- if ( this . _isTokenTransaction ) {
467+ if ( this . _isTokenTransaction || ( this . _sponsorshipInfo && this . _type === TransactionType . Send ) ) {
440468 return this . processTokenBuild ( ) ;
441469 }
442470 const inputs = CardanoWasm . TransactionInputs . new ( ) ;
0 commit comments