diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py
index 3289c7b..7be311e 100644
--- a/basicswap/basicswap.py
+++ b/basicswap/basicswap.py
@@ -2424,11 +2424,17 @@ class BasicSwap(BaseApp):
                 xmr_swap.kbsl_dleag = xmr_swap.pkbsl
 
             # MSG2F
-            xmr_swap.a_lock_tx, xmr_swap.a_lock_tx_script = ci_from.createSCLockTx(
-                bid.amount,
-                xmr_swap.pkal, xmr_swap.pkaf, xmr_swap.vkbv
-            )
-            xmr_swap.a_lock_tx = ci_from.fundSCLockTx(xmr_swap.a_lock_tx, xmr_offer.a_fee_rate, xmr_swap.vkbv)
+            pi = self.pi(SwapTypes.XMR_SWAP)
+            xmr_swap.a_lock_tx_script = pi.genScriptLockTxScript(ci_from, xmr_swap.pkal, xmr_swap.pkaf)
+            prefunded_tx = self.getPreFundedTx(Concepts.OFFER, bid.offer_id, TxTypes.ITX_PRE_FUNDED)
+            if prefunded_tx:
+                xmr_swap.a_lock_tx = pi.promoteMockTx(ci_from, prefunded_tx, xmr_swap.a_lock_tx_script)
+            else:
+                xmr_swap.a_lock_tx = ci_from.createSCLockTx(
+                    bid.amount,
+                    xmr_swap.a_lock_tx_script, xmr_swap.vkbv
+                )
+                xmr_swap.a_lock_tx = ci_from.fundSCLockTx(xmr_swap.a_lock_tx, xmr_offer.a_fee_rate, xmr_swap.vkbv)
 
             xmr_swap.a_lock_tx_id = ci_from.getTxid(xmr_swap.a_lock_tx)
             a_lock_tx_dest = ci_from.getScriptDest(xmr_swap.a_lock_tx_script)
diff --git a/basicswap/interface/btc.py b/basicswap/interface/btc.py
index 2b6c1fa..a96e246 100644
--- a/basicswap/interface/btc.py
+++ b/basicswap/interface/btc.py
@@ -444,19 +444,11 @@ class BTCInterface(CoinInterface):
 
         return pk1, pk2
 
-    def genScriptLockTxScript(self, Kal, Kaf):
-        Kal_enc = Kal if len(Kal) == 33 else self.encodePubkey(Kal)
-        Kaf_enc = Kaf if len(Kaf) == 33 else self.encodePubkey(Kaf)
-
-        return CScript([2, Kal_enc, Kaf_enc, 2, CScriptOp(OP_CHECKMULTISIG)])
-
-    def createSCLockTx(self, value, Kal, Kaf, vkbv=None):
-        script = self.genScriptLockTxScript(Kal, Kaf)
+    def createSCLockTx(self, value: int, script: bytearray, vkbv=None) -> bytes:
         tx = CTransaction()
         tx.nVersion = self.txVersion()
         tx.vout.append(self.txoType()(value, self.getScriptDest(script)))
-
-        return tx.serialize(), script
+        return tx.serialize()
 
     def fundSCLockTx(self, tx_bytes, feerate, vkbv=None):
         return self.fundTx(tx_bytes, feerate)
@@ -1271,6 +1263,7 @@ class BTCInterface(CoinInterface):
 
         sign_for_addr = None
         for addr, value in unspent_addr.items():
+            print('[rm]', value, amount_for)
             if value >= amount_for:
                 sign_for_addr = addr
                 break
diff --git a/basicswap/interface/firo.py b/basicswap/interface/firo.py
index 2490e68..e14bf48 100644
--- a/basicswap/interface/firo.py
+++ b/basicswap/interface/firo.py
@@ -117,13 +117,12 @@ class FIROInterface(BTCInterface):
 
         return rv
 
-    def createSCLockTx(self, value, Kal, Kaf, vkbv=None):
-        script = self.genScriptLockTxScript(Kal, Kaf)
+    def createSCLockTx(self, value: int, script: bytearray, vkbv=None) -> bytes:
         tx = CTransaction()
         tx.nVersion = self.txVersion()
         tx.vout.append(self.txoType()(value, self.getScriptDest(script)))
 
-        return tx.serialize(), script
+        return tx.serialize()
 
     def fundSCLockTx(self, tx_bytes, feerate, vkbv=None):
         return self.fundTx(tx_bytes, feerate)
diff --git a/basicswap/interface/part.py b/basicswap/interface/part.py
index ade3b64..bc542e1 100644
--- a/basicswap/interface/part.py
+++ b/basicswap/interface/part.py
@@ -166,8 +166,7 @@ class PARTInterfaceBlind(PARTInterface):
             ensure(v['result'] is True, 'verifycommitment failed')
         return output_n, blinded_info
 
-    def createSCLockTx(self, value, Kal, Kaf, vkbv):
-        script = self.genScriptLockTxScript(Kal, Kaf)
+    def createSCLockTx(self, value: int, script: bytearray, vkbv) -> bytes:
 
         # Nonce is derived from vkbv, ephemeral_key isn't used
         ephemeral_key = i2b(self.getNewSecretKey())
@@ -181,7 +180,7 @@ class PARTInterfaceBlind(PARTInterface):
         rv = self.rpc_callback('createrawparttransaction', params)
 
         tx_bytes = bytes.fromhex(rv['hex'])
-        return tx_bytes, script
+        return tx_bytes
 
     def fundSCLockTx(self, tx_bytes, feerate, vkbv):
         feerate_str = self.format_amount(feerate)
diff --git a/basicswap/protocols/__init__.py b/basicswap/protocols/__init__.py
index 13402f8..1c4769f 100644
--- a/basicswap/protocols/__init__.py
+++ b/basicswap/protocols/__init__.py
@@ -4,9 +4,21 @@
 # Distributed under the MIT software license, see the accompanying
 # file LICENSE or http://www.opensource.org/licenses/mit-license.php.
 
+from basicswap.script import (
+    OpCodes,
+)
+
 
 class ProtocolInterface:
     swap_type = None
 
     def getFundedInitiateTxTemplate(self, ci, amount: int, sub_fee: bool) -> bytes:
         raise ValueError('base class')
+
+    def getMockScript(self) -> bytearray:
+        return bytearray([
+            OpCodes.OP_RETURN, OpCodes.OP_1])
+
+    def getMockScriptScriptPubkey(self, ci) -> bytearray:
+        script = self.getMockScript()
+        return ci.get_p2wsh_script_pubkey(script) if ci._use_segwit else ci.get_p2sh_script_pubkey(script)
diff --git a/basicswap/protocols/atomic_swap_1.py b/basicswap/protocols/atomic_swap_1.py
index 4917947..37f5161 100644
--- a/basicswap/protocols/atomic_swap_1.py
+++ b/basicswap/protocols/atomic_swap_1.py
@@ -76,13 +76,12 @@ def redeemITx(self, bid_id, session):
 class AtomicSwapInterface(ProtocolInterface):
     swap_type = SwapTypes.SELLER_FIRST
 
-    def getMockScript(self) -> bytearray:
-        return bytearray([
-            OpCodes.OP_RETURN, OpCodes.OP_1])
-
-    def getMockScriptScriptPubkey(self, ci) -> bytearray:
+    def getFundedInitiateTxTemplate(self, ci, amount: int, sub_fee: bool) -> bytes:
         script = self.getMockScript()
-        return ci.get_p2wsh_script_pubkey(script) if ci._use_segwit else ci.get_p2sh_script_pubkey(script)
+        addr_to = ci.encode_p2wsh(getP2WSH(script)) if ci._use_segwit else ci.encode_p2sh(script)
+        funded_tx = ci.createRawFundedTransaction(addr_to, amount, sub_fee, lock_unspents=False)
+
+        return bytes.fromhex(funded_tx)
 
     def promoteMockTx(self, ci, mock_tx: bytes, script: bytearray) -> bytearray:
         mock_txo_script = self.getMockScriptScriptPubkey(ci)
@@ -103,11 +102,3 @@ class AtomicSwapInterface(ProtocolInterface):
 
         funded_tx = ctx.serialize()
         return ci.signTxWithWallet(funded_tx)
-
-    def getFundedInitiateTxTemplate(self, ci, amount: int, sub_fee: bool) -> bytes:
-
-        script = self.getMockScript()
-        addr_to = ci.encode_p2wsh(getP2WSH(script)) if ci._use_segwit else ci.encode_p2sh(script)
-        funded_tx = ci.createRawFundedTransaction(addr_to, amount, sub_fee, lock_unspents=False)
-
-        return bytes.fromhex(funded_tx)
diff --git a/basicswap/protocols/xmr_swap_1.py b/basicswap/protocols/xmr_swap_1.py
index 240ff07..8cc03a6 100644
--- a/basicswap/protocols/xmr_swap_1.py
+++ b/basicswap/protocols/xmr_swap_1.py
@@ -9,6 +9,9 @@ from sqlalchemy.orm import scoped_session
 from basicswap.util import (
     ensure,
 )
+from basicswap.util.script import (
+    getP2WSH,
+)
 from basicswap.chainparams import (
     Coins,
 )
@@ -18,6 +21,9 @@ from basicswap.basicswap_util import (
     EventLogTypes,
 )
 from . import ProtocolInterface
+from basicswap.contrib.test_framework.script import (
+    CScript, CScriptOp,
+    OP_CHECKMULTISIG)
 
 
 def addLockRefundSigs(self, xmr_swap, ci):
@@ -90,3 +96,35 @@ def getChainBSplitKey(swap_client, bid, xmr_swap, offer):
 
 class XmrSwapInterface(ProtocolInterface):
     swap_type = SwapTypes.XMR_SWAP
+
+    def genScriptLockTxScript(self, ci, Kal: bytes, Kaf: bytes) -> CScript:
+        Kal_enc = Kal if len(Kal) == 33 else ci.encodePubkey(Kal)
+        Kaf_enc = Kaf if len(Kaf) == 33 else ci.encodePubkey(Kaf)
+
+        return CScript([2, Kal_enc, Kaf_enc, 2, CScriptOp(OP_CHECKMULTISIG)])
+
+    def getFundedInitiateTxTemplate(self, ci, amount: int, sub_fee: bool) -> bytes:
+        script = self.getMockScript()
+        addr_to = ci.encode_p2wsh(getP2WSH(script)) if ci._use_segwit else ci.encode_p2sh(script)
+        funded_tx = ci.createRawFundedTransaction(addr_to, amount, sub_fee, lock_unspents=False)
+
+        return bytes.fromhex(funded_tx)
+
+    def promoteMockTx(self, ci, mock_tx: bytes, script: bytearray) -> bytearray:
+        mock_txo_script = self.getMockScriptScriptPubkey(ci)
+        real_txo_script = ci.getScriptDest(script)
+
+        found: int = 0
+        ctx = ci.loadTx(mock_tx)
+        for txo in ctx.vout:
+            if txo.scriptPubKey == mock_txo_script:
+                txo.scriptPubKey = real_txo_script
+                found += 1
+
+        if found < 1:
+            raise ValueError('Mocked output not found')
+        if found > 1:
+            raise ValueError('Too many mocked outputs found')
+        ctx.nLockTime = 0
+
+        return ctx.serialize()
diff --git a/tests/basicswap/test_run.py b/tests/basicswap/test_run.py
index f823120..85e71f1 100644
--- a/tests/basicswap/test_run.py
+++ b/tests/basicswap/test_run.py
@@ -560,6 +560,16 @@ class Test(BaseTest):
         wait_for_bid(test_delay_event, swap_clients[2], bid_id, BidStates.SWAP_COMPLETED, wait_for=60)
         wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=60)
 
+        # Verify expected inputs were used
+        bid, offer = swap_clients[2].getBidAndOffer(bid_id)
+        assert (bid.initiate_tx)
+        wtx = ci.rpc_callback('gettransaction', [bid.initiate_tx.txid.hex(),])
+        itx_after = ci.describeTx(wtx['hex'])
+        assert (len(itx_after['vin']) == len(itx_decoded['vin']))
+        for i, txin in enumerate(itx_decoded['vin']):
+            assert (txin['txid'] == itx_after['vin'][i]['txid'])
+            assert (txin['vout'] == itx_after['vin'][i]['vout'])
+
     def pass_99_delay(self):
         logging.info('Delay')
         for i in range(60 * 10):
diff --git a/tests/basicswap/test_xmr.py b/tests/basicswap/test_xmr.py
index 993b3c5..e43c38c 100644
--- a/tests/basicswap/test_xmr.py
+++ b/tests/basicswap/test_xmr.py
@@ -75,6 +75,7 @@ from tests.basicswap.common import (
     wait_for_no_offer,
     wait_for_none_active,
     wait_for_balance,
+    wait_for_unspent,
     compare_bid_states,
     extract_states_from_xu_file,
     TEST_HTTP_HOST,
@@ -1244,6 +1245,78 @@ class Test(BaseTest):
         swap_clients[0].abandonBid(bid_id)
         swap_clients[1].abandonBid(bid_id)
 
+    def test_14_sweep_balance(self):
+        logging.info('---------- Test sweep balance offer')
+        swap_clients = self.swap_clients
+
+        # Disable staking
+        walletsettings = callnoderpc(2, 'walletsettings', ['stakingoptions', ])
+        walletsettings['enabled'] = False
+        walletsettings = callnoderpc(2, 'walletsettings', ['stakingoptions', walletsettings])
+        walletsettings = callnoderpc(2, 'walletsettings', ['stakingoptions', ])
+        assert (walletsettings['stakingoptions']['enabled'] is False)
+
+        # Prepare balance
+        js_w2 = read_json_api(1802, 'wallets')
+        if float(js_w2['PART']['balance']) < 100.0:
+            post_json = {
+                'value': 100,
+                'address': js_w2['PART']['deposit_address'],
+                'subfee': False,
+            }
+            json_rv = read_json_api(TEST_HTTP_PORT + 0, 'wallets/part/withdraw', post_json)
+            assert (len(json_rv['txid']) == 64)
+            wait_for_balance(test_delay_event, 'http://127.0.0.1:1802/json/wallets/part', 'balance', 100.0)
+
+        js_w2 = read_json_api(1802, 'wallets')
+        assert (float(js_w2['PART']['balance']) >= 100.0)
+
+        js_w2 = read_json_api(1802, 'wallets')
+        post_json = {
+            'value': float(js_w2['PART']['balance']),
+            'address': read_json_api(1802, 'wallets/part/nextdepositaddr'),
+            'subfee': True,
+        }
+        json_rv = read_json_api(TEST_HTTP_PORT + 2, 'wallets/part/withdraw', post_json)
+        wait_for_balance(test_delay_event, 'http://127.0.0.1:1802/json/wallets/part', 'balance', 10.0)
+        assert (len(json_rv['txid']) == 64)
+
+        # Create prefunded ITX
+        ci = swap_clients[2].ci(Coins.PART)
+        pi = swap_clients[2].pi(SwapTypes.XMR_SWAP)
+        js_w2 = read_json_api(1802, 'wallets')
+        swap_value = ci.make_int(js_w2['PART']['balance'])
+
+        itx = pi.getFundedInitiateTxTemplate(ci, swap_value, True)
+        itx_decoded = ci.describeTx(itx.hex())
+        value_after_subfee = ci.make_int(itx_decoded['vout'][0]['value'])
+        assert (value_after_subfee < swap_value)
+        swap_value = value_after_subfee
+        wait_for_unspent(test_delay_event, ci, swap_value)
+
+        extra_options = {'prefunded_itx': itx}
+        offer_id = swap_clients[2].postOffer(Coins.PART, Coins.XMR, swap_value, 2 * COIN, swap_value, SwapTypes.XMR_SWAP, extra_options=extra_options)
+
+        wait_for_offer(test_delay_event, swap_clients[1], offer_id)
+        offer = swap_clients[1].getOffer(offer_id)
+        bid_id = swap_clients[1].postBid(offer_id, offer.amount_from)
+
+        wait_for_bid(test_delay_event, swap_clients[2], bid_id, BidStates.BID_RECEIVED)
+        swap_clients[2].acceptBid(bid_id)
+
+        wait_for_bid(test_delay_event, swap_clients[2], bid_id, BidStates.SWAP_COMPLETED, wait_for=120)
+        wait_for_bid(test_delay_event, swap_clients[1], bid_id, BidStates.SWAP_COMPLETED, sent=True, wait_for=120)
+
+        # Verify expected inputs were used
+        bid, _, _, _, _ = swap_clients[2].getXmrBidAndOffer(bid_id)
+        assert (bid.xmr_a_lock_tx)
+        wtx = ci.rpc_callback('gettransaction', [bid.xmr_a_lock_tx.txid.hex(),])
+        itx_after = ci.describeTx(wtx['hex'])
+        assert (len(itx_after['vin']) == len(itx_decoded['vin']))
+        for i, txin in enumerate(itx_decoded['vin']):
+            assert (txin['txid'] == itx_after['vin'][i]['txid'])
+            assert (txin['vout'] == itx_after['vin'][i]['vout'])
+
     def test_98_withdraw_all(self):
         logging.info('---------- Test XMR withdrawal all')
         try: