DLC <-> contact mapping

This commit is contained in:
rorp 2022-05-18 12:08:16 -07:00
parent 2af7923f3b
commit cfee8cf7e4
20 changed files with 725 additions and 72 deletions

View file

@ -2,6 +2,7 @@ package org.bitcoins.commons
import org.bitcoins.commons.serializers.Picklers
import org.bitcoins.commons.serializers.Picklers._
import org.bitcoins.core.api.dlc.wallet.db.DLCContactDb
import org.bitcoins.core.currency.{CurrencyUnit, Satoshis}
import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.protocol.dlc.models.DLCMessage._
@ -17,6 +18,8 @@ import org.bitcoins.testkitcore.util.BitcoinSJvmTest
import org.scalacheck.Gen
import upickle.default._
import java.net.InetSocketAddress
class DLCStatusTest extends BitcoinSJvmTest {
behavior of "DLCStatus"
@ -29,6 +32,12 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Some(
DLCContactDb(address =
InetSocketAddress.createUnresolved("127.0.0.1", 0),
alias = "alias",
memo = "memo"))
val status =
DLCStatus.Offered(
Sha256Digest.empty,
@ -40,7 +49,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
offer.feeRate,
totalCollateral,
offer.collateral,
payoutAddress
payoutAddress,
contact
)
assert(status.state == DLCState.Offered)
@ -66,6 +76,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
"tb1q4ps6c9ewa7uca5v39fakykq9q6hpgjkxje8gve"),
true))
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Accepted(
Sha256Digest.empty,
@ -78,7 +90,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
offer.feeRate,
totalCollateral,
offer.collateral,
payoutAddress
payoutAddress,
contact
)
assert(status.state == DLCState.Accepted)
@ -100,6 +113,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Signed(
Sha256Digest.empty,
@ -113,7 +128,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
totalCollateral,
offer.collateral,
txId,
payoutAddress
payoutAddress,
contact
)
assert(status.state == DLCState.Signed)
@ -135,6 +151,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Broadcasted(
Sha256Digest.empty,
@ -148,7 +166,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
totalCollateral,
offer.collateral,
fundingTxId,
payoutAddress
payoutAddress,
contact
)
assert(status.state == DLCState.Broadcasted)
@ -170,6 +189,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Confirmed(
Sha256Digest.empty,
@ -183,7 +204,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
totalCollateral,
offer.collateral,
fundingTxId,
payoutAddress
payoutAddress,
contact = contact
)
assert(status.state == DLCState.Confirmed)
@ -216,6 +238,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Claimed(
Sha256Digest.empty,
@ -234,7 +258,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
outcome,
myPayout = myPayout,
counterPartyPayout = theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contact
)
assert(status.state == DLCState.Claimed)
@ -270,6 +295,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.RemoteClaimed(
Sha256Digest.empty,
@ -288,7 +315,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
outcome,
myPayout = myPayout,
counterPartyPayout = theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contact
)
assert(status.state == DLCState.RemoteClaimed)
@ -320,6 +348,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
val payoutAddress = Option.empty[PayoutAddress]
val contact = Option.empty[DLCContactDb]
val status =
DLCStatus.Refunded(
Sha256Digest.empty,
@ -336,7 +366,8 @@ class DLCStatusTest extends BitcoinSJvmTest {
closingTxId,
myPayout = myPayout,
counterPartyPayout = theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contact
)
assert(status.state == DLCState.Refunded)

View file

@ -1,6 +1,7 @@
package org.bitcoins.commons.rpc
import org.bitcoins.core.api.dlc.wallet.db.DLCContactDb
import org.bitcoins.crypto.Sha256Digest
import java.net.{InetSocketAddress, URI}
import scala.util.{Failure, Try}
@ -84,3 +85,53 @@ object ContactRemove {
}
}
}
case class DLCContactAdd(dlcId: Sha256Digest, address: InetSocketAddress)
extends CommandRpc
with AppServerCliCommand
object DLCContactAdd {
val empty: DLCContactAdd =
DLCContactAdd(Sha256Digest.empty,
InetSocketAddress.createUnresolved("127.0.0.1", 9999))
def fromJsArr(arr: ujson.Arr): Try[DLCContactAdd] = {
arr.arr.toList match {
case dlcIdJs :: addressJs :: Nil =>
Try {
val dlcId = Sha256Digest.fromHex(dlcIdJs.str)
val address = {
val uri = new URI(s"tcp://${addressJs.str}")
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
}
DLCContactAdd(dlcId, address)
}
case other =>
val exn = new IllegalArgumentException(
s"Bad number or arguments to dlc-contact-add, got=${other.length} expected=2")
Failure(exn)
}
}
}
case class DLCContactRemove(dlcId: Sha256Digest)
extends CommandRpc
with AppServerCliCommand
object DLCContactRemove {
def fromJsArr(arr: ujson.Arr): Try[DLCContactRemove] = {
arr.arr.toList match {
case dlcIdJs :: Nil =>
Try {
val dlcId = Sha256Digest.fromHex(dlcIdJs.str)
DLCContactRemove(dlcId)
}
case other =>
val exn = new IllegalArgumentException(
s"Bad number or arguments to contact-remove, got=${other.length} expected=1")
Failure(exn)
}
}
}

View file

@ -815,7 +815,13 @@ object Picklers {
writer[Value].comap { payoutAddressOpt =>
payoutAddressOpt
.map(pa => writeJs(pa))
.getOrElse(Null)
.getOrElse(ujson.Null)
}
implicit val optionContactDbW: Writer[Option[DLCContactDb]] =
writer[Value].comap {
case Some(contact) => writeContactDb(contact)
case None => ujson.Null
}
implicit val offeredW: Writer[Offered] =
@ -836,7 +842,8 @@ object Picklers {
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -859,7 +866,8 @@ object Picklers {
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -881,7 +889,8 @@ object Picklers {
"totalCollateral" -> Num(totalCollateral.satoshis.toLong.toDouble),
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -905,7 +914,8 @@ object Picklers {
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"fundingTxId" -> Str(fundingTxId.hex),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -928,7 +938,8 @@ object Picklers {
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"fundingTxId" -> Str(fundingTxId.hex),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -952,7 +963,8 @@ object Picklers {
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"fundingTxId" -> Str(fundingTxId.hex),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -976,7 +988,8 @@ object Picklers {
"localCollateral" -> Num(localCollateral.satoshis.toLong.toDouble),
"remoteCollateral" -> Num(remoteCollateral.satoshis.toLong.toDouble),
"fundingTxId" -> Str(fundingTxId.hex),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -1019,7 +1032,8 @@ object Picklers {
claimed.counterPartyPayout.satoshis.toLong.toDouble),
PicklerKeys.pnl -> Num(claimed.pnl.satoshis.toLong.toDouble),
PicklerKeys.rateOfReturn -> Num(claimed.rateOfReturn.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -1062,7 +1076,8 @@ object Picklers {
remoteClaimed.counterPartyPayout.satoshis.toLong.toDouble),
PicklerKeys.pnl -> Num(remoteClaimed.pnl.satoshis.toLong.toDouble),
PicklerKeys.rateOfReturn -> Num(remoteClaimed.rateOfReturn.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -1091,7 +1106,8 @@ object Picklers {
refunded.counterPartyPayout.satoshis.toLong.toDouble),
PicklerKeys.pnl -> Num(refunded.pnl.satoshis.toLong.toDouble),
PicklerKeys.rateOfReturn -> Num(refunded.rateOfReturn.toDouble),
"payoutAddress" -> writeJs(payoutAddress)
"payoutAddress" -> writeJs(payoutAddress),
"contact" -> writeJs(contact)
)
}
@ -1163,6 +1179,9 @@ object Picklers {
val feeRate = SatoshisPerVirtualByte.fromLong(obj("feeRate").num.toLong)
val totalCollateral = Satoshis(obj("totalCollateral").num.toLong)
val localCollateral = Satoshis(obj("localCollateral").num.toLong)
val contactOpt =
if (obj("contact").isNull) None
else Some(readContactDb(obj("contact").obj))
lazy val contractId = ByteVector.fromValidHex(obj("contractId").str)
lazy val fundingTxId = DoubleSha256DigestBE(obj("fundingTxId").str)
@ -1232,7 +1251,8 @@ object Picklers {
feeRate,
totalCollateral,
localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.AcceptComputingAdaptorSigs =>
AcceptedComputingAdaptorSigs(
@ -1246,7 +1266,8 @@ object Picklers {
feeRate,
totalCollateral,
localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Accepted =>
Accepted(
@ -1260,7 +1281,8 @@ object Picklers {
feeRate,
totalCollateral,
localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.SignComputingAdaptorSigs =>
SignedComputingAdaptorSigs(
@ -1275,7 +1297,8 @@ object Picklers {
totalCollateral,
localCollateral,
fundingTxId,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Signed =>
Signed(
@ -1290,7 +1313,8 @@ object Picklers {
totalCollateral,
localCollateral,
fundingTxId,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Broadcasted =>
Broadcasted(
@ -1305,7 +1329,8 @@ object Picklers {
totalCollateral,
localCollateral,
fundingTxId,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Confirmed =>
Confirmed(
@ -1320,7 +1345,8 @@ object Picklers {
totalCollateral,
localCollateral,
fundingTxId,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Claimed =>
Claimed(
@ -1340,7 +1366,8 @@ object Picklers {
oracleOutcome,
myPayout = myPayoutOpt.get,
counterPartyPayout = theirPayoutOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.RemoteClaimed =>
require(oracleSigs.size == 1,
@ -1362,7 +1389,8 @@ object Picklers {
oracleOutcome,
myPayout = myPayoutOpt.get,
counterPartyPayout = theirPayoutOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Refunded =>
Refunded(
@ -1380,7 +1408,8 @@ object Picklers {
closingTxId,
myPayout = myPayoutOpt.get,
counterPartyPayout = theirPayoutOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
}
}

View file

@ -7,6 +7,7 @@ import org.bitcoins.core.currency.{Bitcoins, Satoshis}
import org.bitcoins.core.protocol.dlc.models.ContractInfo
import org.bitcoins.core.protocol.tlv.OracleAnnouncementTLV
import org.bitcoins.core.serializers.PicklerKeys
import org.bitcoins.crypto.Sha256Digest
import org.bitcoins.dlc.node.DLCNode
import org.bitcoins.server.routes.ServerCommand
import org.bitcoins.testkit.BitcoinSTestAppConfig
@ -205,5 +206,42 @@ class DLCRoutesSpec
assert(responseAs[String] == s"""{"result":"ok","error":null}""")
}
}
"dlc-contact-add a peer" in {
(mockWallet
.addDLCContactMapping(_: Sha256Digest, _: InetSocketAddress))
.expects(Sha256Digest.empty, expected.address)
.returning(Future.unit)
val args =
ujson.Arr(ujson.Str(Sha256Digest.empty.hex), ujson.Str(address))
val route =
dlcRoutes.handleCommand(ServerCommand("dlc-contact-add", args))
Post() ~> route ~> check {
assert(contentType == ContentTypes.`application/json`)
assert(responseAs[String] == s"""{"result":"ok","error":null}""")
}
}
"dlc-contact-remove a peer" in {
(mockWallet
.removeDLCContactMapping(_: Sha256Digest))
.expects(Sha256Digest.empty)
.returning(Future.unit)
val args = ujson.Arr(ujson.Str(Sha256Digest.empty.hex))
val route =
dlcRoutes.handleCommand(ServerCommand("dlc-contact-remove", args))
Post() ~> route ~> check {
assert(contentType == ContentTypes.`application/json`)
assert(responseAs[String] == s"""{"result":"ok","error":null}""")
}
}
}
}

View file

@ -75,7 +75,8 @@ class WalletRoutesSpec
feeRate = null,
totalCollateral = null,
localCollateral = null,
payoutAddress = None
payoutAddress = None,
contact = None
)
(mockWalletApi.findDLCByTemporaryContractId: Sha256Digest => Future[

View file

@ -3,7 +3,12 @@ package org.bitcoins.server
import akka.actor.ActorSystem
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._
import org.bitcoins.commons.rpc.{ContactAdd, ContactRemove}
import org.bitcoins.commons.rpc.{
ContactAdd,
ContactRemove,
DLCContactAdd,
DLCContactRemove
}
import org.bitcoins.commons.serializers.Picklers
import org.bitcoins.core.api.dlc.node.DLCNodeApi
import org.bitcoins.core.api.dlc.wallet.db.IncomingDLCOfferDb
@ -159,5 +164,28 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
}
}
case ServerCommand("dlc-contact-add", arr) =>
withValidServerCommand(DLCContactAdd.fromJsArr(arr)) { dlcContactAdd =>
complete {
dlcNode.wallet
.addDLCContactMapping(dlcContactAdd.dlcId, dlcContactAdd.address)
.map { _ =>
Server.httpSuccess("ok")
}
}
}
case ServerCommand("dlc-contact-remove", arr) =>
withValidServerCommand(DLCContactRemove.fromJsArr(arr)) {
dlcContactRemove =>
complete {
dlcNode.wallet
.removeDLCContactMapping(dlcContactRemove.dlcId)
.map { _ =>
Server.httpSuccess("ok")
}
}
}
}
}

View file

@ -650,6 +650,30 @@ object SendToAddress extends ServerJsonModels {
}
case class GetDLCs(contactId: Option[InetSocketAddress])
object GetDLCs extends ServerJsonModels {
def fromJsArr(jsArr: ujson.Arr): Try[GetDLCs] = {
jsArr.arr.toList match {
case addressJs :: Nil =>
Try {
val address = {
val uri = new URI(s"tcp://${addressJs.str}")
InetSocketAddress.createUnresolved(uri.getHost, uri.getPort)
}
GetDLCs(Some(address))
}
case Nil =>
Try(GetDLCs(None))
case other =>
Failure(
new IllegalArgumentException(
s"Bad number of arguments: ${other.length}. Expected: 1"))
}
}
}
case class GetDLC(dlcId: Sha256Digest)
object GetDLC extends ServerJsonModels {

View file

@ -300,11 +300,22 @@ case class WalletRoutes(wallet: AnyDLCHDWalletApi)(implicit
}
}
case ServerCommand("getdlcs", _) =>
complete {
wallet.listDLCs().map { dlcs =>
Server.httpSuccess(dlcs.map(writeJs(_)))
}
case ServerCommand("getdlcs", arr) =>
GetDLCs.fromJsArr(arr) match {
case Success(GetDLCs(Some(contactId))) =>
complete {
wallet.listDLCsByContact(contactId).map { dlcs =>
Server.httpSuccess(dlcs.map(writeJs(_)))
}
}
case Success(GetDLCs(None)) =>
complete {
wallet.listDLCs().map { dlcs =>
Server.httpSuccess(dlcs.map(writeJs(_)))
}
}
case Failure(exception) =>
complete(Server.httpBadRequest(exception))
}
case ServerCommand("getdlc", arr) =>

View file

@ -170,6 +170,14 @@ trait DLCWalletApi { self: WalletApi =>
def removeDLCContact(address: InetSocketAddress): Future[Unit]
def findDLCContacts(alias: String): Future[Vector[DLCContactDb]]
def addDLCContactMapping(
dlcId: Sha256Digest,
contactId: InetSocketAddress): Future[Unit]
def removeDLCContactMapping(dlcId: Sha256Digest): Future[Unit]
def listDLCsByContact(address: InetSocketAddress): Future[Vector[DLCStatus]]
}
/** An HDWallet that supports DLCs and both Neutrino and SPV methods of syncing */

View file

@ -1,5 +1,6 @@
package org.bitcoins.core.protocol.dlc.models
import org.bitcoins.core.api.dlc.wallet.db.DLCContactDb
import org.bitcoins.core.currency.CurrencyUnit
import org.bitcoins.core.dlc.accounting.{DLCAccounting, RateOfReturnUtil}
import org.bitcoins.core.protocol.BitcoinAddress
@ -35,6 +36,7 @@ sealed trait DLCStatus {
def localCollateral: CurrencyUnit
def remoteCollateral: CurrencyUnit = totalCollateral - localCollateral
def payoutAddress: Option[PayoutAddress]
def contact: Option[DLCContactDb]
lazy val announcements: Vector[OracleAnnouncementTLV] = {
oracleInfos.flatMap(_.singleOracleInfos.map(_.announcement))
@ -92,7 +94,8 @@ object DLCStatus {
feeRate: FeeUnit,
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
payoutAddress: Option[PayoutAddress]
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb]
) extends DLCStatus {
override val state: DLCState.Offered.type = DLCState.Offered
}
@ -108,7 +111,8 @@ object DLCStatus {
feeRate: FeeUnit,
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends AcceptedDLCStatus {
override val state: DLCState.AcceptComputingAdaptorSigs.type =
@ -126,7 +130,8 @@ object DLCStatus {
feeRate: FeeUnit,
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends AcceptedDLCStatus {
override val state: DLCState.Accepted.type = DLCState.Accepted
}
@ -143,7 +148,8 @@ object DLCStatus {
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends SignedDLCStatus {
override val state: DLCState.SignComputingAdaptorSigs.type =
@ -162,7 +168,8 @@ object DLCStatus {
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends SignedDLCStatus {
override val state: DLCState.Signed.type = DLCState.Signed
}
@ -179,7 +186,8 @@ object DLCStatus {
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends SignedDLCStatus {
override val state: DLCState.Broadcasted.type = DLCState.Broadcasted
}
@ -196,7 +204,8 @@ object DLCStatus {
totalCollateral: CurrencyUnit,
localCollateral: CurrencyUnit,
fundingTxId: DoubleSha256DigestBE,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends SignedDLCStatus {
override val state: DLCState.Confirmed.type = DLCState.Confirmed
}
@ -218,7 +227,8 @@ object DLCStatus {
oracleOutcome: OracleOutcome,
myPayout: CurrencyUnit,
counterPartyPayout: CurrencyUnit,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends ClaimedDLCStatus {
override val state: DLCState.Claimed.type = DLCState.Claimed
}
@ -240,7 +250,8 @@ object DLCStatus {
oracleOutcome: OracleOutcome,
myPayout: CurrencyUnit,
counterPartyPayout: CurrencyUnit,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends ClaimedDLCStatus {
override val state: DLCState.RemoteClaimed.type = DLCState.RemoteClaimed
override val oracleSigs: Vector[SchnorrDigitalSignature] = Vector(oracleSig)
@ -261,7 +272,8 @@ object DLCStatus {
closingTxId: DoubleSha256DigestBE,
myPayout: CurrencyUnit,
counterPartyPayout: CurrencyUnit,
payoutAddress: Option[PayoutAddress])
payoutAddress: Option[PayoutAddress],
contact: Option[DLCContactDb])
extends ClosedDLCStatus {
override val state: DLCState.Refunded.type = DLCState.Refunded
}

View file

@ -83,13 +83,13 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg {
val result = dlcDbManagement.migrate()
dlcAppConfig.driver match {
case SQLite =>
val expected = 7
val expected = 8
assert(result.migrationsExecuted == expected)
val flywayInfo = dlcAppConfig.info()
assert(flywayInfo.applied().length == expected)
assert(flywayInfo.pending().length == 0)
case PostgreSQL =>
val expected = 8
val expected = 9
assert(result.migrationsExecuted == expected)
val flywayInfo = dlcAppConfig.info()

View file

@ -0,0 +1,217 @@
package org.bitcoins.dlc.wallet
import org.bitcoins.core.api.dlc.wallet.db.{DLCContactDb, DLCDb}
import org.bitcoins.crypto.Sha256Digest
import org.bitcoins.dlc.wallet.models.{DLCContactMapping, DLCContactMappingDb}
import org.bitcoins.testkit.fixtures.DLCDAOFixture
import org.bitcoins.testkit.wallet.{BitcoinSWalletTest, DLCWalletUtil}
import java.net.InetSocketAddress
import java.sql.SQLException
class DLCContactMappingDAOTest extends BitcoinSWalletTest with DLCDAOFixture {
behavior of "DLCContactMappingDAO"
val dlcDb1: DLCDb = DLCWalletUtil.sampleDLCDb
val dlcDb2: DLCDb = DLCWalletUtil.sampleDLCDb.copy(
dlcId = Sha256Digest.fromBytes(dlcDb1.dlcId.bytes.reverse),
tempContractId =
Sha256Digest.fromBytes(dlcDb1.tempContractId.bytes.reverse))
val address1 = InetSocketAddress.createUnresolved("127.0.0.1", 1)
val address2 = InetSocketAddress.createUnresolved("127.0.0.1", 2)
val contactDb1: DLCContactDb = DLCContactDb(
address = address1,
alias = "1",
memo = "memo 1"
)
val contactDb2: DLCContactDb = DLCContactDb(
address = address2,
alias = "2",
memo = "memo 2"
)
it should "insert rows and enforce foreign keys" in { daos =>
val dao = daos.dlcContactMappingDAO
for {
// no such DLC
_ <- recoverToSucceededIf[SQLException](
dao.create(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
)))
_ <- daos.dlcDAO.create(dlcDb1)
// no such contact
_ <- recoverToSucceededIf[SQLException](
dao.create(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
)))
_ <- daos.contactDAO.create(contactDb1)
// both DLC and contact exist
created <- dao.create(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
))
read <- dao.read(dlcDb1.dlcId)
} yield {
assert(read.isDefined)
assert(read.get == created)
assert(created.dlcId == dlcDb1.dlcId)
assert(created.contactId == contactDb1.address)
}
}
it should "update rows and enforce foreign keys" in { daos =>
val dao = daos.dlcContactMappingDAO
for {
_ <- daos.dlcDAO.create(dlcDb1)
_ <- daos.contactDAO.create(contactDb1)
_ <- dao.create(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
))
// no such contact
_ <- recoverToSucceededIf[SQLException](
dao.update(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb2.address
)))
_ <- daos.contactDAO.create(contactDb2)
updated <- dao.update(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb2.address
))
read <- dao.read(dlcDb1.dlcId)
} yield {
assert(read.isDefined)
assert(read.get == updated)
assert(updated.dlcId == dlcDb1.dlcId)
assert(updated.contactId == contactDb2.address)
}
}
it should "upsert rows and enforce foreign keys" in { daos =>
val dao = daos.dlcContactMappingDAO
for {
// no such DLC
_ <- recoverToSucceededIf[SQLException](
dao.upsert(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
)))
_ <- daos.dlcDAO.create(dlcDb1)
// no such contact
_ <- recoverToSucceededIf[SQLException](
dao.upsert(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
)))
_ <- daos.contactDAO.create(contactDb1)
// both DLC and contact exist
upserted1 <- dao.upsert(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb1.address
))
read1 <- dao.read(dlcDb1.dlcId)
_ <- daos.contactDAO.create(contactDb2)
upserted2 <- dao.upsert(
DLCContactMappingDb(
dlcDb1.dlcId,
contactDb2.address
))
read2 <- dao.read(dlcDb1.dlcId)
} yield {
assert(read1.isDefined)
assert(read1.get == upserted1)
assert(upserted1.dlcId == dlcDb1.dlcId)
assert(upserted1.contactId == contactDb1.address)
assert(read2.isDefined)
assert(read2.get == upserted2)
assert(upserted2.dlcId == dlcDb1.dlcId)
assert(upserted2.contactId == contactDb2.address)
}
}
it should "list all DLCs with and without associated contacts" in { daos =>
for {
_ <- daos.dlcDAO.create(dlcDb1)
_ <- daos.dlcDAO.create(dlcDb2)
_ <- daos.contactDAO.create(contactDb1)
_ <- daos.dlcContactMappingDAO.create(dlcDb1, contactDb1)
actual <- daos.dlcContactMappingDAO.listAll()
} yield {
assert(actual.size == 2)
val expected = Vector(
DLCContactMapping(dlcDb1, Some(contactDb1)),
DLCContactMapping(dlcDb2, None)
).sortBy(_.dlc.dlcId.hex)
assert(actual.sortBy(_.dlc.dlcId.hex) == expected)
}
}
it should "find all DLCs by contact" in { daos =>
for {
_ <- daos.dlcDAO.create(dlcDb1)
_ <- daos.dlcDAO.create(dlcDb2)
_ <- daos.contactDAO.create(contactDb1)
_ <- daos.dlcContactMappingDAO.create(dlcDb1, contactDb1)
actual1 <- daos.dlcContactMappingDAO.findDLCsByContactId(contactId =
contactDb1.address)
actual2 <- daos.dlcContactMappingDAO.findDLCsByContactId(contactId =
contactDb2.address)
} yield {
assert(actual1.size == 1)
assert(actual2.isEmpty)
val expected1 = Vector(dlcDb1)
assert(actual1 == expected1)
}
}
it should "find contact by DLCs" in { daos =>
for {
_ <- daos.dlcDAO.create(dlcDb1)
_ <- daos.dlcDAO.create(dlcDb2)
_ <- daos.contactDAO.create(contactDb1)
_ <- daos.dlcContactMappingDAO.create(dlcDb1, contactDb1)
actual1 <- daos.dlcContactMappingDAO.findContactByDLCId(dlcDb1.dlcId)
actual2 <- daos.dlcContactMappingDAO.findContactByDLCId(dlcDb2.dlcId)
} yield {
assert(actual1.size == 1)
assert(actual2.isEmpty)
val expected1 = Some(contactDb1)
assert(actual1 == expected1)
}
}
}

View file

@ -0,0 +1,6 @@
CREATE TABLE "dlc_contact_mapping" (
"dlc_id" TEXT NOT NULL PRIMARY KEY,
"contact_id" TEXT NOT NULL,
CONSTRAINT "fk_dlc_contact_dlc_id" FOREIGN KEY ("dlc_id") references "global_dlc_data" ("dlc_id") on update NO ACTION on delete NO ACTION,
CONSTRAINT "fk_dlc_contact_contact_id" FOREIGN KEY ("contact_id") references "contacts" ("address") on update NO ACTION on delete NO ACTION
);

View file

@ -0,0 +1,6 @@
CREATE TABLE "dlc_contact_mapping" (
"dlc_id" TEXT NOT NULL PRIMARY KEY,
"contact_id" TEXT NOT NULL,
CONSTRAINT "fk_dlc_contact_dlc_id" FOREIGN KEY ("dlc_id") references "global_dlc_data" ("dlc_id") on update NO ACTION on delete NO ACTION,
CONSTRAINT "fk_dlc_contact_contact_id" FOREIGN KEY ("contact_id") references "contacts" ("address") on update NO ACTION on delete NO ACTION
);

View file

@ -2,7 +2,7 @@ package org.bitcoins.dlc.wallet
import org.bitcoins.core.api.chain.ChainQueryApi
import org.bitcoins.core.api.dlc.wallet.AnyDLCHDWalletApi
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
import org.bitcoins.core.api.dlc.wallet.db.{DLCContactDb, DLCDb}
import org.bitcoins.core.api.feeprovider.FeeRateApi
import org.bitcoins.core.api.node.NodeApi
import org.bitcoins.core.api.wallet.db._
@ -43,6 +43,7 @@ import org.bitcoins.wallet.{Wallet, WalletLogger}
import scodec.bits.ByteVector
import slick.dbio.{DBIO, DBIOAction}
import java.net.InetSocketAddress
import scala.concurrent.{ExecutionContext, Future}
/** A [[Wallet]] with full DLC Functionality */
@ -77,6 +78,9 @@ abstract class DLCWallet
private[bitcoins] val contactDAO: DLCContactDAO =
DLCContactDAO()
private[bitcoins] val dlcContactMappingDAO: DLCContactMappingDAO =
DLCContactMappingDAO()
private[wallet] val dlcWalletDAOs = DLCWalletDAOs(
dlcDAO,
contractDataDAO,
@ -805,7 +809,8 @@ abstract class DLCWallet
offerDb = initializedAccept.offerDb,
payoutAddress = Some(
PayoutAddress(initializedAccept.pubKeys.payoutAddress,
isExternalAddress))
isExternalAddress)),
contactOpt = None
)
_ = dlcConfig.walletCallbacks.executeOnDLCStateChange(logger, status)
cetSigs <- signer.createCETSigsAsync()
@ -1630,6 +1635,7 @@ abstract class DLCWallet
for {
dlcDbOpt <- dlcDAO.findByContractId(contractId)
dlcDb = dlcDbOpt.get
contactOpt <- dlcContactMappingDAO.findContactByDLCId(dlcDb.dlcId)
offerDbOpt <- dlcOfferDAO.findByDLCId(dlcDb.dlcId)
_ = require(offerDbOpt.nonEmpty,
s"Invalid DLC $dlcDb.dlcId: no offer data")
@ -1678,7 +1684,8 @@ abstract class DLCWallet
contractData,
offerDbOpt.get,
dlcAcceptOpt,
closingTxOpt)
closingTxOpt,
contactOpt)
_ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(logger, status.get)
} yield refundTx
}
@ -1696,8 +1703,23 @@ abstract class DLCWallet
}
override def listDLCs(): Future[Vector[DLCStatus]] = {
listDLCs(None)
}
override def listDLCsByContact(
contactId: InetSocketAddress): Future[Vector[DLCStatus]] = {
listDLCs(Some(contactId))
}
private def listDLCs(
contactIdOpt: Option[InetSocketAddress]): Future[Vector[DLCStatus]] = {
for {
ids <- dlcDAO.findAll().map(_.map(_.dlcId))
dlcs <- contactIdOpt match {
case Some(contactId) =>
dlcContactMappingDAO.findDLCsByContactId(contactId)
case None => dlcDAO.findAll()
}
ids = dlcs.map(_.dlcId)
dlcFs = ids.map(findDLC)
dlcs <- Future.sequence(dlcFs)
} yield {
@ -1760,6 +1782,7 @@ abstract class DLCWallet
val contractDataOptF = contractDataDAO.read(dlcId)
val offerDbOptF = dlcOfferDAO.read(dlcId)
val acceptDbOptF = dlcAcceptDAO.read(dlcId)
val contactDbOptF = dlcContactMappingDAO.findContactByDLCId(dlcId)
val closingTxOptF: Future[Option[TransactionDb]] = getClosingTxOpt(dlcDb)
val dlcOptF: Future[Option[DLCStatus]] = for {
@ -1767,6 +1790,7 @@ abstract class DLCWallet
offerDbOpt <- offerDbOptF
acceptDbOpt <- acceptDbOptF
closingTxOpt <- closingTxOptF
contactDbOpt <- contactDbOptF
result <- {
(contractDataOpt, offerDbOpt) match {
case (Some(contractData), Some(offerDb)) =>
@ -1774,7 +1798,8 @@ abstract class DLCWallet
contractData,
offerDb,
acceptDbOpt,
closingTxOpt)
closingTxOpt,
contactDbOpt)
case (_, _) => Future.successful(None)
}
}
@ -1788,7 +1813,8 @@ abstract class DLCWallet
contractData: DLCContractDataDb,
offerDb: DLCOfferDb,
acceptDbOpt: Option[DLCAcceptDb],
closingTxOpt: Option[TransactionDb]): Future[Option[DLCStatus]] = {
closingTxOpt: Option[TransactionDb],
contactOpt: Option[DLCContactDb]): Future[Option[DLCStatus]] = {
val dlcId = dlcDb.dlcId
val aggregatedF: Future[(
Vector[DLCAnnouncementDb],
@ -1823,7 +1849,8 @@ abstract class DLCWallet
contractInfo = contractInfo,
contractData = contractData,
offerDb = offerDb,
payoutAddress = payoutAddress)
payoutAddress = payoutAddress,
contactOpt = contactOpt)
Future.successful(inProgress)
case _: DLCState.ClosedState =>
(acceptDbOpt, closingTxOpt) match {
@ -1838,7 +1865,8 @@ abstract class DLCWallet
offerDb = offerDb,
acceptDb = acceptDb,
closingTx = closingTx.transaction,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contactOpt = contactOpt
)
Future.successful(status)
case (None, None) =>

View file

@ -58,4 +58,15 @@ trait IncomingDLCOffersHandling { self: DLCWallet =>
override def findDLCContacts(alias: String): Future[Vector[DLCContactDb]] =
contactDAO.findByAlias(alias)
override def addDLCContactMapping(
dlcId: Sha256Digest,
contcatId: InetSocketAddress): Future[Unit] = {
dlcContactMappingDAO
.create(dlcId, contcatId)
.map(_ => ())
}
override def removeDLCContactMapping(dlcId: Sha256Digest): Future[Unit] = {
dlcContactMappingDAO.delete(dlcId)
}
}

View file

@ -0,0 +1,129 @@
package org.bitcoins.dlc.wallet.models
import org.bitcoins.core.api.dlc.wallet.db.{DLCContactDb, DLCDb}
import org.bitcoins.crypto.Sha256Digest
import org.bitcoins.db.{CRUD, SlickUtil}
import org.bitcoins.dlc.wallet.DLCAppConfig
import slick.lifted.ForeignKeyQuery
import java.net.InetSocketAddress
import scala.concurrent.{ExecutionContext, Future}
case class DLCContactMapping(dlc: DLCDb, contact: Option[DLCContactDb]) {
def dlcId: Sha256Digest = dlc.dlcId
def toDLCContactMappingDb: Option[DLCContactMappingDb] =
contact.map(c => DLCContactMappingDb(dlc.dlcId, c.address))
}
case class DLCContactMappingDb(
dlcId: Sha256Digest,
contactId: InetSocketAddress)
case class DLCContactMappingDAO()(implicit
override val ec: ExecutionContext,
override val appConfig: DLCAppConfig)
extends CRUD[DLCContactMappingDb, Sha256Digest]
with SlickUtil[DLCContactMappingDb, Sha256Digest] {
private val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile)
import mappers._
import profile.api._
/** The table inside our database we are inserting into */
override val table: TableQuery[DLCContactMappingTable] =
TableQuery[DLCContactMappingTable]
private lazy val dlcTable: slick.lifted.TableQuery[DLCDAO#DLCTable] = {
DLCDAO().table
}
private lazy val contactTable: slick.lifted.TableQuery[
DLCContactDAO#DLCContactTable] = {
DLCContactDAO().table
}
override def createAll(
ts: Vector[DLCContactMappingDb]): Future[Vector[DLCContactMappingDb]] = {
createAllNoAutoInc(ts, safeDatabase)
}
def create(
dlcDb: DLCDb,
contactDb: DLCContactDb): Future[DLCContactMappingDb] = {
create(DLCContactMappingDb(dlcDb.dlcId, contactDb.address))
}
def create(
dlcId: Sha256Digest,
contactId: InetSocketAddress): Future[DLCContactMappingDb] = {
create(DLCContactMappingDb(dlcId, contactId))
}
def delete(dlcId: Sha256Digest): Future[Unit] = {
safeDatabase.run(table.filter(_.dlcId === dlcId).delete).map(_ => ())
}
def findContactByDLCId(dlcId: Sha256Digest): Future[Option[DLCContactDb]] = {
val join =
table.join(contactTable).on(_.contactId === _.address)
safeDatabase
.run(join.filter(_._1.dlcId === dlcId).result)
.map(_.headOption.map(_._2))
}
def findDLCsByContactId(
contactId: InetSocketAddress): Future[Vector[DLCDb]] = {
val join = table.join(dlcTable).on(_.dlcId === _.dlcId)
safeDatabase
.runVec(join.filter(_._1.contactId === contactId).result)
.map(_.map(_._2))
}
def listAll(): Future[Vector[DLCContactMapping]] = {
val contactJoin = table.join(contactTable).on(_.contactId === _.address)
val dlcJoin = dlcTable.joinLeft(contactJoin).on(_.dlcId === _._1.dlcId)
safeDatabase
.runVec(dlcJoin.result)
.map(_.map(row => DLCContactMapping(row._1, row._2.map(_._2))))
}
override protected def findByPrimaryKeys(ids: Vector[Sha256Digest]): Query[
Table[DLCContactMappingDb],
DLCContactMappingDb,
Seq] = {
table.filter(_.dlcId.inSet(ids))
}
override protected def findAll(ts: Vector[DLCContactMappingDb]): Query[
Table[_],
DLCContactMappingDb,
Seq] = findByPrimaryKeys(ts.map(_.dlcId))
class DLCContactMappingTable(tag: Tag)
extends Table[DLCContactMappingDb](tag,
schemaName,
"dlc_contact_mapping") {
import profile.api._
def dlcId: Rep[Sha256Digest] = column("dlc_id", O.PrimaryKey)
def contactId: Rep[InetSocketAddress] = column("contact_id")
def fkDLCId: ForeignKeyQuery[_, DLCDb] =
foreignKey("fk_dlc_contact_dlc_id",
sourceColumns = dlcId,
targetTableQuery = dlcTable)(_.dlcId)
def fkContactId: ForeignKeyQuery[_, DLCContactDb] =
foreignKey("fk_dlc_contact_contact_id",
sourceColumns = contactId,
targetTableQuery = contactTable)(_.address)
def * =
(dlcId,
contactId) <> (DLCContactMappingDb.tupled, DLCContactMappingDb.unapply)
}
}

View file

@ -1,6 +1,6 @@
package org.bitcoins.dlc.wallet.util
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
import org.bitcoins.core.api.dlc.wallet.db.{DLCContactDb, DLCDb}
import org.bitcoins.core.dlc.accounting.DLCAccounting
import org.bitcoins.core.protocol.dlc.models.DLCStatus._
import org.bitcoins.core.protocol.dlc.models._
@ -18,7 +18,8 @@ object DLCStatusBuilder {
contractInfo: ContractInfo,
contractData: DLCContractDataDb,
offerDb: DLCOfferDb,
payoutAddress: Option[PayoutAddress]): DLCStatus = {
payoutAddress: Option[PayoutAddress],
contactOpt: Option[DLCContactDb]): DLCStatus = {
require(
dlcDb.state.isInstanceOf[DLCState.InProgressState],
s"Cannot have divergent states beteween dlcDb and the parameter state, got= dlcDb.state=${dlcDb.state} state=${dlcDb.state}"
@ -45,7 +46,8 @@ object DLCStatusBuilder {
dlcDb.feeRate,
totalCollateral,
localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.AcceptComputingAdaptorSigs =>
AcceptedComputingAdaptorSigs(
@ -59,7 +61,8 @@ object DLCStatusBuilder {
feeRate = dlcDb.feeRate,
totalCollateral = totalCollateral,
localCollateral = localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Accepted =>
Accepted(
@ -73,7 +76,8 @@ object DLCStatusBuilder {
dlcDb.feeRate,
totalCollateral,
localCollateral,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.SignComputingAdaptorSigs =>
SignedComputingAdaptorSigs(
@ -88,7 +92,8 @@ object DLCStatusBuilder {
totalCollateral = totalCollateral,
localCollateral = localCollateral,
dlcDb.fundingTxIdOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Signed =>
Signed(
@ -103,7 +108,8 @@ object DLCStatusBuilder {
totalCollateral,
localCollateral,
dlcDb.fundingTxIdOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Broadcasted =>
Broadcasted(
@ -118,7 +124,8 @@ object DLCStatusBuilder {
totalCollateral,
localCollateral,
dlcDb.fundingTxIdOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
case DLCState.Confirmed =>
Confirmed(
@ -133,7 +140,8 @@ object DLCStatusBuilder {
totalCollateral,
localCollateral,
dlcDb.fundingTxIdOpt.get,
payoutAddress
payoutAddress,
contactOpt
)
}
@ -150,7 +158,8 @@ object DLCStatusBuilder {
offerDb: DLCOfferDb,
acceptDb: DLCAcceptDb,
closingTx: Transaction,
payoutAddress: Option[PayoutAddress]): ClosedDLCStatus = {
payoutAddress: Option[PayoutAddress],
contactOpt: Option[DLCContactDb]): ClosedDLCStatus = {
require(
dlcDb.state.isInstanceOf[DLCState.ClosedState],
s"Cannot have divergent states beteween dlcDb and the parameter state, got= dlcDb.state=${dlcDb.state} state=${dlcDb.state}"
@ -186,7 +195,8 @@ object DLCStatusBuilder {
closingTx.txIdBE,
myPayout = accounting.myPayout,
counterPartyPayout = accounting.theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contactOpt
)
refund
case oracleOutcomeState: DLCState.ClosedViaOracleOutcomeState =>
@ -214,7 +224,8 @@ object DLCStatusBuilder {
oracleOutcome,
myPayout = accounting.myPayout,
counterPartyPayout = accounting.theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contactOpt
)
case DLCState.RemoteClaimed =>
RemoteClaimed(
@ -234,7 +245,8 @@ object DLCStatusBuilder {
oracleOutcome,
myPayout = accounting.myPayout,
counterPartyPayout = accounting.theirPayout,
payoutAddress = payoutAddress
payoutAddress = payoutAddress,
contact = contactOpt
)
}
}

View file

@ -278,6 +278,9 @@ the `-p 9999:9999` port mapping on the docker container to adjust for this.
- `contacts-list` - lists all contacts in the wallet
- `contact-remove` `address`
- `address` - the tor address for the peer to remove
- `dlc-contact-add` `dlcid` `address` - Associated a DLC with a peer
- `dlc-contact-remove` `dlcid` - Removes a DLC-peer association
- `address` - the tor address for the peer to remove
- `signdlc` `accept` - Signs a DLC
- `accept` - Hex encoded dlc accept message
- `signdlcfromfile` `path` `[destination]` - Signs a DLC

View file

@ -21,7 +21,9 @@ case class DLCDAOs(
dlcSigsDAO: DLCCETSignaturesDAO,
dlcRefundSigDAO: DLCRefundSigsDAO,
dlcRemoteTxDAO: DLCRemoteTxDAO,
incomingDLCOfferDAO: IncomingDLCOfferDAO) {
incomingDLCOfferDAO: IncomingDLCOfferDAO,
contactDAO: DLCContactDAO,
dlcContactMappingDAO: DLCContactMappingDAO) {
val list = Vector(
announcementDAO,
@ -35,7 +37,9 @@ case class DLCDAOs(
dlcSigsDAO,
dlcRefundSigDAO,
dlcRemoteTxDAO,
incomingDLCOfferDAO
incomingDLCOfferDAO,
contactDAO: DLCContactDAO,
dlcContactMappingDAO: DLCContactMappingDAO
)
}
@ -54,6 +58,8 @@ trait DLCDAOFixture extends BitcoinSFixture with EmbeddedPg {
val dlcRefundSigDAO = DLCRefundSigsDAO()
val dlcRemoteTxDAO = DLCRemoteTxDAO()
val incomingDLCOfferDAO = IncomingDLCOfferDAO()
val contactDAO = DLCContactDAO()
val dlcContactMappingDAO = DLCContactMappingDAO()
DLCDAOs(
announcementDAO = announcementDAO,
nonceDAO = nonceDAO,
@ -66,7 +72,9 @@ trait DLCDAOFixture extends BitcoinSFixture with EmbeddedPg {
dlcSigsDAO = dlcSigsDAO,
dlcRefundSigDAO = dlcRefundSigDAO,
dlcRemoteTxDAO = dlcRemoteTxDAO,
incomingDLCOfferDAO = incomingDLCOfferDAO
incomingDLCOfferDAO = incomingDLCOfferDAO,
contactDAO = contactDAO,
dlcContactMappingDAO = dlcContactMappingDAO
)
}