@@ -1302,6 +1302,11 @@ impl TransactionBuilder {
13021302 let input_total = self . get_total_input ( ) ?;
13031303 let output_total = self . get_total_output ( ) ?;
13041304
1305+ let shortage = get_input_shortage ( & input_total, & output_total, & fee) ?;
1306+ if let Some ( shortage) = shortage {
1307+ return Err ( JsError :: from_str ( & format ! ( "Insufficient input in transaction. {}" , shortage) ) ) ;
1308+ }
1309+
13051310 use std:: cmp:: Ordering ;
13061311 match & input_total. partial_cmp ( & output_total. checked_add ( & Value :: new ( & fee) ) ?) {
13071312 Some ( Ordering :: Equal ) => {
@@ -2926,6 +2931,196 @@ mod tests {
29262931 ) ;
29272932 }
29282933
2934+ #[ test]
2935+ fn change_with_input_and_mint_not_enough_ada ( ) {
2936+ let mut tx_builder = create_tx_builder_with_fee ( & create_linear_fee ( 1 , 1 ) ) ;
2937+ let spend = root_key_15 ( )
2938+ . derive ( harden ( 1852 ) )
2939+ . derive ( harden ( 1815 ) )
2940+ . derive ( harden ( 0 ) )
2941+ . derive ( 0 )
2942+ . derive ( 0 )
2943+ . to_public ( ) ;
2944+ let change_key = root_key_15 ( )
2945+ . derive ( harden ( 1852 ) )
2946+ . derive ( harden ( 1815 ) )
2947+ . derive ( harden ( 0 ) )
2948+ . derive ( 1 )
2949+ . derive ( 0 )
2950+ . to_public ( ) ;
2951+ let stake = root_key_15 ( )
2952+ . derive ( harden ( 1852 ) )
2953+ . derive ( harden ( 1815 ) )
2954+ . derive ( harden ( 0 ) )
2955+ . derive ( 2 )
2956+ . derive ( 0 )
2957+ . to_public ( ) ;
2958+
2959+ let spend_cred = StakeCredential :: from_keyhash ( & spend. to_raw_key ( ) . hash ( ) ) ;
2960+ let stake_cred = StakeCredential :: from_keyhash ( & stake. to_raw_key ( ) . hash ( ) ) ;
2961+
2962+ let ( min_script, policy_id) = mint_script_and_policy ( 0 ) ;
2963+ let asset_name = AssetName :: new ( vec ! [ 0u8 , 1 , 2 , 3 ] ) . unwrap ( ) ;
2964+
2965+ let amount_minted = to_bignum ( 1000 ) ;
2966+ let amount_sent = to_bignum ( 500 ) ;
2967+ let amount_input_amount = to_bignum ( 600 ) ;
2968+
2969+ let mut asset_input = Assets :: new ( ) ;
2970+ asset_input. insert ( & asset_name, & amount_input_amount) ;
2971+ let mut mass_input = MultiAsset :: new ( ) ;
2972+ mass_input. insert ( & policy_id, & asset_input) ;
2973+
2974+ // Input with 600 coins
2975+ tx_builder. add_input (
2976+ & EnterpriseAddress :: new ( NetworkInfo :: testnet ( ) . network_id ( ) , & spend_cred) . to_address ( ) ,
2977+ & TransactionInput :: new ( & genesis_id ( ) , 0 ) ,
2978+ & Value :: new ( & to_bignum ( 600 ) ) ,
2979+ ) ;
2980+
2981+ tx_builder. add_input (
2982+ & EnterpriseAddress :: new ( NetworkInfo :: testnet ( ) . network_id ( ) , & spend_cred) . to_address ( ) ,
2983+ & TransactionInput :: new ( & genesis_id ( ) , 1 ) ,
2984+ & Value :: new_with_assets ( & to_bignum ( 1 ) , & mass_input) ,
2985+ ) ;
2986+
2987+ let addr_net_0 = BaseAddress :: new (
2988+ NetworkInfo :: testnet ( ) . network_id ( ) ,
2989+ & spend_cred,
2990+ & stake_cred,
2991+ ) . to_address ( ) ;
2992+
2993+ // Adding mint of the asset - which should work as an input
2994+ tx_builder. add_mint_asset ( & min_script, & asset_name, Int :: new ( & amount_minted) ) ;
2995+
2996+ let mut asset = Assets :: new ( ) ;
2997+ asset. insert ( & asset_name, & amount_sent) ;
2998+ let mut mass = MultiAsset :: new ( ) ;
2999+ mass. insert ( & policy_id, & asset) ;
3000+
3001+ // One coin and the minted asset goes into the output
3002+ let mut output_amount = Value :: new ( & to_bignum ( 400 ) ) ;
3003+ output_amount. set_multiasset ( & mass) ;
3004+
3005+ tx_builder
3006+ . add_output (
3007+ & TransactionOutputBuilder :: new ( )
3008+ . with_address ( & addr_net_0)
3009+ . next ( )
3010+ . unwrap ( )
3011+ . with_value ( & output_amount)
3012+ . build ( )
3013+ . unwrap ( ) ,
3014+ )
3015+ . unwrap ( ) ;
3016+
3017+ let change_cred = StakeCredential :: from_keyhash ( & change_key. to_raw_key ( ) . hash ( ) ) ;
3018+ let change_addr = BaseAddress :: new (
3019+ NetworkInfo :: testnet ( ) . network_id ( ) ,
3020+ & change_cred,
3021+ & stake_cred,
3022+ )
3023+ . to_address ( ) ;
3024+
3025+ let added_change = tx_builder. add_change_if_needed ( & change_addr) ;
3026+ assert ! ( added_change. is_err( ) ) ;
3027+ }
3028+
3029+ #[ test]
3030+ fn change_with_input_and_mint_not_enough_assets ( ) {
3031+ let mut tx_builder = create_tx_builder_with_fee ( & create_linear_fee ( 1 , 1 ) ) ;
3032+ let spend = root_key_15 ( )
3033+ . derive ( harden ( 1852 ) )
3034+ . derive ( harden ( 1815 ) )
3035+ . derive ( harden ( 0 ) )
3036+ . derive ( 0 )
3037+ . derive ( 0 )
3038+ . to_public ( ) ;
3039+ let change_key = root_key_15 ( )
3040+ . derive ( harden ( 1852 ) )
3041+ . derive ( harden ( 1815 ) )
3042+ . derive ( harden ( 0 ) )
3043+ . derive ( 1 )
3044+ . derive ( 0 )
3045+ . to_public ( ) ;
3046+ let stake = root_key_15 ( )
3047+ . derive ( harden ( 1852 ) )
3048+ . derive ( harden ( 1815 ) )
3049+ . derive ( harden ( 0 ) )
3050+ . derive ( 2 )
3051+ . derive ( 0 )
3052+ . to_public ( ) ;
3053+
3054+ let spend_cred = StakeCredential :: from_keyhash ( & spend. to_raw_key ( ) . hash ( ) ) ;
3055+ let stake_cred = StakeCredential :: from_keyhash ( & stake. to_raw_key ( ) . hash ( ) ) ;
3056+
3057+ let ( min_script, policy_id) = mint_script_and_policy ( 0 ) ;
3058+ let asset_name = AssetName :: new ( vec ! [ 0u8 , 1 , 2 , 3 ] ) . unwrap ( ) ;
3059+
3060+ let amount_minted = to_bignum ( 1000 ) ;
3061+ let amount_sent = to_bignum ( 100000 ) ;
3062+ let amount_input_amount = to_bignum ( 600 ) ;
3063+
3064+ let mut asset_input = Assets :: new ( ) ;
3065+ asset_input. insert ( & asset_name, & amount_input_amount) ;
3066+ let mut mass_input = MultiAsset :: new ( ) ;
3067+ mass_input. insert ( & policy_id, & asset_input) ;
3068+
3069+ // Input with 600 coins
3070+ tx_builder. add_input (
3071+ & EnterpriseAddress :: new ( NetworkInfo :: testnet ( ) . network_id ( ) , & spend_cred) . to_address ( ) ,
3072+ & TransactionInput :: new ( & genesis_id ( ) , 0 ) ,
3073+ & Value :: new ( & to_bignum ( 100000 ) ) ,
3074+ ) ;
3075+
3076+ tx_builder. add_input (
3077+ & EnterpriseAddress :: new ( NetworkInfo :: testnet ( ) . network_id ( ) , & spend_cred) . to_address ( ) ,
3078+ & TransactionInput :: new ( & genesis_id ( ) , 1 ) ,
3079+ & Value :: new_with_assets ( & to_bignum ( 1 ) , & mass_input) ,
3080+ ) ;
3081+
3082+ let addr_net_0 = BaseAddress :: new (
3083+ NetworkInfo :: testnet ( ) . network_id ( ) ,
3084+ & spend_cred,
3085+ & stake_cred,
3086+ ) . to_address ( ) ;
3087+
3088+ // Adding mint of the asset - which should work as an input
3089+ tx_builder. add_mint_asset ( & min_script, & asset_name, Int :: new ( & amount_minted) ) ;
3090+
3091+ let mut asset = Assets :: new ( ) ;
3092+ asset. insert ( & asset_name, & amount_sent) ;
3093+ let mut mass = MultiAsset :: new ( ) ;
3094+ mass. insert ( & policy_id, & asset) ;
3095+
3096+ // One coin and the minted asset goes into the output
3097+ let mut output_amount = Value :: new ( & to_bignum ( 400 ) ) ;
3098+ output_amount. set_multiasset ( & mass) ;
3099+
3100+ tx_builder
3101+ . add_output (
3102+ & TransactionOutputBuilder :: new ( )
3103+ . with_address ( & addr_net_0)
3104+ . next ( )
3105+ . unwrap ( )
3106+ . with_value ( & output_amount)
3107+ . build ( )
3108+ . unwrap ( ) ,
3109+ )
3110+ . unwrap ( ) ;
3111+
3112+ let change_cred = StakeCredential :: from_keyhash ( & change_key. to_raw_key ( ) . hash ( ) ) ;
3113+ let change_addr = BaseAddress :: new (
3114+ NetworkInfo :: testnet ( ) . network_id ( ) ,
3115+ & change_cred,
3116+ & stake_cred,
3117+ )
3118+ . to_address ( ) ;
3119+
3120+ let added_change = tx_builder. add_change_if_needed ( & change_addr) ;
3121+ assert ! ( added_change. is_err( ) ) ;
3122+ }
3123+
29293124 #[ ignore]
29303125 #[ test]
29313126 fn build_tx_with_native_assets_change ( ) {
0 commit comments