@@ -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,26 @@ 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+ let feeAddressChange = feeAddressUtxoBalance . checked_sub ( this . _fee ) ;
231+ const senderAddressUtxoBalance = CardanoWasm . BigNum . from_str ( this . _senderBalance ) ;
232+ if ( this . _isTokenTransaction ) {
233+ // Fee address sponsors min ada
234+ feeAddressChange = this . addReceiverOutputs ( outputs , feeAddressChange ) ;
235+ this . addChangeOutput ( senderAddressUtxoBalance , outputs , this . _changeAddress ) ;
236+ this . addChangeOutput ( feeAddressChange , outputs , this . _sponsorshipInfo . feeAddress ) ;
237+ } else {
238+ const senderChangeAfterReceiverDeductions = this . addReceiverOutputs ( outputs , senderAddressUtxoBalance ) ;
239+ this . addChangeOutput ( senderChangeAfterReceiverDeductions , outputs , this . _changeAddress ) ;
240+ this . addChangeOutput ( feeAddressChange , outputs , this . _sponsorshipInfo . feeAddress ) ;
241+ }
242+ } else {
243+ const utxoBalance = CardanoWasm . BigNum . from_str ( this . _senderBalance ) ; // Total UTXO balance
244+ const change = utxoBalance . checked_sub ( this . _fee ) ;
245+ const changeAfterReceiverDeductions = this . addReceiverOutputs ( outputs , change ) ;
246+ this . addChangeOutput ( changeAfterReceiverDeductions , outputs , this . _changeAddress ) ;
247+ }
226248 }
227249
228250 /**
@@ -250,6 +272,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
250272 ) ;
251273 }
252274
275+ // output.multiAssets is set when there are token assets to send
253276 const multiAssets = output . multiAssets as Asset ;
254277 if ( multiAssets ) {
255278 const policyId = multiAssets . policy_id ;
@@ -273,6 +296,12 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
273296 } ) ;
274297
275298 change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
299+ } else {
300+ // Native coin send
301+ const amount = CardanoWasm . BigNum . from_str ( receiverAmount ) ;
302+ outputs . add (
303+ CardanoWasm . TransactionOutput . new ( util . getWalletAddress ( receiverAddress ) , CardanoWasm . Value . new ( amount ) )
304+ ) ;
276305 }
277306 } catch ( e ) {
278307 if ( e instanceof BuildTransactionError ) {
@@ -337,26 +366,32 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
337366 * @param change - The change amount in Lovelace
338367 * @param outputs - The outputs collection to add to
339368 */
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- }
369+ private addChangeOutput ( change , outputs , outputAddress ) {
370+ const changeAddress = util . getWalletAddress ( outputAddress ) ;
371+ /**
372+ * this.mutableSenderAssetList is the list of assets from the sender address
373+ * As ada only utxos are picked for fee address, the assets by default are sent to the sender address
374+ */
375+ if ( ! this . _sponsorshipInfo || this . _sponsorshipInfo . feeAddress !== outputAddress ) {
376+ Object . keys ( this . _mutableSenderAssetList ) . forEach ( ( fingerprint ) => {
377+ const asset = this . _mutableSenderAssetList [ fingerprint ] ;
378+ const changeQty = asset . quantity ;
379+ const policyId = asset . policy_id ;
380+ const assetName = asset . asset_name ;
381+
382+ if ( CardanoWasm . BigNum . from_str ( changeQty ) . is_zero ( ) ) {
383+ return ;
384+ }
351385
352- const minAmountNeededForAssetOutput = this . addTokensToOutput ( change , outputs , this . _changeAddress , {
353- policy_id : policyId ,
354- asset_name : assetName ,
355- quantity : changeQty ,
356- fingerprint,
386+ const minAmountNeededForAssetOutput = this . addTokensToOutput ( change , outputs , outputAddress , {
387+ policy_id : policyId ,
388+ asset_name : assetName ,
389+ quantity : changeQty ,
390+ fingerprint,
391+ } ) ;
392+ change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
357393 } ) ;
358- change = change . checked_sub ( minAmountNeededForAssetOutput ) ;
359- } ) ;
394+ }
360395 if ( ! change . is_zero ( ) ) {
361396 const changeOutput = CardanoWasm . TransactionOutput . new ( changeAddress , CardanoWasm . Value . new ( change ) ) ;
362397 outputs . add ( changeOutput ) ;
@@ -436,7 +471,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
436471
437472 /** @inheritdoc */
438473 protected async buildImplementation ( ) : Promise < Transaction > {
439- if ( this . _isTokenTransaction ) {
474+ if ( this . _isTokenTransaction || ( this . _sponsorshipInfo && this . _type === TransactionType . Send ) ) {
440475 return this . processTokenBuild ( ) ;
441476 }
442477 const inputs = CardanoWasm . TransactionInputs . new ( ) ;
0 commit comments