Skip to content

Commit

Permalink
internal: Add basic simnet xmr swap.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeGruffins committed Aug 28, 2024
1 parent 6ccec62 commit 0fce615
Show file tree
Hide file tree
Showing 6 changed files with 1,469 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ client/cmd/translationsreport/worksheets
server/cmd/dexadm/dexadm
server/cmd/geogame/geogame
internal/libsecp256k1/secp256k1
internal/cmd/xmrswap/xmrswap
2 changes: 1 addition & 1 deletion client/cmd/bisonw-desktop/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module decred.org/dcrdex/client/cmd/bisonw-desktop

go 1.21
go 1.21.10

replace decred.org/dcrdex => ../../..

Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.21
require (
decred.org/dcrwallet/v4 v4.1.1
fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412
github.com/btcsuite/btcd v0.24.2-beta.rc1.0.20240625142744-cc26860b4026
github.com/btcsuite/btcd/btcec/v2 v2.3.4
github.com/btcsuite/btcd/btcutil v1.1.5
Expand Down Expand Up @@ -43,6 +44,7 @@ require (
github.com/decred/go-socks v1.1.0
github.com/decred/slog v1.2.0
github.com/decred/vspd/types/v2 v2.1.0
github.com/dev-warrior777/go-monero v0.1.0
github.com/dgraph-io/badger v1.6.2
github.com/ethereum/go-ethereum v1.14.8
github.com/fatih/color v1.16.0
Expand All @@ -51,6 +53,7 @@ require (
github.com/gcash/bchutil v0.0.0-20210113190856-6ea28dff4000
github.com/go-chi/chi/v5 v5.0.1
github.com/gorilla/websocket v1.5.1
github.com/haven-protocol-org/monero-go-utils v0.0.0-20211126154105-058b2666f217
github.com/huandu/skiplist v1.2.0
github.com/jessevdk/go-flags v1.5.0
github.com/jrick/logrotate v1.0.0
Expand Down Expand Up @@ -81,7 +84,6 @@ require (
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/aead/siphash v1.0.1 // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ github.com/decred/vspd/types/v2 v2.1.0 h1:cUVlmHPeLVsksPRnr2WHsmC2t1Skl6g1WH0Hmp
github.com/decred/vspd/types/v2 v2.1.0/go.mod h1:2xnNqedkt9GuL+pK8uIzDxqYxFlwLRflYFJH64b76n0=
github.com/denis-tingajkin/go-header v0.4.2/go.mod h1:eLRHAVXzE5atsKAnNRDB90WHCFFnBUn4RN0nRcs1LJA=
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE=
github.com/dev-warrior777/go-monero v0.1.0 h1:86JJRiYNk2muLJFWM6kgb7qZh1gE/ETjvjHSW+3Rn5c=
github.com/dev-warrior777/go-monero v0.1.0/go.mod h1:DSf/k695WklA8lTl1EzqNLhtKP3BE3x5KU6tsPrXp4k=
github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8=
github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
Expand Down Expand Up @@ -613,6 +615,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/haven-protocol-org/monero-go-utils v0.0.0-20211126154105-058b2666f217 h1:CflMOYZHhaBo+7up92oOYcesIG+qDCAKdJo+niKBFWM=
github.com/haven-protocol-org/monero-go-utils v0.0.0-20211126154105-058b2666f217/go.mod h1:vSMDRpw62HGWO1Fi9DQwfgs4e3JCbt475GWY/W5DQZI=
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4=
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
Expand Down
239 changes: 239 additions & 0 deletions internal/adaptorsigs/dcr/dcr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
package dcr

import "github.com/decred/dcrd/txscript/v4"

func LockRefundTxScript(kal, kaf []byte, locktime int64) ([]byte, error) {
return txscript.NewScriptBuilder().
AddOp(txscript.OP_IF).
AddOp(txscript.OP_2).
AddData(kal).
AddData(kaf).
AddOp(txscript.OP_2).
AddOp(txscript.OP_CHECKMULTISIG).
AddOp(txscript.OP_ELSE).
AddInt64(locktime).
AddOp(txscript.OP_CHECKSEQUENCEVERIFY).
AddOp(txscript.OP_DROP).
AddData(kaf).
AddOp(txscript.OP_CHECKSIG).
AddOp(txscript.OP_ENDIF).
Script()
}

func LockTxScript(kal, kaf []byte) ([]byte, error) {
return txscript.NewScriptBuilder().
AddOp(txscript.OP_2).
AddData(kal).
AddData(kaf).
AddOp(txscript.OP_2).
AddOp(txscript.OP_CHECKMULTISIG).
Script()
}

// def verifySCLockTx(self, tx_bytes, script_out,
// swap_value,
// Kal, Kaf,
// feerate,
// check_lock_tx_inputs, vkbv=None):
// # Verify:
// #
//
// # Not necessary to check the lock txn is mineable, as protocol will wait for it to confirm
// # However by checking early we can avoid wasting time processing unmineable txns
// # Check fee is reasonable
//
// tx = self.loadTx(tx_bytes)
// txid = self.getTxid(tx)
// self._log.info('Verifying lock tx: {}.'.format(b2h(txid)))
//
// ensure(tx.nVersion == self.txVersion(), 'Bad version')
// ensure(tx.nLockTime == 0, 'Bad nLockTime') # TODO match txns created by cores
//
// script_pk = self.getScriptDest(script_out)
// locked_n = findOutput(tx, script_pk)
// ensure(locked_n is not None, 'Output not found in tx')
// locked_coin = tx.vout[locked_n].nValue
//
// # Check value
// ensure(locked_coin == swap_value, 'Bad locked value')
//
// # Check script
// A, B = self.extractScriptLockScriptValues(script_out)
// ensure(A == Kal, 'Bad script pubkey')
// ensure(B == Kaf, 'Bad script pubkey')
//
// if check_lock_tx_inputs:
// # TODO: Check that inputs are unspent
// # Verify fee rate
// inputs_value = 0
// add_bytes = 0
// add_witness_bytes = getCompactSizeLen(len(tx.vin))
// for pi in tx.vin:
// ptx = self.rpc('getrawtransaction', [i2h(pi.prevout.hash), True])
// prevout = ptx['vout'][pi.prevout.n]
// inputs_value += make_int(prevout['value'])
//
// prevout_type = prevout['scriptPubKey']['type']
// if prevout_type == 'witness_v0_keyhash':
// add_witness_bytes += 107 # sig 72, pk 33 and 2 size bytes
// add_witness_bytes += getCompactSizeLen(107)
// else:
// # Assume P2PKH, TODO more types
// add_bytes += 107 # OP_PUSH72 <ecdsa_signature> OP_PUSH33 <public_key>
//
// outputs_value = 0
// for txo in tx.vout:
// outputs_value += txo.nValue
// fee_paid = inputs_value - outputs_value
// assert (fee_paid > 0)
//
// vsize = self.getTxVSize(tx, add_bytes, add_witness_bytes)
// fee_rate_paid = fee_paid * 1000 // vsize
//
// self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
//
// if not self.compareFeeRates(fee_rate_paid, feerate):
// self._log.warning('feerate paid doesn\'t match expected: %ld, %ld', fee_rate_paid, feerate)
// # TODO: Display warning to user
//
// return txid, locked_n
//
// def verifySCLockRefundTx(self, tx_bytes, lock_tx_bytes, script_out,
// prevout_id, prevout_n, prevout_seq, prevout_script,
// Kal, Kaf, csv_val_expect, swap_value, feerate, vkbv=None):
// # Verify:
// # Must have only one input with correct prevout and sequence
// # Must have only one output to the p2wsh of the lock refund script
// # Output value must be locked_coin - lock tx fee
//
// tx = self.loadTx(tx_bytes)
// txid = self.getTxid(tx)
// self._log.info('Verifying lock refund tx: {}.'.format(b2h(txid)))
//
// ensure(tx.nVersion == self.txVersion(), 'Bad version')
// ensure(tx.nLockTime == 0, 'nLockTime not 0')
// ensure(len(tx.vin) == 1, 'tx doesn\'t have one input')
//
// ensure(tx.vin[0].nSequence == prevout_seq, 'Bad input nSequence')
// ensure(tx.vin[0].scriptSig == self.getScriptScriptSig(prevout_script), 'Input scriptsig mismatch')
// ensure(tx.vin[0].prevout.hash == b2i(prevout_id) and tx.vin[0].prevout.n == prevout_n, 'Input prevout mismatch')
//
// ensure(len(tx.vout) == 1, 'tx doesn\'t have one output')
//
// script_pk = self.getScriptDest(script_out)
// locked_n = findOutput(tx, script_pk)
// ensure(locked_n is not None, 'Output not found in tx')
// locked_coin = tx.vout[locked_n].nValue
//
// # Check script and values
// A, B, csv_val, C = self.extractScriptLockRefundScriptValues(script_out)
// ensure(A == Kal, 'Bad script pubkey')
// ensure(B == Kaf, 'Bad script pubkey')
// ensure(csv_val == csv_val_expect, 'Bad script csv value')
// ensure(C == Kaf, 'Bad script pubkey')
//
// fee_paid = swap_value - locked_coin
// assert (fee_paid > 0)
//
// dummy_witness_stack = self.getScriptLockTxDummyWitness(prevout_script)
// witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
// vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
// fee_rate_paid = fee_paid * 1000 // vsize
//
// self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', locked_coin, vsize, fee_rate_paid)
//
// if not self.compareFeeRates(fee_rate_paid, feerate):
// raise ValueError('Bad fee rate, expected: {}'.format(feerate))
//
// return txid, locked_coin, locked_n
//
// def verifySCLockRefundSpendTx(self, tx_bytes, lock_refund_tx_bytes,
// lock_refund_tx_id, prevout_script,
// Kal,
// prevout_n, prevout_value, feerate, vkbv=None):
// # Verify:
// # Must have only one input with correct prevout (n is always 0) and sequence
// # Must have only one output sending lock refund tx value - fee to leader's address, TODO: follower shouldn't need to verify destination addr
// tx = self.loadTx(tx_bytes)
// txid = self.getTxid(tx)
// self._log.info('Verifying lock refund spend tx: {}.'.format(b2h(txid)))
//
// ensure(tx.nVersion == self.txVersion(), 'Bad version')
// ensure(tx.nLockTime == 0, 'nLockTime not 0')
// ensure(len(tx.vin) == 1, 'tx doesn\'t have one input')
//
// ensure(tx.vin[0].nSequence == 0, 'Bad input nSequence')
// ensure(tx.vin[0].scriptSig == self.getScriptScriptSig(prevout_script), 'Input scriptsig mismatch')
// ensure(tx.vin[0].prevout.hash == b2i(lock_refund_tx_id) and tx.vin[0].prevout.n == 0, 'Input prevout mismatch')
//
// ensure(len(tx.vout) == 1, 'tx doesn\'t have one output')
//
// # Destination doesn't matter to the follower
// '''
// p2wpkh = CScript([OP_0, hash160(Kal)])
// locked_n = findOutput(tx, p2wpkh)
// ensure(locked_n is not None, 'Output not found in lock refund spend tx')
// '''
// tx_value = tx.vout[0].nValue
//
// fee_paid = prevout_value - tx_value
// assert (fee_paid > 0)
//
// dummy_witness_stack = self.getScriptLockRefundSpendTxDummyWitness(prevout_script)
// witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
// vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
// fee_rate_paid = fee_paid * 1000 // vsize
//
// self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx_value, vsize, fee_rate_paid)
//
// if not self.compareFeeRates(fee_rate_paid, feerate):
// raise ValueError('Bad fee rate, expected: {}'.format(feerate))
//
// return True
//
// def verifySCLockSpendTx(self, tx_bytes,
// lock_tx_bytes, lock_tx_script,
// a_pkhash_f, feerate, vkbv=None):
// # Verify:
// # Must have only one input with correct prevout (n is always 0) and sequence
// # Must have only one output with destination and amount
//
// tx = self.loadTx(tx_bytes)
// txid = self.getTxid(tx)
// self._log.info('Verifying lock spend tx: {}.'.format(b2h(txid)))
//
// ensure(tx.nVersion == self.txVersion(), 'Bad version')
// ensure(tx.nLockTime == 0, 'nLockTime not 0')
// ensure(len(tx.vin) == 1, 'tx doesn\'t have one input')
//
// lock_tx = self.loadTx(lock_tx_bytes)
// lock_tx_id = self.getTxid(lock_tx)
//
// output_script = self.getScriptDest(lock_tx_script)
// locked_n = findOutput(lock_tx, output_script)
// ensure(locked_n is not None, 'Output not found in tx')
// locked_coin = lock_tx.vout[locked_n].nValue
//
// ensure(tx.vin[0].nSequence == 0, 'Bad input nSequence')
// ensure(tx.vin[0].scriptSig == self.getScriptScriptSig(lock_tx_script), 'Input scriptsig mismatch')
// ensure(tx.vin[0].prevout.hash == b2i(lock_tx_id) and tx.vin[0].prevout.n == locked_n, 'Input prevout mismatch')
//
// ensure(len(tx.vout) == 1, 'tx doesn\'t have one output')
// p2wpkh = self.getScriptForPubkeyHash(a_pkhash_f)
// ensure(tx.vout[0].scriptPubKey == p2wpkh, 'Bad output destination')
//
// # The value of the lock tx output should already be verified, if the fee is as expected the difference will be the correct amount
// fee_paid = locked_coin - tx.vout[0].nValue
// assert (fee_paid > 0)
//
// dummy_witness_stack = self.getScriptLockTxDummyWitness(lock_tx_script)
// witness_bytes = self.getWitnessStackSerialisedLength(dummy_witness_stack)
// vsize = self.getTxVSize(tx, add_witness_bytes=witness_bytes)
// fee_rate_paid = fee_paid * 1000 // vsize
//
// self._log.info('tx amount, vsize, feerate: %ld, %ld, %ld', tx.vout[0].nValue, vsize, fee_rate_paid)
//
// if not self.compareFeeRates(fee_rate_paid, feerate):
// raise ValueError('Bad fee rate, expected: {}'.format(feerate))
//
// return True
Loading

0 comments on commit 0fce615

Please sign in to comment.