xmr: Add prefunded itx.

This commit is contained in:
tecnovert
2022-12-06 00:45:35 +02:00
parent c90fa6f2c6
commit 7d43512845
9 changed files with 156 additions and 35 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()