@@ -6190,6 +6190,77 @@ void FillBlinds(CWallet* pwallet, CMutableTransaction& tx, std::vector<uint256>&
61906190 }
61916191}
61926192
6193+ RPCHelpMan analyzerawtransaction ()
6194+ {
6195+ return RPCHelpMan{" analyzerawtransaction" ,
6196+ " \n Generate a mapping showing losses and gains resulting in the signing and broadcasting of the given transaction.\n " +
6197+ HELP_REQUIRING_PASSPHRASE,
6198+ {
6199+ {" hexstring" , RPCArg::Type::STR, RPCArg::Optional::NO, " The transaction hex string" },
6200+ },
6201+ RPCResult{
6202+ RPCResult::Type::OBJ_DYN, " " , " " ,
6203+ {
6204+ {RPCResult::Type::NUM, " asset" , " The wallet change for the given asset (negative means decrease)." },
6205+ }
6206+ },
6207+ RPCExamples{
6208+ HelpExampleCli (" analyzerawtransaction" , " \" myhex\" " )
6209+ + HelpExampleRpc (" analyzerawtransaction" , " \" myhex\" " )
6210+ },
6211+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
6212+ {
6213+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
6214+ if (!wallet) return NullUniValue;
6215+ CWallet* const pwallet = wallet.get ();
6216+
6217+ RPCTypeCheck (request.params , {UniValue::VSTR}, true );
6218+
6219+ LOCK (pwallet->cs_wallet );
6220+ EnsureWalletIsUnlocked (pwallet);
6221+
6222+ // Decode and unblind the transaction
6223+ CMutableTransaction mtx;
6224+ if (!DecodeHexTx (mtx, request.params [0 ].get_str ())) {
6225+ throw JSONRPCError (RPC_DESERIALIZATION_ERROR, " TX decode failed. Make sure the tx has at least one input." );
6226+ }
6227+
6228+ std::vector<uint256> output_value_blinds;
6229+ std::vector<uint256> output_asset_blinds;
6230+ std::vector<CPubKey> output_pubkeys;
6231+ std::vector<CKey> asset_keys;
6232+ std::vector<CKey> token_keys;
6233+ FillBlinds (pwallet, mtx, output_value_blinds, output_asset_blinds, output_pubkeys, asset_keys, token_keys);
6234+ CTransaction tx (mtx);
6235+
6236+ // Calculate changes (+credit, -debit)
6237+ CAmountMap changes;
6238+
6239+ // Fetch debit; we are *spending* these; if the transaction is signed and broadcast, we will lose everything in these
6240+ for (size_t i = 0 ; i < tx.vin .size (); ++i) {
6241+ CAmountMap debit = pwallet->GetDebit (tx.vin .at (i), ISMINE_SPENDABLE);
6242+ for (const auto & entry : debit) {
6243+ changes[entry.first ] -= entry.second ;
6244+ }
6245+ }
6246+
6247+ // Fetch credit; we are *receiving* these; if the transaciton is signed and broadcast, we will receive everything in these
6248+ for (size_t i = 0 ; i < tx.vout .size (); ++i) {
6249+ const CTxOut& txout = tx.vout .at (i);
6250+ if (!pwallet->IsMine (txout)) continue ;
6251+ if (!txout.nAsset .IsExplicit () || !txout.nValue .IsExplicit ()) {
6252+ throw JSONRPCError (RPC_WALLET_ERROR, " Output belongs to me but I can't unblind it" );
6253+ }
6254+ const auto & asset = txout.nAsset .GetAsset ();
6255+ const auto & value = txout.nValue .GetAmount ();
6256+ changes[asset] += value;
6257+ }
6258+
6259+ return AmountMapToUniv (changes, " " );
6260+ }
6261+ };
6262+ }
6263+
61936264static RPCHelpMan blindrawtransaction ()
61946265{
61956266 return RPCHelpMan{" blindrawtransaction" ,
@@ -7069,6 +7140,7 @@ static const CRPCCommand commands[] =
70697140 { " wallet" , " getpeginaddress" , &getpeginaddress, {} },
70707141 { " wallet" , " claimpegin" , &claimpegin, {" bitcoin_tx" , " txoutproof" , " claim_script" } },
70717142 { " wallet" , " createrawpegin" , &createrawpegin, {" bitcoin_tx" , " txoutproof" , " claim_script" } },
7143+ { " wallet" , " analyzerawtransaction" , &analyzerawtransaction, {" hexstring" } },
70727144 { " wallet" , " blindrawtransaction" , &blindrawtransaction, {" hexstring" , " ignoreblindfail" , " asset_commitments" , " blind_issuances" , " totalblinder" } },
70737145 { " wallet" , " unblindrawtransaction" , &unblindrawtransaction, {" hex" } },
70747146 { " wallet" , " sendtomainchain" , &sendtomainchain, {" address" , " amount" , " subtractfeefromamount" , " verbose" } },
0 commit comments