mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
2024 09 30 dlcwallet has a wallet (#5692)
* refactor: Rework codebase so that DLCWallet has-a instance of Wallet rather than is-a via inheritance * Fix cast * Fix RescanHandling in DLCWallet * Remove default implementation of WalletApi.broadcastTransaction() * fix broadcast callback for DLCWallet * Add DLCWalletDAOs.fromDLCAppConfig() * Fix scaladoc for AddressHandlingApi.getUnusedAddress
This commit is contained in:
parent
5afa058892
commit
52c0625ba9
@ -2,7 +2,10 @@ package org.bitcoins.server
|
||||
|
||||
import org.apache.pekko.http.scaladsl.model.ContentTypes
|
||||
import org.apache.pekko.http.scaladsl.testkit.ScalatestRouteTest
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCNeutrinoHDWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCNeutrinoHDWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCContactDb
|
||||
import org.bitcoins.core.currency.{Bitcoins, Satoshis}
|
||||
import org.bitcoins.core.protocol.dlc.models.ContractInfo
|
||||
@ -30,6 +33,9 @@ class DLCRoutesSpec
|
||||
|
||||
val mockNodeApi = DLCNode(mockWallet)(system, conf.dlcNodeConf)
|
||||
|
||||
val mockIncomingDLCOfferHandlingApi: IncomingDLCOfferHandlingApi =
|
||||
mock[IncomingDLCOfferHandlingApi]
|
||||
|
||||
val dlcRoutes = DLCRoutes(mockNodeApi)
|
||||
|
||||
// https://test.oracle.suredbits.com/announcement/8863cd80e1d37f668e27b84cbfed48541d671b4fed1462b86d547e7f13b5a9e4
|
||||
@ -161,7 +167,11 @@ class DLCRoutesSpec
|
||||
}
|
||||
|
||||
"contact-add a peer" in {
|
||||
(mockWallet
|
||||
(() => mockWallet.incomingOfferHandling)
|
||||
.expects()
|
||||
.returning(mockIncomingDLCOfferHandlingApi)
|
||||
.anyNumberOfTimes()
|
||||
(mockWallet.incomingOfferHandling
|
||||
.addDLCContact(_: DLCContactDb))
|
||||
.expects(expected)
|
||||
.returning(Future.unit)
|
||||
@ -178,7 +188,12 @@ class DLCRoutesSpec
|
||||
}
|
||||
|
||||
"contacts-list list contacts" in {
|
||||
(() => mockWallet.listDLCContacts())
|
||||
(() => mockWallet.incomingOfferHandling)
|
||||
.expects()
|
||||
.returning(mockIncomingDLCOfferHandlingApi)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
(() => mockWallet.incomingOfferHandling.listDLCContacts())
|
||||
.expects()
|
||||
.returning(Future.successful(Vector(expected)))
|
||||
|
||||
@ -200,7 +215,12 @@ class DLCRoutesSpec
|
||||
val address = host + port
|
||||
val unresolved = InetSocketAddress.createUnresolved(host, 2862)
|
||||
|
||||
(mockWallet
|
||||
(() => mockWallet.incomingOfferHandling)
|
||||
.expects()
|
||||
.returning(mockIncomingDLCOfferHandlingApi)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
(mockWallet.incomingOfferHandling
|
||||
.removeDLCContact(_: InetSocketAddress))
|
||||
.expects(unresolved)
|
||||
.returning(Future.unit)
|
||||
@ -216,7 +236,12 @@ class DLCRoutesSpec
|
||||
}
|
||||
|
||||
"dlc-contact-add a peer" in {
|
||||
(mockWallet
|
||||
(() => mockWallet.incomingOfferHandling)
|
||||
.expects()
|
||||
.returning(mockIncomingDLCOfferHandlingApi)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
(mockWallet.incomingOfferHandling
|
||||
.addDLCContactMapping(_: Sha256Digest, _: InetSocketAddress))
|
||||
.expects(Sha256Digest.empty, expected.address)
|
||||
.returning(Future.unit)
|
||||
@ -236,8 +261,12 @@ class DLCRoutesSpec
|
||||
}
|
||||
|
||||
"dlc-contact-remove a peer" in {
|
||||
(() => mockWallet.incomingOfferHandling)
|
||||
.expects()
|
||||
.returning(mockIncomingDLCOfferHandlingApi)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
(mockWallet
|
||||
(mockWallet.incomingOfferHandling
|
||||
.removeDLCContactMapping(_: Sha256Digest))
|
||||
.expects(Sha256Digest.empty)
|
||||
.returning(Future.unit)
|
||||
|
@ -297,15 +297,18 @@ object BitcoindRpcBackendUtil extends BitcoinSLogger {
|
||||
// after we have created it into SyncUtil.getNodeApiWalletCallback
|
||||
// so we don't lose the internal state of the wallet
|
||||
val walletCallbackP = Promise[DLCWallet]()
|
||||
val nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
||||
bitcoind,
|
||||
walletCallbackP.future,
|
||||
chainCallbacksOpt
|
||||
)
|
||||
|
||||
val pairedWallet = DLCWallet(
|
||||
nodeApi = BitcoindRpcBackendUtil.buildBitcoindNodeApi(
|
||||
bitcoind,
|
||||
walletCallbackP.future,
|
||||
chainCallbacksOpt
|
||||
),
|
||||
chainQueryApi = bitcoind
|
||||
)(wallet.walletConfig, wallet.dlcConfig)
|
||||
val walletConfig = wallet.walletConfig
|
||||
val dlcConfig = wallet.dlcConfig
|
||||
val bitcoindCallbackWallet =
|
||||
wallet.walletApi.copy(nodeApi = nodeApi)(walletConfig)
|
||||
val pairedWallet =
|
||||
DLCWallet(bitcoindCallbackWallet)(dlcConfig, walletConfig)
|
||||
|
||||
walletCallbackP.success(pairedWallet)
|
||||
|
||||
|
@ -76,7 +76,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
|
||||
case ServerCommand("offers-list", _) =>
|
||||
complete {
|
||||
dlcNode.wallet.listIncomingDLCOffers().map { offers =>
|
||||
dlcNode.incomingOfferHandling.listIncomingDLCOffers().map { offers =>
|
||||
def toJson(io: IncomingDLCOfferDb): Value = {
|
||||
Obj(
|
||||
"hash" -> io.hash.hex,
|
||||
@ -94,7 +94,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
case ServerCommand("offer-add", arr) =>
|
||||
withValidServerCommand(OfferAdd.fromJsArr(arr)) { register =>
|
||||
complete {
|
||||
dlcNode.wallet
|
||||
dlcNode.incomingOfferHandling
|
||||
.registerIncomingDLCOffer(
|
||||
register.offerTLV,
|
||||
register.peer,
|
||||
@ -109,9 +109,11 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
case ServerCommand("offer-remove", arr) =>
|
||||
withValidServerCommand(OfferRemove.fromJsArr(arr)) { reject =>
|
||||
complete {
|
||||
dlcNode.wallet.rejectIncomingDLCOffer(reject.hash).map { _ =>
|
||||
Server.httpSuccess(reject.hash.hex)
|
||||
}
|
||||
dlcNode.incomingOfferHandling
|
||||
.rejectIncomingDLCOffer(reject.hash)
|
||||
.map { _ =>
|
||||
Server.httpSuccess(reject.hash.hex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +140,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
|
||||
case ServerCommand("contacts-list", _) =>
|
||||
complete {
|
||||
dlcNode.wallet.listDLCContacts().map { contacts =>
|
||||
dlcNode.incomingOfferHandling.listDLCContacts().map { contacts =>
|
||||
val json = contacts
|
||||
.map(c => upickle.default.writeJs(c)(Picklers.contactDbPickler))
|
||||
Server.httpSuccess(json)
|
||||
@ -148,7 +150,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
case ServerCommand("contact-add", arr) =>
|
||||
withValidServerCommand(ContactAdd.fromJsArr(arr)) { contactAdd =>
|
||||
complete {
|
||||
dlcNode.wallet
|
||||
dlcNode.incomingOfferHandling
|
||||
.addDLCContact(contactAdd.toDLCContactDb)
|
||||
.map { _ =>
|
||||
Server.httpSuccess("ok")
|
||||
@ -159,7 +161,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
case ServerCommand("contact-remove", arr) =>
|
||||
withValidServerCommand(ContactRemove.fromJsArr(arr)) { contactAdd =>
|
||||
complete {
|
||||
dlcNode.wallet
|
||||
dlcNode.incomingOfferHandling
|
||||
.removeDLCContact(contactAdd.address)
|
||||
.map { _ =>
|
||||
Server.httpSuccess("ok")
|
||||
@ -170,7 +172,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
case ServerCommand("dlc-contact-add", arr) =>
|
||||
withValidServerCommand(DLCContactAdd.fromJsArr(arr)) { dlcContactAdd =>
|
||||
complete {
|
||||
dlcNode.wallet
|
||||
dlcNode.incomingOfferHandling
|
||||
.addDLCContactMapping(dlcContactAdd.dlcId, dlcContactAdd.address)
|
||||
.map { _ =>
|
||||
val dlcId = dlcContactAdd.dlcId.hex
|
||||
@ -187,7 +189,7 @@ case class DLCRoutes(dlcNode: DLCNodeApi)(implicit system: ActorSystem)
|
||||
withValidServerCommand(DLCContactRemove.fromJsArr(arr)) {
|
||||
dlcContactRemove =>
|
||||
complete {
|
||||
dlcNode.wallet
|
||||
dlcNode.incomingOfferHandling
|
||||
.removeDLCContactMapping(dlcContactRemove.dlcId)
|
||||
.map { _ =>
|
||||
Server.httpSuccess("ok")
|
||||
|
@ -1,9 +1,12 @@
|
||||
package org.bitcoins.core.api.dlc.node
|
||||
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.dlc.models.DLCMessage
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.tlv.*
|
||||
import org.bitcoins.core.util.StartStopAsync
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
|
||||
@ -13,6 +16,8 @@ import scala.concurrent.Future
|
||||
trait DLCNodeApi extends StartStopAsync[Unit] {
|
||||
|
||||
def wallet: DLCWalletApi
|
||||
final def incomingOfferHandling: IncomingDLCOfferHandlingApi =
|
||||
wallet.incomingOfferHandling
|
||||
|
||||
def acceptDLCOffer(
|
||||
peerAddress: InetSocketAddress,
|
||||
|
@ -1,10 +1,6 @@
|
||||
package org.bitcoins.core.api.dlc.wallet
|
||||
|
||||
import org.bitcoins.core.api.dlc.wallet.db.{
|
||||
DLCContactDb,
|
||||
DLCDb,
|
||||
IncomingDLCOfferDb
|
||||
}
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
|
||||
import org.bitcoins.core.api.wallet._
|
||||
import org.bitcoins.core.currency.Satoshis
|
||||
import org.bitcoins.core.dlc.accounting._
|
||||
@ -21,7 +17,9 @@ import scodec.bits.ByteVector
|
||||
import java.net.InetSocketAddress
|
||||
import scala.concurrent._
|
||||
|
||||
trait DLCWalletApi { self: WalletApi =>
|
||||
trait DLCWalletApi {
|
||||
protected def walletApi: WalletApi
|
||||
def incomingOfferHandling: IncomingDLCOfferHandlingApi
|
||||
|
||||
def createDLCOffer(
|
||||
contractInfoTLV: ContractInfoTLV,
|
||||
@ -161,32 +159,6 @@ trait DLCWalletApi { self: WalletApi =>
|
||||
/** Retrieves accounting and financial metrics for the entire dlc wallet */
|
||||
def getWalletAccounting(): Future[DLCWalletAccounting]
|
||||
|
||||
def registerIncomingDLCOffer(
|
||||
offerTLV: DLCOfferTLV,
|
||||
peer: Option[String],
|
||||
message: Option[String]): Future[Sha256Digest]
|
||||
|
||||
def listIncomingDLCOffers(): Future[Vector[IncomingDLCOfferDb]]
|
||||
|
||||
def rejectIncomingDLCOffer(offerHash: Sha256Digest): Future[Unit]
|
||||
|
||||
def findIncomingDLCOffer(
|
||||
offerHash: Sha256Digest): Future[Option[IncomingDLCOfferDb]]
|
||||
|
||||
def listDLCContacts(): Future[Vector[DLCContactDb]]
|
||||
|
||||
def addDLCContact(contact: DLCContactDb): Future[Unit]
|
||||
|
||||
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]]
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
package org.bitcoins.core.api.dlc.wallet
|
||||
|
||||
import org.bitcoins.core.api.dlc.wallet.db.{DLCContactDb, IncomingDLCOfferDb}
|
||||
import org.bitcoins.core.protocol.tlv.DLCOfferTLV
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
import scala.concurrent.Future
|
||||
|
||||
trait IncomingDLCOfferHandlingApi {
|
||||
def registerIncomingDLCOffer(
|
||||
offerTLV: DLCOfferTLV,
|
||||
peer: Option[String],
|
||||
message: Option[String]): Future[Sha256Digest]
|
||||
|
||||
def listIncomingDLCOffers(): Future[Vector[IncomingDLCOfferDb]]
|
||||
|
||||
def rejectIncomingDLCOffer(offerHash: Sha256Digest): Future[Unit]
|
||||
|
||||
def findIncomingDLCOffer(
|
||||
offerHash: Sha256Digest): Future[Option[IncomingDLCOfferDb]]
|
||||
|
||||
def listDLCContacts(): Future[Vector[DLCContactDb]]
|
||||
|
||||
def addDLCContact(contact: DLCContactDb): Future[Unit]
|
||||
|
||||
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]
|
||||
}
|
@ -2,7 +2,7 @@ package org.bitcoins.core.api.wallet
|
||||
|
||||
import org.bitcoins.core.api.wallet.db.{AddressDb, AddressTagDb, ScriptPubKeyDb}
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.hd.AddressType
|
||||
import org.bitcoins.core.hd.{AddressType, HDAccount}
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.protocol.transaction.{
|
||||
@ -16,9 +16,25 @@ import org.bitcoins.core.wallet.utxo.{
|
||||
AddressTagType
|
||||
}
|
||||
|
||||
import scala.concurrent.Future
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
trait AddressHandlingApi {
|
||||
final def contains(
|
||||
address: BitcoinAddress,
|
||||
accountOpt: Option[(AccountHandlingApi, HDAccount)]
|
||||
)(implicit ec: ExecutionContext): Future[Boolean] = {
|
||||
val possibleAddressesF = accountOpt match {
|
||||
case Some((ah, account)) =>
|
||||
ah.listAddresses(account)
|
||||
case None =>
|
||||
listAddresses()
|
||||
}
|
||||
|
||||
possibleAddressesF.map { possibleAddresses =>
|
||||
possibleAddresses.exists(_.address == address)
|
||||
}
|
||||
}
|
||||
|
||||
def dropAddressTag(addressTagDb: AddressTagDb): Future[Int]
|
||||
def dropAddressTagType(
|
||||
addressTagType: AddressTagType
|
||||
@ -55,11 +71,17 @@ trait AddressHandlingApi {
|
||||
): Future[Option[AddressInfo]]
|
||||
def getAddressTags(): Future[Vector[AddressTagDb]]
|
||||
def getAddressTags(address: BitcoinAddress): Future[Vector[AddressTagDb]]
|
||||
def getAddressTags(tagType: AddressTagType): Future[Vector[AddressTagDb]]
|
||||
def getAddressTags(
|
||||
address: BitcoinAddress,
|
||||
tagType: AddressTagType
|
||||
): Future[Vector[AddressTagDb]]
|
||||
|
||||
/** Gets a external address. Calling this method multiple times will return
|
||||
* the same address, until it has received funds.
|
||||
*/
|
||||
def getUnusedAddress: Future[BitcoinAddress]
|
||||
|
||||
/** Determines if the given output is from this wallet and is a change output
|
||||
* from this wallet
|
||||
*/
|
||||
|
@ -35,8 +35,7 @@ trait WalletApi {
|
||||
def feeRateApi: FeeRateApi
|
||||
val creationTime: Instant
|
||||
|
||||
def broadcastTransaction(transaction: Transaction): Future[Unit] =
|
||||
nodeApi.broadcastTransaction(transaction)
|
||||
def broadcastTransaction(transaction: Transaction): Future[Unit]
|
||||
|
||||
def getFeeRate(): Future[FeeUnit] = feeRateApi.getFeeRate()
|
||||
|
||||
|
@ -61,6 +61,7 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
|
||||
_ <- DLCClient.connect(
|
||||
Peer(connectAddress, socks5ProxyParams = None),
|
||||
walletB,
|
||||
walletB.incomingOfferHandling,
|
||||
Some(handlerP),
|
||||
handleWrite = handleWriteFn,
|
||||
handleWriteError = handleWriteErrorFn
|
||||
@ -130,6 +131,7 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
|
||||
_ <- DLCClient.connect(
|
||||
Peer(connectAddress, socks5ProxyParams = None),
|
||||
walletB,
|
||||
walletB.incomingOfferHandling,
|
||||
Some(handlerP),
|
||||
handleWrite = { (_, tlvId) =>
|
||||
okP.success(tlvId)
|
||||
@ -143,8 +145,8 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
|
||||
|
||||
handler <- handlerP.future
|
||||
|
||||
preA <- walletA.listIncomingDLCOffers()
|
||||
preB <- walletA.listIncomingDLCOffers()
|
||||
preA <- walletA.incomingOfferHandling.listIncomingDLCOffers()
|
||||
preB <- walletA.incomingOfferHandling.listIncomingDLCOffers()
|
||||
_ = assert(preA.isEmpty)
|
||||
_ = assert(preB.isEmpty)
|
||||
|
||||
@ -168,10 +170,10 @@ class DLCNegotiationTest extends BitcoinSDualWalletTest {
|
||||
_ = assert(!errorP.isCompleted)
|
||||
|
||||
_ <- TestAsyncUtil.awaitConditionF { () =>
|
||||
walletA.listIncomingDLCOffers().map(_.nonEmpty)
|
||||
walletA.incomingOfferHandling.listIncomingDLCOffers().map(_.nonEmpty)
|
||||
}
|
||||
postA <- walletA.listIncomingDLCOffers()
|
||||
postB <- walletB.listIncomingDLCOffers()
|
||||
postA <- walletA.incomingOfferHandling.listIncomingDLCOffers()
|
||||
postB <- walletB.incomingOfferHandling.listIncomingDLCOffers()
|
||||
} yield {
|
||||
assert(postA.nonEmpty)
|
||||
assert(postB.isEmpty)
|
||||
|
@ -52,7 +52,7 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet {
|
||||
dlcWalletApi.wallet,
|
||||
bindAddress,
|
||||
Some(boundAddressPromise),
|
||||
{ (_, _, connectionHandler) =>
|
||||
{ (_, _, _, connectionHandler) =>
|
||||
serverConnectionHandlerOpt = Some(connectionHandler)
|
||||
serverProbe.ref
|
||||
},
|
||||
@ -70,9 +70,10 @@ class DLCServerTest extends BitcoinSActorFixtureWithDLCWallet {
|
||||
val client = TestActorRef(
|
||||
DLCClient.props(
|
||||
dlcWalletApi.wallet,
|
||||
dlcWalletApi.wallet.incomingOfferHandling,
|
||||
Some(connectedAddressPromise),
|
||||
None,
|
||||
{ (_, _, connectionHandler) =>
|
||||
{ (_, _, _, connectionHandler) =>
|
||||
clientConnectionHandlerOpt = Some(connectionHandler)
|
||||
clientProbe.ref
|
||||
},
|
||||
|
@ -75,7 +75,7 @@ class DLCServerTorTest
|
||||
fundedDLCWallet.wallet,
|
||||
bindAddress,
|
||||
Some(boundAddressPromise),
|
||||
{ (_, _, connectionHandler) =>
|
||||
{ (_, _, _, connectionHandler) =>
|
||||
serverConnectionHandlerOpt = Some(connectionHandler)
|
||||
serverProbe.ref
|
||||
},
|
||||
@ -94,9 +94,10 @@ class DLCServerTorTest
|
||||
val client = TestActorRef(
|
||||
DLCClient.props(
|
||||
fundedDLCWallet.wallet,
|
||||
fundedDLCWallet.wallet.incomingOfferHandling,
|
||||
Some(connectedAddressPromise),
|
||||
None,
|
||||
{ (_, _, connectionHandler) =>
|
||||
{ (_, _, _, connectionHandler) =>
|
||||
clientConnectionHandlerOpt = Some(connectionHandler)
|
||||
clientProbe.ref
|
||||
},
|
||||
|
@ -10,7 +10,10 @@ import org.apache.pekko.actor.{
|
||||
}
|
||||
import org.apache.pekko.event.LoggingReceive
|
||||
import org.apache.pekko.io.{IO, Tcp}
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.api.node.Peer
|
||||
import org.bitcoins.core.api.tor.Socks5ProxyParams
|
||||
import org.bitcoins.core.protocol.BigSizeUInt
|
||||
@ -25,6 +28,7 @@ import scala.concurrent.{Future, Promise}
|
||||
|
||||
class DLCClient(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connectedAddress: Option[Promise[InetSocketAddress]],
|
||||
handlerP: Option[Promise[ActorRef]],
|
||||
dataHandlerFactory: DLCDataHandler.Factory,
|
||||
@ -93,6 +97,7 @@ class DLCClient(
|
||||
Props(
|
||||
new DLCConnectionHandler(
|
||||
dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
connection,
|
||||
handlerP,
|
||||
dataHandlerFactory,
|
||||
@ -127,6 +132,7 @@ class DLCClient(
|
||||
Props(
|
||||
new DLCConnectionHandler(
|
||||
dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
proxy,
|
||||
handlerP,
|
||||
dataHandlerFactory,
|
||||
@ -155,6 +161,7 @@ object DLCClient {
|
||||
|
||||
def props(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connectedAddress: Option[Promise[InetSocketAddress]],
|
||||
handlerP: Option[Promise[ActorRef]],
|
||||
dataHandlerFactory: DLCDataHandler.Factory,
|
||||
@ -164,6 +171,7 @@ object DLCClient {
|
||||
Props(
|
||||
new DLCClient(
|
||||
dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
connectedAddress,
|
||||
handlerP,
|
||||
dataHandlerFactory,
|
||||
@ -175,6 +183,7 @@ object DLCClient {
|
||||
def connect(
|
||||
peer: Peer,
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
handlerP: Option[Promise[ActorRef]],
|
||||
dataHandlerFactory: DLCDataHandler.Factory =
|
||||
DLCDataHandler.defaultFactory,
|
||||
@ -186,6 +195,7 @@ object DLCClient {
|
||||
system.actorOf(
|
||||
props(
|
||||
dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
Some(promise),
|
||||
handlerP,
|
||||
dataHandlerFactory,
|
||||
|
@ -5,9 +5,12 @@ import org.apache.pekko.event.LoggingReceive
|
||||
import org.apache.pekko.io.Tcp
|
||||
import org.apache.pekko.util.ByteString
|
||||
import org.bitcoins.commons.util.BitcoinSLogger
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.protocol.BigSizeUInt
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.tlv.*
|
||||
import org.bitcoins.dlc.node.DLCConnectionHandler.parseIndividualMessages
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
@ -18,6 +21,7 @@ import scala.util.{Failure, Success, Try}
|
||||
|
||||
class DLCConnectionHandler(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connection: ActorRef,
|
||||
handlerP: Option[Promise[ActorRef]],
|
||||
dataHandlerFactory: DLCDataHandler.Factory,
|
||||
@ -27,7 +31,8 @@ class DLCConnectionHandler(
|
||||
with ActorLogging {
|
||||
|
||||
private val handler = {
|
||||
val h = dataHandlerFactory(dlcWalletApi, context, self)
|
||||
val h =
|
||||
dataHandlerFactory(dlcWalletApi, incomingOfferHandling, context, self)
|
||||
handlerP.foreach(_.success(h))
|
||||
h
|
||||
}
|
||||
@ -142,6 +147,7 @@ object DLCConnectionHandler extends BitcoinSLogger {
|
||||
|
||||
def props(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connection: ActorRef,
|
||||
handlerP: Option[Promise[ActorRef]],
|
||||
dataHandlerFactory: DLCDataHandler.Factory,
|
||||
@ -151,6 +157,7 @@ object DLCConnectionHandler extends BitcoinSLogger {
|
||||
Props(
|
||||
new DLCConnectionHandler(
|
||||
dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
connection,
|
||||
handlerP,
|
||||
dataHandlerFactory,
|
||||
|
@ -9,12 +9,18 @@ import org.apache.pekko.actor.{
|
||||
Terminated
|
||||
}
|
||||
import org.apache.pekko.event.LoggingReceive
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCWalletApi
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.protocol.tlv.*
|
||||
|
||||
import scala.concurrent._
|
||||
import scala.concurrent.*
|
||||
|
||||
class DLCDataHandler(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef)
|
||||
class DLCDataHandler(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connectionHandler: ActorRef)
|
||||
extends Actor
|
||||
with ActorLogging {
|
||||
implicit val ec: ExecutionContextExecutor = context.system.dispatcher
|
||||
@ -58,11 +64,13 @@ class DLCDataHandler(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef)
|
||||
Future.unit
|
||||
case dlcOffer: DLCOfferTLV =>
|
||||
for {
|
||||
_ <- dlcWalletApi.registerIncomingDLCOffer(dlcOffer, None, None)
|
||||
_ <- incomingOfferHandling.registerIncomingDLCOffer(dlcOffer,
|
||||
None,
|
||||
None)
|
||||
} yield ()
|
||||
case dlcOfferMessage: SendOfferTLV =>
|
||||
for {
|
||||
_ <- dlcWalletApi.registerIncomingDLCOffer(
|
||||
_ <- incomingOfferHandling.registerIncomingDLCOffer(
|
||||
offerTLV = dlcOfferMessage.offer,
|
||||
peer = Some(dlcOfferMessage.peer),
|
||||
message = Some(dlcOfferMessage.message)
|
||||
@ -91,7 +99,11 @@ class DLCDataHandler(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef)
|
||||
|
||||
object DLCDataHandler {
|
||||
|
||||
type Factory = (DLCWalletApi, ActorContext, ActorRef) => ActorRef
|
||||
type Factory = (
|
||||
DLCWalletApi,
|
||||
IncomingDLCOfferHandlingApi,
|
||||
ActorContext,
|
||||
ActorRef) => ActorRef
|
||||
|
||||
sealed trait Command
|
||||
case class Received(message: LnMessage[TLV]) extends Command
|
||||
@ -99,12 +111,20 @@ object DLCDataHandler {
|
||||
|
||||
def defaultFactory(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
context: ActorContext,
|
||||
connectionHandler: ActorRef
|
||||
): ActorRef = {
|
||||
context.actorOf(props(dlcWalletApi, connectionHandler))
|
||||
context.actorOf(
|
||||
props(dlcWalletApi, incomingOfferHandling, connectionHandler))
|
||||
}
|
||||
|
||||
def props(dlcWalletApi: DLCWalletApi, connectionHandler: ActorRef): Props =
|
||||
Props(new DLCDataHandler(dlcWalletApi, connectionHandler))
|
||||
def props(
|
||||
dlcWalletApi: DLCWalletApi,
|
||||
incomingOfferHandling: IncomingDLCOfferHandlingApi,
|
||||
connectionHandler: ActorRef): Props =
|
||||
Props(
|
||||
new DLCDataHandler(dlcWalletApi,
|
||||
incomingOfferHandling,
|
||||
connectionHandler))
|
||||
}
|
||||
|
@ -220,6 +220,7 @@ case class DLCNode(wallet: DLCWalletApi)(implicit
|
||||
_ <- DLCClient.connect(
|
||||
peer,
|
||||
wallet,
|
||||
wallet.incomingOfferHandling,
|
||||
Some(handlerP),
|
||||
handleWrite = handleTLVSendSucceed,
|
||||
handleWriteError = handleTLVSendFailed
|
||||
|
@ -57,6 +57,7 @@ class DLCServer(
|
||||
Props(
|
||||
new DLCConnectionHandler(
|
||||
dlcWalletApi,
|
||||
dlcWalletApi.incomingOfferHandling,
|
||||
connection,
|
||||
None,
|
||||
dataHandlerFactory,
|
||||
|
@ -544,7 +544,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
|
||||
it must "cancel an offered DLC" in {
|
||||
(FundedDLCWallets: (FundedDLCWallet, FundedDLCWallet)) =>
|
||||
val walletA = FundedDLCWallets._1.wallet
|
||||
val dlcWalletA = FundedDLCWallets._1.wallet
|
||||
val walletApiA = dlcWalletA.walletApi
|
||||
|
||||
val offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer
|
||||
|
||||
@ -555,11 +556,11 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
val announcementTLV = announcementTLVs.head
|
||||
|
||||
for {
|
||||
oldBalance <- walletA.getBalance()
|
||||
oldReserved <- walletA.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
oldBalance <- dlcWalletA.getBalance()
|
||||
oldReserved <- walletApiA.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
_ = assert(oldReserved.isEmpty)
|
||||
|
||||
offer <- walletA.createDLCOffer(
|
||||
offer <- dlcWalletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
offerData.collateral,
|
||||
Some(offerData.feeRate),
|
||||
@ -572,18 +573,18 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
|
||||
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
|
||||
|
||||
_ <- walletA.cancelDLC(dlcId)
|
||||
_ <- dlcWalletA.cancelDLC(dlcId)
|
||||
|
||||
announcementData <- walletA.announcementDAO.findByPublicKey(
|
||||
announcementData <- dlcWalletA.announcementDAO.findByPublicKey(
|
||||
announcementTLV.publicKey
|
||||
)
|
||||
nonceDbs <- walletA.oracleNonceDAO.findByAnnouncementIds(
|
||||
nonceDbs <- dlcWalletA.oracleNonceDAO.findByAnnouncementIds(
|
||||
announcementData.map(_.id.get)
|
||||
)
|
||||
|
||||
balance <- walletA.getBalance()
|
||||
reserved <- walletA.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
dlcOpt <- walletA.findDLC(dlcId)
|
||||
balance <- dlcWalletA.getBalance()
|
||||
reserved <- walletApiA.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
dlcOpt <- dlcWalletA.findDLC(dlcId)
|
||||
} yield {
|
||||
assert(balance == oldBalance)
|
||||
assert(reserved.isEmpty)
|
||||
@ -597,17 +598,19 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
|
||||
it must "cancel an accepted DLC" in {
|
||||
(FundedDLCWallets: (FundedDLCWallet, FundedDLCWallet)) =>
|
||||
val walletA = FundedDLCWallets._1.wallet
|
||||
val walletB = FundedDLCWallets._2.wallet
|
||||
val dlcWalletA = FundedDLCWallets._1.wallet
|
||||
val dlcWalletB = FundedDLCWallets._2.wallet
|
||||
|
||||
val walletApiB = dlcWalletB.walletApi
|
||||
|
||||
val offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer
|
||||
|
||||
for {
|
||||
oldBalance <- walletB.getBalance()
|
||||
oldReserved <- walletB.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
oldBalance <- dlcWalletB.getBalance()
|
||||
oldReserved <- walletApiB.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
_ = assert(oldReserved.isEmpty)
|
||||
|
||||
offer <- walletA.createDLCOffer(
|
||||
offer <- dlcWalletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
offerData.collateral,
|
||||
Some(offerData.feeRate),
|
||||
@ -617,15 +620,15 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
None,
|
||||
None
|
||||
)
|
||||
_ <- walletB.acceptDLCOffer(offer, None, None, None)
|
||||
_ <- dlcWalletB.acceptDLCOffer(offer, None, None, None)
|
||||
|
||||
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
|
||||
|
||||
_ <- walletB.cancelDLC(dlcId)
|
||||
_ <- dlcWalletB.cancelDLC(dlcId)
|
||||
|
||||
balance <- walletB.getBalance()
|
||||
reserved <- walletB.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
dlcOpt <- walletB.findDLC(dlcId)
|
||||
balance <- dlcWalletB.getBalance()
|
||||
reserved <- walletApiB.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
dlcOpt <- dlcWalletB.findDLC(dlcId)
|
||||
} yield {
|
||||
assert(balance == oldBalance)
|
||||
assert(reserved.isEmpty)
|
||||
@ -635,25 +638,28 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
|
||||
it must "cancel a signed DLC" in {
|
||||
(FundedDLCWallets: (FundedDLCWallet, FundedDLCWallet)) =>
|
||||
val walletA = FundedDLCWallets._1.wallet
|
||||
val walletB = FundedDLCWallets._2.wallet
|
||||
val dlcWalletA = FundedDLCWallets._1.wallet
|
||||
val dlcWalletB = FundedDLCWallets._2.wallet
|
||||
|
||||
val walletApiA = dlcWalletA.walletApi
|
||||
val walletApiB = dlcWalletB.walletApi
|
||||
|
||||
val offerData: DLCOffer = DLCWalletUtil.sampleDLCOffer
|
||||
|
||||
for {
|
||||
oldBalanceA <- walletA.getBalance()
|
||||
oldReservedA <- walletA.spendingInfoDAO.findByTxoState(
|
||||
oldBalanceA <- dlcWalletA.getBalance()
|
||||
oldReservedA <- walletApiA.utxoHandling.listUtxos(
|
||||
TxoState.Reserved
|
||||
)
|
||||
_ = assert(oldReservedA.isEmpty)
|
||||
|
||||
oldBalanceB <- walletB.getBalance()
|
||||
oldReservedB <- walletB.spendingInfoDAO.findByTxoState(
|
||||
oldBalanceB <- dlcWalletB.getBalance()
|
||||
oldReservedB <- walletApiB.utxoHandling.listUtxos(
|
||||
TxoState.Reserved
|
||||
)
|
||||
_ = assert(oldReservedB.isEmpty)
|
||||
|
||||
offer <- walletA.createDLCOffer(
|
||||
offer <- dlcWalletA.createDLCOffer(
|
||||
offerData.contractInfo,
|
||||
offerData.collateral,
|
||||
Some(offerData.feeRate),
|
||||
@ -663,22 +669,22 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
|
||||
None,
|
||||
None
|
||||
)
|
||||
accept <- walletB.acceptDLCOffer(offer, None, None, None)
|
||||
sign <- walletA.signDLC(accept)
|
||||
_ <- walletB.addDLCSigs(sign)
|
||||
accept <- dlcWalletB.acceptDLCOffer(offer, None, None, None)
|
||||
sign <- dlcWalletA.signDLC(accept)
|
||||
_ <- dlcWalletB.addDLCSigs(sign)
|
||||
|
||||
dlcId = calcDLCId(offer.fundingInputs.map(_.outPoint))
|
||||
|
||||
_ <- walletA.cancelDLC(dlcId)
|
||||
_ <- walletB.cancelDLC(dlcId)
|
||||
_ <- dlcWalletA.cancelDLC(dlcId)
|
||||
_ <- dlcWalletB.cancelDLC(dlcId)
|
||||
|
||||
balanceA <- walletA.getBalance()
|
||||
reservedA <- walletA.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
dlcAOpt <- walletA.findDLC(dlcId)
|
||||
balanceA <- dlcWalletA.getBalance()
|
||||
reservedA <- walletApiA.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
dlcAOpt <- dlcWalletA.findDLC(dlcId)
|
||||
|
||||
balanceB <- walletB.getBalance()
|
||||
reservedB <- walletB.spendingInfoDAO.findByTxoState(TxoState.Reserved)
|
||||
dlcBOpt <- walletB.findDLC(dlcId)
|
||||
balanceB <- dlcWalletB.getBalance()
|
||||
reservedB <- walletApiB.utxoHandling.listUtxos(TxoState.Reserved)
|
||||
dlcBOpt <- dlcWalletB.findDLC(dlcId)
|
||||
} yield {
|
||||
assert(balanceA == oldBalanceA)
|
||||
assert(reservedA.isEmpty)
|
||||
|
@ -334,13 +334,12 @@ object DLCAppConfig
|
||||
walletConf.hasWallet().flatMap { walletExists =>
|
||||
if (walletExists) {
|
||||
logger.info(s"Using pre-existing wallet")
|
||||
val wallet =
|
||||
DLCWallet(nodeApi, chainQueryApi)
|
||||
Future.successful(wallet)
|
||||
val walletF = walletConf.createHDWallet(nodeApi, chainQueryApi)
|
||||
walletF.map(DLCWallet.apply)
|
||||
} else {
|
||||
logger.info(s"Creating new wallet")
|
||||
val unInitializedWallet =
|
||||
DLCWallet(nodeApi, chainQueryApi)
|
||||
Wallet(nodeApi, chainQueryApi)
|
||||
|
||||
Wallet
|
||||
.initialize(
|
||||
@ -348,7 +347,7 @@ object DLCAppConfig
|
||||
accountHandling = unInitializedWallet.accountHandling,
|
||||
bip39PasswordOpt = bip39PasswordOpt
|
||||
)
|
||||
.map(_.asInstanceOf[DLCWallet])
|
||||
.map(DLCWallet.apply)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,31 @@
|
||||
package org.bitcoins.dlc.wallet
|
||||
|
||||
import org.bitcoins.commons.util.BitcoinSLogger
|
||||
import org.bitcoins.core.api.chain.ChainQueryApi
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCNeutrinoHDWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCNeutrinoHDWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
|
||||
import org.bitcoins.core.api.feeprovider.FeeRateApi
|
||||
import org.bitcoins.core.api.node.NodeApi
|
||||
import org.bitcoins.core.api.wallet.{
|
||||
AccountHandlingApi,
|
||||
AddressHandlingApi,
|
||||
BlockSyncState,
|
||||
FundTransactionHandlingApi,
|
||||
NeutrinoHDWalletApi,
|
||||
RescanHandlingApi,
|
||||
SendFundsHandlingApi,
|
||||
SyncHeightDescriptor,
|
||||
UtxoHandlingApi,
|
||||
WalletInfo
|
||||
}
|
||||
import org.bitcoins.core.api.wallet.db.*
|
||||
import org.bitcoins.core.config.NetworkParameters
|
||||
import org.bitcoins.core.currency.*
|
||||
import org.bitcoins.core.dlc.accounting.DLCWalletAccounting
|
||||
import org.bitcoins.core.gcs.GolombFilter
|
||||
import org.bitcoins.core.hd.*
|
||||
import org.bitcoins.core.number.*
|
||||
import org.bitcoins.core.protocol.*
|
||||
@ -39,72 +58,72 @@ import org.bitcoins.dlc.wallet.util.{
|
||||
IntermediaryDLCStatus
|
||||
}
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import org.bitcoins.wallet.internal.TransactionProcessing
|
||||
import org.bitcoins.wallet.models.WalletDAOs
|
||||
import org.bitcoins.wallet.internal.{
|
||||
RescanHandling,
|
||||
TransactionProcessing,
|
||||
UtxoHandling
|
||||
}
|
||||
import org.bitcoins.wallet.models.{
|
||||
AddressDAO,
|
||||
ScriptPubKeyDAO,
|
||||
TransactionDAO,
|
||||
WalletDAOs
|
||||
}
|
||||
import org.bitcoins.wallet.{Wallet, WalletLogger}
|
||||
import scodec.bits.ByteVector
|
||||
import slick.dbio.*
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
import java.time.Instant
|
||||
import scala.concurrent.Future
|
||||
|
||||
/** A [[Wallet]] with full DLC Functionality */
|
||||
abstract class DLCWallet
|
||||
extends Wallet
|
||||
with DLCNeutrinoHDWalletApi
|
||||
with IncomingDLCOffersHandling {
|
||||
|
||||
implicit val dlcConfig: DLCAppConfig
|
||||
case class DLCWallet(override val walletApi: Wallet)(implicit
|
||||
val dlcConfig: DLCAppConfig,
|
||||
val walletConfig: WalletAppConfig)
|
||||
extends DLCNeutrinoHDWalletApi
|
||||
with BitcoinSLogger {
|
||||
import dlcConfig.ec
|
||||
|
||||
import dlcConfig.profile.api._
|
||||
|
||||
private val networkParameters: NetworkParameters = walletConfig.network
|
||||
private[wallet] val dlcWalletDAOs = DLCWalletDAOs.fromDLCAppConfig(dlcConfig)
|
||||
private[bitcoins] val announcementDAO: OracleAnnouncementDataDAO =
|
||||
OracleAnnouncementDataDAO()
|
||||
private[bitcoins] val oracleNonceDAO: OracleNonceDAO = OracleNonceDAO()
|
||||
dlcWalletDAOs.oracleAnnouncementDAO
|
||||
private[bitcoins] val oracleNonceDAO: OracleNonceDAO =
|
||||
dlcWalletDAOs.oracleNonceDAO
|
||||
|
||||
private[bitcoins] val dlcAnnouncementDAO: DLCAnnouncementDAO =
|
||||
DLCAnnouncementDAO()
|
||||
private[bitcoins] val dlcOfferDAO: DLCOfferDAO = DLCOfferDAO()
|
||||
private[bitcoins] val dlcAcceptDAO: DLCAcceptDAO = DLCAcceptDAO()
|
||||
private[bitcoins] val dlcDAO: DLCDAO = DLCDAO()
|
||||
dlcWalletDAOs.dlcAnnouncementDAO
|
||||
private[bitcoins] val dlcOfferDAO: DLCOfferDAO = dlcWalletDAOs.dlcOfferDAO
|
||||
private[bitcoins] val dlcAcceptDAO: DLCAcceptDAO = dlcWalletDAOs.dlcAcceptDAO
|
||||
private[bitcoins] val dlcDAO: DLCDAO = dlcWalletDAOs.dlcDAO
|
||||
|
||||
private[bitcoins] val contractDataDAO: DLCContractDataDAO =
|
||||
DLCContractDataDAO()
|
||||
private[bitcoins] val dlcInputsDAO: DLCFundingInputDAO = DLCFundingInputDAO()
|
||||
private[bitcoins] val dlcSigsDAO: DLCCETSignaturesDAO = DLCCETSignaturesDAO()
|
||||
private[bitcoins] val dlcRefundSigDAO: DLCRefundSigsDAO = DLCRefundSigsDAO()
|
||||
private[bitcoins] val remoteTxDAO: DLCRemoteTxDAO = DLCRemoteTxDAO()
|
||||
|
||||
private[bitcoins] val incomingOfferDAO: IncomingDLCOfferDAO =
|
||||
IncomingDLCOfferDAO()
|
||||
dlcWalletDAOs.contractDataDAO
|
||||
private[bitcoins] val dlcInputsDAO: DLCFundingInputDAO =
|
||||
dlcWalletDAOs.dlcInputsDAO
|
||||
private[bitcoins] val dlcSigsDAO: DLCCETSignaturesDAO =
|
||||
dlcWalletDAOs.dlcSigsDAO
|
||||
private[bitcoins] val dlcRefundSigDAO: DLCRefundSigsDAO =
|
||||
dlcWalletDAOs.dlcRefundSigDAO
|
||||
private[bitcoins] val remoteTxDAO: DLCRemoteTxDAO =
|
||||
dlcWalletDAOs.dlcRemoteTxDAO
|
||||
|
||||
private[bitcoins] val contactDAO: DLCContactDAO =
|
||||
DLCContactDAO()
|
||||
dlcWalletDAOs.contactDAO
|
||||
|
||||
private val walletDAOs: WalletDAOs = WalletDAOs(accountDAO,
|
||||
addressDAO,
|
||||
addressTagDAO,
|
||||
spendingInfoDAO,
|
||||
transactionDAO,
|
||||
incomingTxDAO,
|
||||
outgoingTxDAO,
|
||||
scriptPubKeyDAO,
|
||||
stateDescriptorDAO)
|
||||
private[wallet] val dlcWalletDAOs = DLCWalletDAOs(
|
||||
dlcDAO,
|
||||
contractDataDAO,
|
||||
dlcAnnouncementDAO,
|
||||
dlcInputsDAO,
|
||||
dlcOfferDAO,
|
||||
dlcAcceptDAO,
|
||||
dlcSigsDAO,
|
||||
dlcRefundSigDAO,
|
||||
oracleNonceDAO,
|
||||
announcementDAO,
|
||||
remoteTxDAO,
|
||||
incomingOfferDAO,
|
||||
contactDAO
|
||||
)
|
||||
private def walletDAOs: WalletDAOs = walletApi.walletDAOs
|
||||
|
||||
private[bitcoins] def addressDAO: AddressDAO = walletApi.addressDAO
|
||||
private[bitcoins] def transactionDAO: TransactionDAO =
|
||||
walletApi.transactionDAO
|
||||
private[bitcoins] def scriptPubKeyDAO: ScriptPubKeyDAO =
|
||||
walletApi.scriptPubKeyDAO
|
||||
|
||||
override def incomingOfferHandling: IncomingDLCOfferHandlingApi =
|
||||
IncomingDLCOffersHandling(dlcWalletDAOs)
|
||||
|
||||
private[wallet] val dlcDataManagement = DLCDataManagement(dlcWalletDAOs)
|
||||
|
||||
@ -116,22 +135,34 @@ abstract class DLCWallet
|
||||
val txProcessing = TransactionProcessing(
|
||||
walletApi = this,
|
||||
chainQueryApi = chainQueryApi,
|
||||
utxoHandling = utxoHandling,
|
||||
utxoHandling = utxoHandling.asInstanceOf[UtxoHandling],
|
||||
walletDAOs = walletDAOs
|
||||
)
|
||||
)(walletApi.walletConfig, ec)
|
||||
DLCTransactionProcessing(
|
||||
txProcessing = txProcessing,
|
||||
dlcWalletDAOs = dlcWalletDAOs,
|
||||
walletDAOs = walletDAOs,
|
||||
dlcDataManagement = dlcDataManagement,
|
||||
keyManager = keyManager,
|
||||
transactionDAO = transactionDAO,
|
||||
keyManager = walletApi.keyManager,
|
||||
transactionDAO = walletDAOs.transactionDAO,
|
||||
utxoHandling = utxoHandling,
|
||||
dlcWalletApi = this
|
||||
)
|
||||
}
|
||||
|
||||
override lazy val rescanHandling: RescanHandlingApi = {
|
||||
RescanHandling(
|
||||
transactionProcessing = transactionProcessing,
|
||||
accountHandling = accountHandling,
|
||||
addressHandling = addressHandling,
|
||||
chainQueryApi = chainQueryApi,
|
||||
nodeApi = nodeApi,
|
||||
walletDAOs = walletDAOs
|
||||
)(walletConfig, walletConfig.system)
|
||||
}
|
||||
private lazy val safeDLCDatabase: SafeDatabase = dlcDAO.safeDatabase
|
||||
private lazy val walletDatabase: SafeDatabase = addressDAO.safeDatabase
|
||||
private lazy val walletDatabase: SafeDatabase =
|
||||
walletDAOs.addressDAO.safeDatabase
|
||||
|
||||
/** Updates the contract Id in the wallet database for the given offer and
|
||||
* accept
|
||||
@ -299,8 +330,8 @@ abstract class DLCWallet
|
||||
index: Int
|
||||
): Future[Vector[AddressDb]] = {
|
||||
for {
|
||||
zero <- addressHandling.getAddress(account, chainType, index)
|
||||
one <- addressHandling.getAddress(account, chainType, index + 1)
|
||||
zero <- walletApi.addressHandling.getAddress(account, chainType, index)
|
||||
one <- walletApi.addressHandling.getAddress(account, chainType, index + 1)
|
||||
} yield {
|
||||
logger.debug(s"Wrote DLC key addresses to database using index $index")
|
||||
Vector(zero, one)
|
||||
@ -331,7 +362,7 @@ abstract class DLCWallet
|
||||
s"Canceling DLC with tempContractId=${dlcDb.tempContractId.hex} dlcId=${dlcId.hex} contractId=${dlcDb.contractIdOpt}"
|
||||
)
|
||||
inputs <- dlcInputsDAO.findByDLCId(dlcId, dlcDb.isInitiator)
|
||||
dbs <- spendingInfoDAO.findByOutPoints(inputs.map(_.outPoint))
|
||||
dbs <- walletDAOs.utxoDAO.findByOutPoints(inputs.map(_.outPoint))
|
||||
// allow this to fail in the case they have already been unreserved
|
||||
_ <- utxoHandling.unmarkUTXOsAsReserved(dbs).recoverWith {
|
||||
case scala.util.control.NonFatal(_) => Future.successful(Vector.empty)
|
||||
@ -430,10 +461,11 @@ abstract class DLCWallet
|
||||
chainType = HDChainType.External
|
||||
|
||||
account <- accountHandling.getDefaultAccountForType(AddressType.SegWit)
|
||||
nextIndex <- addressHandling.getNextAvailableIndex(account, chainType)
|
||||
nextIndex <- walletApi.addressHandling.getNextAvailableIndex(account,
|
||||
chainType)
|
||||
_ <- writeDLCKeysToAddressDb(account, chainType, nextIndex)
|
||||
|
||||
fundRawTxHelper <- fundTxHandling.fundRawTransactionInternal(
|
||||
fundRawTxHelper <- walletApi.fundTxHandling.fundRawTransactionInternal(
|
||||
destinations = Vector(TransactionOutput(collateral, EmptyScriptPubKey)),
|
||||
feeRate = feeRate,
|
||||
fromAccount = account,
|
||||
@ -635,7 +667,7 @@ abstract class DLCWallet
|
||||
}
|
||||
case None =>
|
||||
val nextIndexF =
|
||||
addressHandling.getNextAvailableIndex(account, chainType)
|
||||
walletApi.addressHandling.getNextAvailableIndex(account, chainType)
|
||||
val acceptWithoutSigsWithKeysF
|
||||
: Future[(DLCAcceptWithoutSigs, DLCPublicKeys)] =
|
||||
nextIndexF.map { nextIndex =>
|
||||
@ -838,7 +870,7 @@ abstract class DLCWallet
|
||||
val txBuilderAndSpendingInfosF
|
||||
: Future[FundRawTxHelper[ShufflingNonInteractiveFinalizer]] = {
|
||||
for {
|
||||
fundRawTxHelper <- fundTxHandling.fundRawTransactionInternal(
|
||||
fundRawTxHelper <- walletApi.fundTxHandling.fundRawTransactionInternal(
|
||||
destinations =
|
||||
Vector(TransactionOutput(collateral, EmptyScriptPubKey)),
|
||||
feeRate = offer.feeRate,
|
||||
@ -862,7 +894,7 @@ abstract class DLCWallet
|
||||
)
|
||||
)
|
||||
val privKeyPath = HDPath.fromString(bip32Path.toString)
|
||||
keyManager.toSign(privKeyPath)
|
||||
walletApi.keyManager.toSign(privKeyPath)
|
||||
}
|
||||
|
||||
private def createNewDLCAccept(
|
||||
@ -1215,7 +1247,7 @@ abstract class DLCWallet
|
||||
dlcId = dlc.dlcId,
|
||||
transactionDAO = transactionDAO,
|
||||
fundingUtxoScriptSigParams = scriptSigParams,
|
||||
keyManager = keyManager
|
||||
keyManager = walletApi.keyManager
|
||||
)
|
||||
|
||||
mySigs <- dlcSigsDAO.findByDLCId(dlc.dlcId)
|
||||
@ -1574,7 +1606,7 @@ abstract class DLCWallet
|
||||
dlcDb = dlcDb,
|
||||
fundingUtxoScriptSigParams = scriptSigParams,
|
||||
transactionDAO = transactionDAO,
|
||||
keyManager = keyManager
|
||||
keyManager = walletApi.keyManager
|
||||
)
|
||||
_ = require(
|
||||
signerOpt.isDefined,
|
||||
@ -1635,11 +1667,13 @@ abstract class DLCWallet
|
||||
isValidBroadcastState(dlcDb)
|
||||
}
|
||||
tx <- fundingTxF
|
||||
_ <- updateDLCState(contractId, DLCState.Broadcasted)
|
||||
state <- updateDLCState(contractId, DLCState.Broadcasted)
|
||||
_ = logger.info(
|
||||
s"Broadcasting funding transaction ${tx.txIdBE.hex} for contract ${contractId.toHex}"
|
||||
)
|
||||
_ <- broadcastTransaction(tx)
|
||||
status <- findDLC(state.dlcId)
|
||||
_ <- dlcConfig.walletCallbacks.executeOnDLCStateChange(status.get)
|
||||
_ = logger.info(s"Done broadcast tx ${contractId}")
|
||||
} yield tx
|
||||
}
|
||||
@ -1773,7 +1807,7 @@ abstract class DLCWallet
|
||||
contractId = contractId,
|
||||
txDAO = transactionDAO,
|
||||
fundingUtxoScriptSigParams = scriptSigParams,
|
||||
keyManager = keyManager
|
||||
keyManager = walletApi.keyManager
|
||||
)
|
||||
}
|
||||
executorWithSetupOptF.flatMap {
|
||||
@ -1879,7 +1913,7 @@ abstract class DLCWallet
|
||||
dlcDb.dlcId,
|
||||
transactionDAO,
|
||||
scriptSigParams,
|
||||
keyManager
|
||||
walletApi.keyManager
|
||||
)
|
||||
_ = require(
|
||||
executorOpt.isDefined,
|
||||
@ -2254,6 +2288,62 @@ abstract class DLCWallet
|
||||
case Some(feeRate) =>
|
||||
Future.successful(feeRate)
|
||||
}
|
||||
|
||||
override def broadcastTransaction(transaction: Transaction): Future[Unit] = {
|
||||
walletApi.broadcastTransaction(transaction)
|
||||
}
|
||||
|
||||
override def processCompactFilters(
|
||||
blockFilters: Vector[(DoubleSha256DigestBE, GolombFilter)])
|
||||
: Future[NeutrinoHDWalletApi] =
|
||||
walletApi.processCompactFilters(blockFilters)
|
||||
|
||||
override def accountHandling: AccountHandlingApi = walletApi.accountHandling
|
||||
|
||||
override def fundTxHandling: FundTransactionHandlingApi =
|
||||
walletApi.fundTxHandling
|
||||
|
||||
override def addressHandling: AddressHandlingApi = walletApi.addressHandling
|
||||
|
||||
override def utxoHandling: UtxoHandlingApi = walletApi.utxoHandling
|
||||
|
||||
override def sendFundsHandling: SendFundsHandlingApi =
|
||||
walletApi.sendFundsHandling
|
||||
|
||||
override val nodeApi: NodeApi = walletApi.nodeApi
|
||||
override val chainQueryApi: ChainQueryApi = walletApi.chainQueryApi
|
||||
|
||||
override def feeRateApi: FeeRateApi = walletApi.feeRateApi
|
||||
|
||||
override val creationTime: Instant = walletApi.creationTime
|
||||
|
||||
/** Gets the sum of all confirmed UTXOs in this wallet */
|
||||
override def getConfirmedBalance(): Future[CurrencyUnit] =
|
||||
walletApi.getConfirmedBalance()
|
||||
|
||||
override def getNewAddress(): Future[BitcoinAddress] =
|
||||
walletApi.getNewAddress()
|
||||
|
||||
override def getNewChangeAddress(): Future[BitcoinAddress] =
|
||||
walletApi.getNewChangeAddress()
|
||||
|
||||
/** Gets the sum of all unconfirmed UTXOs in this wallet */
|
||||
override def getUnconfirmedBalance(): Future[CurrencyUnit] =
|
||||
walletApi.getUnconfirmedBalance()
|
||||
|
||||
/** Checks if the wallet contains any data */
|
||||
override def isEmpty(): Future[Boolean] = walletApi.isEmpty()
|
||||
|
||||
override def getSyncState(): Future[BlockSyncState] = walletApi.getSyncState()
|
||||
|
||||
override def isRescanning(): Future[Boolean] = walletApi.isRescanning()
|
||||
|
||||
override def getSyncDescriptorOpt(): Future[Option[SyncHeightDescriptor]] =
|
||||
walletApi.getSyncDescriptorOpt()
|
||||
|
||||
override def getWalletName(): Future[String] = walletApi.getWalletName()
|
||||
|
||||
override def getInfo(): Future[WalletInfo] = walletApi.getInfo()
|
||||
}
|
||||
|
||||
object DLCWallet extends WalletLogger {
|
||||
@ -2264,21 +2354,6 @@ object DLCWallet extends WalletLogger {
|
||||
case class InvalidAnnouncementSignature(message: String)
|
||||
extends RuntimeException(message)
|
||||
|
||||
private case class DLCWalletImpl(
|
||||
nodeApi: NodeApi,
|
||||
chainQueryApi: ChainQueryApi
|
||||
)(implicit
|
||||
val walletConfig: WalletAppConfig,
|
||||
val dlcConfig: DLCAppConfig
|
||||
) extends DLCWallet
|
||||
|
||||
def apply(
|
||||
nodeApi: NodeApi,
|
||||
chainQueryApi: ChainQueryApi
|
||||
)(implicit config: WalletAppConfig, dlcConfig: DLCAppConfig): DLCWallet = {
|
||||
DLCWalletImpl(nodeApi, chainQueryApi)
|
||||
}
|
||||
|
||||
private object AcceptingOffersLatch {
|
||||
|
||||
private val tempContractIds =
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.bitcoins.dlc.wallet.internal
|
||||
|
||||
import org.bitcoins.core.api.dlc.wallet.IncomingDLCOfferHandlingApi
|
||||
import org.bitcoins.core.api.dlc.wallet.db.{
|
||||
DLCContactDb,
|
||||
DLCContactDbHelper,
|
||||
@ -7,15 +8,25 @@ import org.bitcoins.core.api.dlc.wallet.db.{
|
||||
}
|
||||
import org.bitcoins.core.protocol.tlv.DLCOfferTLV
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
import org.bitcoins.dlc.wallet.DLCWallet
|
||||
import org.bitcoins.dlc.wallet.models.IncomingDLCOfferDbHelper
|
||||
import org.bitcoins.dlc.wallet.DLCAppConfig
|
||||
import org.bitcoins.dlc.wallet.models.{
|
||||
DLCContactDAO,
|
||||
DLCDAO,
|
||||
DLCWalletDAOs,
|
||||
IncomingDLCOfferDbHelper
|
||||
}
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
import scala.concurrent.Future
|
||||
|
||||
trait IncomingDLCOffersHandling { self: DLCWallet =>
|
||||
case class IncomingDLCOffersHandling(dlcWalletDAOs: DLCWalletDAOs)(implicit
|
||||
dlcConfig: DLCAppConfig)
|
||||
extends IncomingDLCOfferHandlingApi {
|
||||
import dlcConfig.ec
|
||||
|
||||
def registerIncomingDLCOffer(
|
||||
private val contactDAO: DLCContactDAO = dlcWalletDAOs.contactDAO
|
||||
private val dlcDAO: DLCDAO = dlcWalletDAOs.dlcDAO
|
||||
override def registerIncomingDLCOffer(
|
||||
offerTLV: DLCOfferTLV,
|
||||
peerOpt: Option[String],
|
||||
message: Option[String]
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.bitcoins.dlc.wallet.models
|
||||
|
||||
import org.bitcoins.dlc.wallet.DLCAppConfig
|
||||
|
||||
case class DLCWalletDAOs(
|
||||
dlcDAO: DLCDAO,
|
||||
contractDataDAO: DLCContractDataDAO,
|
||||
@ -15,3 +17,37 @@ case class DLCWalletDAOs(
|
||||
incomingDLCOfferDAO: IncomingDLCOfferDAO,
|
||||
contactDAO: DLCContactDAO
|
||||
)
|
||||
|
||||
object DLCWalletDAOs {
|
||||
def fromDLCAppConfig(dlcConfig: DLCAppConfig): DLCWalletDAOs = {
|
||||
val dlcDAO = DLCDAO()(dlcConfig.ec, dlcConfig)
|
||||
val contractDAO = DLCContractDataDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcAnnouncementDAO = DLCAnnouncementDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcInputsDAO = DLCFundingInputDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcOfferDAO = DLCOfferDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcAcceptDAO = DLCAcceptDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcSigsDAO = DLCCETSignaturesDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcRefundSigDAO = DLCRefundSigsDAO()(dlcConfig.ec, dlcConfig)
|
||||
val oracleNonceDAO = OracleNonceDAO()(dlcConfig.ec, dlcConfig)
|
||||
val oracleAnnouncementDAO =
|
||||
OracleAnnouncementDataDAO()(dlcConfig.ec, dlcConfig)
|
||||
val dlcRemoteTxDAO = DLCRemoteTxDAO()(dlcConfig.ec, dlcConfig)
|
||||
val incomingDLCOfferDAO = IncomingDLCOfferDAO()(dlcConfig.ec, dlcConfig)
|
||||
val contactDAO = DLCContactDAO()(dlcConfig.ec, dlcConfig)
|
||||
DLCWalletDAOs(
|
||||
dlcDAO = dlcDAO,
|
||||
contractDataDAO = contractDAO,
|
||||
dlcAnnouncementDAO = dlcAnnouncementDAO,
|
||||
dlcInputsDAO = dlcInputsDAO,
|
||||
dlcOfferDAO = dlcOfferDAO,
|
||||
dlcAcceptDAO = dlcAcceptDAO,
|
||||
dlcSigsDAO = dlcSigsDAO,
|
||||
dlcRefundSigDAO = dlcRefundSigDAO,
|
||||
oracleNonceDAO = oracleNonceDAO,
|
||||
oracleAnnouncementDAO = oracleAnnouncementDAO,
|
||||
dlcRemoteTxDAO = dlcRemoteTxDAO,
|
||||
incomingDLCOfferDAO = incomingDLCOfferDAO,
|
||||
contactDAO = contactDAO
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -304,17 +304,17 @@ object BitcoinSWalletTest extends WalletLogger {
|
||||
} yield ()
|
||||
|
||||
initConfs.flatMap { _ =>
|
||||
val wallet =
|
||||
DLCWallet(nodeApi, chainQueryApi)(
|
||||
config.walletConf,
|
||||
config.dlcConf
|
||||
)
|
||||
val wallet = Wallet(nodeApi, chainQueryApi)(config.walletConf)
|
||||
|
||||
Wallet
|
||||
.initialize(wallet,
|
||||
wallet.accountHandling,
|
||||
config.walletConf.bip39PasswordOpt)
|
||||
.map(_.asInstanceOf[DLCWallet])
|
||||
.map(w =>
|
||||
DLCWallet(w)(
|
||||
config.dlcConf,
|
||||
config.walletConf
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,8 +521,8 @@ object BitcoinSWalletTest extends WalletLogger {
|
||||
} yield ()
|
||||
}
|
||||
|
||||
def destroyDLCWallet(wallet: DLCWallet): Future[Unit] = {
|
||||
import wallet.ec
|
||||
def destroyDLCWallet(wallet: DLCWallet)(implicit
|
||||
ec: ExecutionContext): Future[Unit] = {
|
||||
for {
|
||||
_ <- destroyWalletAppConfig(wallet.walletConfig)
|
||||
_ <- wallet.dlcConfig.stop()
|
||||
|
@ -403,9 +403,13 @@ object DLCWalletUtil extends BitcoinSLogger {
|
||||
tx <- walletB.broadcastDLCFundingTx(sigs.contractId)
|
||||
_ <- walletA.transactionProcessing.processTransaction(tx, None)
|
||||
} yield {
|
||||
val fundedA =
|
||||
FundedDLCWallet(walletA, walletA.walletConfig, walletA.dlcConfig)
|
||||
val fundedB =
|
||||
FundedDLCWallet(walletB, walletB.walletConfig, walletB.dlcConfig)
|
||||
(
|
||||
InitializedDLCWallet(FundedDLCWallet(walletA)),
|
||||
InitializedDLCWallet(FundedDLCWallet(walletB))
|
||||
InitializedDLCWallet(fundedA),
|
||||
InitializedDLCWallet(fundedB)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ import org.apache.pekko.actor.ActorSystem
|
||||
import org.bitcoins.commons.util.BitcoinSLogger
|
||||
import org.bitcoins.core.api.chain.ChainQueryApi
|
||||
import org.bitcoins.core.api.node.NodeApi
|
||||
import org.bitcoins.core.api.wallet.NeutrinoHDWalletApi
|
||||
import org.bitcoins.core.api.wallet.{NeutrinoHDWalletApi, WalletApi}
|
||||
import org.bitcoins.core.currency.CurrencyUnit
|
||||
import org.bitcoins.core.hd.HDAccount
|
||||
import org.bitcoins.core.protocol.BitcoinAddress
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutput}
|
||||
import org.bitcoins.core.util.FutureUtil
|
||||
import org.bitcoins.crypto.DoubleSha256DigestBE
|
||||
import org.bitcoins.dlc.wallet.DLCWallet
|
||||
import org.bitcoins.dlc.wallet.{DLCAppConfig, DLCWallet}
|
||||
import org.bitcoins.rpc.client.common.BitcoindRpcClient
|
||||
import org.bitcoins.server.{BitcoinSAppConfig, BitcoindRpcBackendUtil}
|
||||
import org.bitcoins.testkit.wallet.BitcoinSWalletTest.{
|
||||
@ -24,7 +24,6 @@ import org.bitcoins.testkit.wallet.FundWalletUtil.{
|
||||
}
|
||||
import org.bitcoins.testkitcore.gen.TransactionGenerators
|
||||
import org.bitcoins.testkitcore.util.TransactionTestUtil
|
||||
import org.bitcoins.wallet.Wallet
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
@ -64,8 +63,8 @@ trait FundWalletUtil extends BitcoinSLogger {
|
||||
def fundAccountForWallet(
|
||||
amts: Vector[CurrencyUnit],
|
||||
account: HDAccount,
|
||||
wallet: Wallet
|
||||
)(implicit ec: ExecutionContext): Future[Wallet] = {
|
||||
wallet: WalletApi
|
||||
)(implicit ec: ExecutionContext): Future[WalletApi] = {
|
||||
|
||||
val addressesF: Future[Vector[BitcoinAddress]] = Future.sequence {
|
||||
Vector.fill(3)(wallet.accountHandling.getNewAddress(account))
|
||||
@ -132,17 +131,18 @@ trait FundWalletUtil extends BitcoinSLogger {
|
||||
/** Funds a bitcoin-s wallet with 3 utxos with 1, 2 and 3 bitcoin in the utxos
|
||||
*/
|
||||
def fundWallet(
|
||||
wallet: Wallet
|
||||
wallet: WalletApi,
|
||||
walletConfig: WalletAppConfig
|
||||
)(implicit ec: ExecutionContext): Future[FundedTestWallet] = {
|
||||
|
||||
val defaultAccount = wallet.walletConfig.defaultAccount
|
||||
val defaultAccount = walletConfig.defaultAccount
|
||||
val fundedDefaultAccountWalletF = FundWalletUtil.fundAccountForWallet(
|
||||
amts = BitcoinSWalletTest.defaultAcctAmts,
|
||||
account = defaultAccount,
|
||||
wallet = wallet
|
||||
)
|
||||
|
||||
val hdAccount1 = WalletTestUtil.getHdAccount1(wallet.walletConfig)
|
||||
val hdAccount1 = WalletTestUtil.getHdAccount1(walletConfig)
|
||||
val fundedAccount1WalletF = for {
|
||||
fundedDefaultAcct <- fundedDefaultAccountWalletF
|
||||
fundedAcct1 <- FundWalletUtil.fundAccountForWallet(
|
||||
@ -169,35 +169,28 @@ trait FundWalletUtil extends BitcoinSLogger {
|
||||
s"got balance=${hdAccount1} expected=${BitcoinSWalletTest.expectedAccount1Amt}"
|
||||
)
|
||||
|
||||
} yield FundedWallet(fundedWallet)
|
||||
} yield FundedWallet(fundedWallet, walletConfig)
|
||||
}
|
||||
}
|
||||
|
||||
object FundWalletUtil extends FundWalletUtil {
|
||||
|
||||
trait FundedTestWallet {
|
||||
def wallet: Wallet
|
||||
}
|
||||
|
||||
object FundedTestWallet {
|
||||
|
||||
def apply(wallet: Wallet): FundedTestWallet = {
|
||||
wallet match {
|
||||
case dlc: DLCWallet =>
|
||||
FundedDLCWallet(dlc)
|
||||
case _: Wallet =>
|
||||
FundedWallet(wallet)
|
||||
}
|
||||
}
|
||||
def wallet: WalletApi
|
||||
}
|
||||
|
||||
/** This is a wallet that was two funded accounts Account 0 (default account)
|
||||
* has utxos of 1,2,3 bitcoin in it (6 btc total) Account 1 has a utxos of
|
||||
* 0.2,0.3,0.5 bitcoin in it (0.6 total)
|
||||
*/
|
||||
case class FundedWallet(wallet: Wallet) extends FundedTestWallet
|
||||
case class FundedWallet(wallet: WalletApi, walletConfig: WalletAppConfig)
|
||||
extends FundedTestWallet
|
||||
|
||||
case class FundedDLCWallet(wallet: DLCWallet) extends FundedTestWallet
|
||||
case class FundedDLCWallet(
|
||||
wallet: DLCWallet,
|
||||
walletConfig: WalletAppConfig,
|
||||
dlcConfig: DLCAppConfig)
|
||||
extends FundedTestWallet
|
||||
|
||||
/** This creates a wallet that was two funded accounts Account 0 (default
|
||||
* account) has utxos of 1,2,3 bitcoin in it (6 btc total) Account 1 has a
|
||||
@ -214,8 +207,8 @@ object FundWalletUtil extends FundWalletUtil {
|
||||
nodeApi = nodeApi,
|
||||
chainQueryApi = chainQueryApi
|
||||
)
|
||||
funded <- FundWalletUtil.fundWallet(wallet)
|
||||
} yield FundedWallet(funded.wallet)
|
||||
funded <- FundWalletUtil.fundWallet(wallet, config)
|
||||
} yield FundedWallet(funded.wallet, config)
|
||||
}
|
||||
|
||||
def createFundedDLCWallet(nodeApi: NodeApi, chainQueryApi: ChainQueryApi)(
|
||||
@ -229,9 +222,11 @@ object FundWalletUtil extends FundWalletUtil {
|
||||
nodeApi = nodeApi,
|
||||
chainQueryApi = chainQueryApi
|
||||
)
|
||||
funded <- FundWalletUtil.fundWallet(wallet)
|
||||
funded <- FundWalletUtil.fundWallet(wallet, config.walletConf)
|
||||
} yield {
|
||||
FundedDLCWallet(funded.wallet.asInstanceOf[DLCWallet])
|
||||
FundedDLCWallet(funded.wallet.asInstanceOf[DLCWallet],
|
||||
config.walletConf,
|
||||
config.dlcConf)
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +259,9 @@ object FundWalletUtil extends FundWalletUtil {
|
||||
bitcoind
|
||||
)
|
||||
} yield {
|
||||
FundedDLCWallet(funded.asInstanceOf[DLCWallet])
|
||||
FundedDLCWallet(funded.asInstanceOf[DLCWallet],
|
||||
wallet.walletConfig,
|
||||
wallet.dlcConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.bitcoins.core.wallet.utxo.{
|
||||
}
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedWallet
|
||||
import org.bitcoins.testkit.wallet.{BitcoinSWalletTest, WalletTestUtil}
|
||||
import org.bitcoins.wallet.models.{ScriptPubKeyDAO, SpendingInfoDAO}
|
||||
import org.scalatest.FutureOutcome
|
||||
|
||||
import scala.concurrent.Future
|
||||
@ -40,7 +41,7 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
||||
it must "generate an address for a non default account and then find it" in {
|
||||
(fundedWallet: FundedWallet) =>
|
||||
val wallet = fundedWallet.wallet
|
||||
val account1 = WalletTestUtil.getHdAccount1(wallet.walletConfig)
|
||||
val account1 = WalletTestUtil.getHdAccount1(fundedWallet.walletConfig)
|
||||
val addressF = wallet.accountHandling.getNewAddress(account1)
|
||||
for {
|
||||
address <- addressF
|
||||
@ -116,7 +117,7 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
||||
tx <- wallet.sendFundsHandling.sendToAddress(tempAddress,
|
||||
Bitcoins(1),
|
||||
None)
|
||||
spentDbs <- wallet.spendingInfoDAO.findOutputsBeingSpent(tx)
|
||||
spentDbs <- wallet.utxoHandling.findOutputsBeingSpent(tx)
|
||||
spentAddresses <- wallet.addressHandling.listSpentAddresses()
|
||||
} yield {
|
||||
val diff = spentDbs
|
||||
@ -131,7 +132,7 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
for {
|
||||
unspentDbs <- wallet.spendingInfoDAO.findAllUnspent()
|
||||
unspentDbs <- wallet.utxoHandling.listUtxos()
|
||||
fundedAddresses <- wallet.addressHandling.listFundedAddresses()
|
||||
} yield {
|
||||
val diff = unspentDbs
|
||||
@ -147,9 +148,10 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
||||
it must "get the correct unused addresses" in {
|
||||
(fundedWallet: FundedWallet) =>
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
val spendingInfoDAO =
|
||||
SpendingInfoDAO()(executionContext, fundedWallet.walletConfig)
|
||||
for {
|
||||
addrDbs <- wallet.spendingInfoDAO.findAllSpendingInfos()
|
||||
addrDbs <- spendingInfoDAO.findAllSpendingInfos()
|
||||
fundedAddresses <- wallet.addressHandling.listUnusedAddresses()
|
||||
} yield {
|
||||
val intersect = addrDbs
|
||||
@ -269,11 +271,11 @@ class AddressHandlingTest extends BitcoinSWalletTest {
|
||||
(fundedWallet: FundedWallet) =>
|
||||
val wallet = fundedWallet.wallet
|
||||
val addressF = wallet.getNewAddress()
|
||||
val spendingInfoDAO = wallet.spendingInfoDAO
|
||||
val spkDAO = wallet.scriptPubKeyDAO
|
||||
val spkDAO =
|
||||
ScriptPubKeyDAO()(executionContext, fundedWallet.walletConfig)
|
||||
for {
|
||||
address <- addressF
|
||||
utxos <- spendingInfoDAO.findByScriptPubKey(address.scriptPubKey)
|
||||
utxos <- wallet.utxoHandling.findByScriptPubKey(address.scriptPubKey)
|
||||
spkOpt <- spkDAO.findScriptPubKey(address.scriptPubKey)
|
||||
} yield {
|
||||
assert(utxos.isEmpty)
|
||||
|
@ -43,7 +43,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onNewAddressGenerated(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
@ -68,7 +68,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onTransactionProcessed(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
@ -94,7 +94,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onTransactionProcessed(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
@ -132,7 +132,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onTransactionBroadcast(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
@ -155,7 +155,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onReservedUtxos(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
@ -187,7 +187,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
for {
|
||||
utxos <- wallet.utxoHandling.listUtxos()
|
||||
reserved <- wallet.utxoHandling.markUTXOsAsReserved(Vector(utxos.head))
|
||||
_ = fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
_ = fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
_ <- wallet.utxoHandling.unmarkUTXOsAsReserved(reserved)
|
||||
result <- resultP.future
|
||||
@ -208,7 +208,7 @@ class WalletCallbackTest extends BitcoinSWalletTest {
|
||||
|
||||
val callbacks = WalletCallbacks.onBlockProcessed(callback)
|
||||
|
||||
fundedWallet.wallet.walletConfig.addCallbacks(callbacks)
|
||||
fundedWallet.walletConfig.addCallbacks(callbacks)
|
||||
|
||||
val wallet = fundedWallet.wallet
|
||||
|
||||
|
@ -17,6 +17,8 @@ import org.bitcoins.testkit.wallet.BitcoinSWalletTest
|
||||
import org.bitcoins.testkit.wallet.FundWalletUtil.FundedWallet
|
||||
import org.bitcoins.testkitcore.Implicits.GeneratorOps
|
||||
import org.bitcoins.testkitcore.gen.FeeUnitGen
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import org.bitcoins.wallet.models.{OutgoingTransactionDAO, SpendingInfoDAO}
|
||||
import org.scalatest.{Assertion, FutureOutcome}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
@ -113,9 +115,9 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
}
|
||||
|
||||
def testOpReturnCommitment(
|
||||
wallet: Wallet,
|
||||
wallet: WalletApi,
|
||||
hashMessage: Boolean
|
||||
): Future[Assertion] = {
|
||||
)(implicit walletConfig: WalletAppConfig): Future[Assertion] = {
|
||||
val message = "ben was here"
|
||||
for {
|
||||
tx <- wallet.sendFundsHandling.makeOpReturnCommitment(
|
||||
@ -123,8 +125,8 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
hashMessage = hashMessage,
|
||||
feeRateOpt = None
|
||||
)
|
||||
|
||||
outgoingTxDbOpt <- wallet.outgoingTxDAO.read(tx.txIdBE)
|
||||
outgoingTxDAO = OutgoingTransactionDAO()(executionContext, walletConfig)
|
||||
outgoingTxDbOpt <- outgoingTxDAO.read(tx.txIdBE)
|
||||
} yield {
|
||||
val opReturnOutputOpt = tx.outputs.find(_.value == 0.satoshis)
|
||||
assert(opReturnOutputOpt.isDefined, "Missing output with 0 value")
|
||||
@ -157,12 +159,14 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
}
|
||||
|
||||
it should "correctly make a hashed OP_RETURN commitment" in { fundedWallet =>
|
||||
testOpReturnCommitment(fundedWallet.wallet, hashMessage = true)
|
||||
testOpReturnCommitment(fundedWallet.wallet, hashMessage = true)(
|
||||
fundedWallet.walletConfig)
|
||||
}
|
||||
|
||||
it should "correctly make an unhashed OP_RETURN commitment" in {
|
||||
fundedWallet =>
|
||||
testOpReturnCommitment(fundedWallet.wallet, hashMessage = false)
|
||||
testOpReturnCommitment(fundedWallet.wallet, hashMessage = false)(
|
||||
fundedWallet.walletConfig)
|
||||
}
|
||||
|
||||
it should "fail to make an OP_RETURN commitment that is too long" in {
|
||||
@ -210,8 +214,10 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
|
||||
it should "correctly send from outpoints" in { fundedWallet =>
|
||||
val wallet = fundedWallet.wallet
|
||||
val spendingInfoDAO =
|
||||
SpendingInfoDAO()(executionContext, fundedWallet.walletConfig)
|
||||
for {
|
||||
allOutPoints <- wallet.spendingInfoDAO.findAllOutpoints()
|
||||
allOutPoints <- spendingInfoDAO.findAllOutpoints()
|
||||
// use half of them
|
||||
outPoints = allOutPoints.drop(allOutPoints.size / 2)
|
||||
tx <- wallet.sendFundsHandling.sendFromOutPoints(outPoints,
|
||||
@ -346,9 +352,10 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
|
||||
newFeeRate = SatoshisPerByte(feeRate.currencyUnit + Satoshis(50))
|
||||
bumpedTx <- wallet.sendFundsHandling.bumpFeeRBF(tx.txIdBE, newFeeRate)
|
||||
|
||||
txDb1Opt <- wallet.outgoingTxDAO.findByTxId(tx.txIdBE)
|
||||
txDb2Opt <- wallet.outgoingTxDAO.findByTxId(bumpedTx.txIdBE)
|
||||
outgoingTxDAO = OutgoingTransactionDAO()(executionContext,
|
||||
fundedWallet.walletConfig)
|
||||
txDb1Opt <- outgoingTxDAO.findByTxId(tx.txIdBE)
|
||||
txDb2Opt <- outgoingTxDAO.findByTxId(bumpedTx.txIdBE)
|
||||
|
||||
secondBal <- wallet.getBalance()
|
||||
} yield {
|
||||
@ -422,8 +429,9 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
None)
|
||||
bumpRate <- wallet.feeRateApi.getFeeRate()
|
||||
child <- wallet.sendFundsHandling.bumpFeeCPFP(parent.txIdBE, bumpRate)
|
||||
|
||||
received <- wallet.spendingInfoDAO.findTx(child).map(_.nonEmpty)
|
||||
spendingInfoDAO = SpendingInfoDAO()(executionContext,
|
||||
fundedWallet.walletConfig)
|
||||
received <- spendingInfoDAO.findTx(child).map(_.nonEmpty)
|
||||
} yield {
|
||||
// Verify we are only sending to ourself
|
||||
assert(child.outputs.size == 1)
|
||||
@ -492,7 +500,9 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
DoubleSha256DigestBE.empty
|
||||
) // dummy spending txid
|
||||
.copyWithState(TxoState.PendingConfirmationsSpent)
|
||||
_ <- wallet.spendingInfoDAO.update(spent)
|
||||
spendingInfoDAO = SpendingInfoDAO()(executionContext,
|
||||
fundedWallet.walletConfig)
|
||||
_ <- spendingInfoDAO.update(spent)
|
||||
test <- recoverToSucceededIf[IllegalArgumentException](
|
||||
wallet.sendFundsHandling.sendFromOutPoints(
|
||||
allUtxos.map(_.outPoint),
|
||||
@ -505,7 +515,7 @@ class WalletSendingTest extends BitcoinSWalletTest {
|
||||
}
|
||||
|
||||
def testSendWithAlgo(
|
||||
wallet: Wallet,
|
||||
wallet: WalletApi,
|
||||
algo: CoinSelectionAlgo
|
||||
): Future[Assertion] = {
|
||||
for {
|
||||
|
@ -33,13 +33,17 @@ import java.util.concurrent.TimeUnit
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
abstract class Wallet extends NeutrinoHDWalletApi with WalletLogger {
|
||||
case class Wallet(
|
||||
override val nodeApi: NodeApi,
|
||||
override val chainQueryApi: ChainQueryApi
|
||||
)(implicit
|
||||
val walletConfig: WalletAppConfig
|
||||
) extends NeutrinoHDWalletApi
|
||||
with WalletLogger {
|
||||
def keyManager: BIP39KeyManager = {
|
||||
walletConfig.kmConf.toBip39KeyManager
|
||||
}
|
||||
def feeRateApi: FeeRateApi = walletConfig.feeRateApi
|
||||
implicit val walletConfig: WalletAppConfig
|
||||
|
||||
implicit val system: ActorSystem = walletConfig.system
|
||||
|
||||
implicit val ec: ExecutionContext = system.dispatcher
|
||||
@ -50,36 +54,28 @@ abstract class Wallet extends NeutrinoHDWalletApi with WalletLogger {
|
||||
|
||||
val networkParameters: BitcoinNetwork = walletConfig.network
|
||||
|
||||
private[bitcoins] val addressDAO: AddressDAO = AddressDAO()
|
||||
private[bitcoins] val accountDAO: AccountDAO = AccountDAO()
|
||||
private[bitcoins] val spendingInfoDAO: SpendingInfoDAO = SpendingInfoDAO()
|
||||
private[bitcoins] val transactionDAO: TransactionDAO = TransactionDAO()
|
||||
private[bitcoins] val scriptPubKeyDAO: ScriptPubKeyDAO = ScriptPubKeyDAO()
|
||||
private[bitcoins] val walletDAOs: WalletDAOs =
|
||||
WalletDAOs.fromWalletConfig(walletConfig)
|
||||
|
||||
private[bitcoins] val addressDAO: AddressDAO = walletDAOs.addressDAO
|
||||
private[bitcoins] val accountDAO: AccountDAO = walletDAOs.accountDAO
|
||||
private[bitcoins] val spendingInfoDAO: SpendingInfoDAO = walletDAOs.utxoDAO
|
||||
private[bitcoins] val transactionDAO: TransactionDAO =
|
||||
walletDAOs.transactionDAO
|
||||
private[bitcoins] val scriptPubKeyDAO: ScriptPubKeyDAO =
|
||||
walletDAOs.scriptPubKeyDAO
|
||||
|
||||
private[bitcoins] val incomingTxDAO: IncomingTransactionDAO =
|
||||
IncomingTransactionDAO()
|
||||
walletDAOs.incomingTxDAO
|
||||
|
||||
private[bitcoins] val outgoingTxDAO: OutgoingTransactionDAO =
|
||||
OutgoingTransactionDAO()
|
||||
private[bitcoins] val addressTagDAO: AddressTagDAO = AddressTagDAO()
|
||||
walletDAOs.outgoingTxDAO
|
||||
private[bitcoins] val addressTagDAO: AddressTagDAO = walletDAOs.addressTagDAO
|
||||
|
||||
private[bitcoins] val stateDescriptorDAO: WalletStateDescriptorDAO =
|
||||
WalletStateDescriptorDAO()
|
||||
|
||||
private def walletDAOs: WalletDAOs = WalletDAOs(accountDAO,
|
||||
addressDAO,
|
||||
addressTagDAO,
|
||||
spendingInfoDAO,
|
||||
transactionDAO,
|
||||
incomingTxDAO,
|
||||
outgoingTxDAO,
|
||||
scriptPubKeyDAO,
|
||||
stateDescriptorDAO)
|
||||
|
||||
walletDAOs.stateDescriptorDAO
|
||||
protected lazy val safeDatabase: SafeDatabase = spendingInfoDAO.safeDatabase
|
||||
|
||||
val nodeApi: NodeApi
|
||||
val chainQueryApi: ChainQueryApi
|
||||
val creationTime: Instant = keyManager.creationTime
|
||||
|
||||
def utxoHandling: UtxoHandling =
|
||||
@ -310,23 +306,8 @@ abstract class Wallet extends NeutrinoHDWalletApi with WalletLogger {
|
||||
}
|
||||
}
|
||||
|
||||
// todo: create multiple wallets, need to maintain multiple databases
|
||||
object Wallet extends WalletLogger {
|
||||
|
||||
private case class WalletImpl(
|
||||
nodeApi: NodeApi,
|
||||
chainQueryApi: ChainQueryApi
|
||||
)(implicit
|
||||
val walletConfig: WalletAppConfig
|
||||
) extends Wallet
|
||||
|
||||
def apply(
|
||||
nodeApi: NodeApi,
|
||||
chainQueryApi: ChainQueryApi
|
||||
)(implicit config: WalletAppConfig): Wallet = {
|
||||
WalletImpl(nodeApi, chainQueryApi)
|
||||
}
|
||||
|
||||
/** Creates the master xpub for the key manager in the database
|
||||
* @throws RuntimeException
|
||||
* if a different master xpub key exists in the database
|
||||
|
@ -2,12 +2,11 @@ package org.bitcoins.wallet
|
||||
|
||||
import org.bitcoins.commons.util.BitcoinSLogger
|
||||
import org.bitcoins.core.api.chain.ChainQueryApi
|
||||
import org.bitcoins.core.api.dlc.wallet.DLCNeutrinoHDWalletApi
|
||||
import org.bitcoins.core.api.dlc.wallet.db.{
|
||||
DLCContactDb,
|
||||
DLCDb,
|
||||
IncomingDLCOfferDb
|
||||
import org.bitcoins.core.api.dlc.wallet.{
|
||||
DLCNeutrinoHDWalletApi,
|
||||
IncomingDLCOfferHandlingApi
|
||||
}
|
||||
import org.bitcoins.core.api.dlc.wallet.db.DLCDb
|
||||
import org.bitcoins.core.api.feeprovider.FeeRateApi
|
||||
import org.bitcoins.core.api.node.NodeApi
|
||||
import org.bitcoins.core.api.wallet.*
|
||||
@ -38,7 +37,7 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
|
||||
@volatile private var walletOpt: Option[DLCNeutrinoHDWalletApi] =
|
||||
initWalletOpt
|
||||
|
||||
private def wallet: DLCNeutrinoHDWalletApi = synchronized {
|
||||
override protected def walletApi: DLCNeutrinoHDWalletApi = synchronized {
|
||||
walletOpt match {
|
||||
case Some(wallet) => wallet
|
||||
case None =>
|
||||
@ -46,22 +45,25 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
|
||||
}
|
||||
}
|
||||
|
||||
override def accountHandling: AccountHandlingApi = wallet.accountHandling
|
||||
override def incomingOfferHandling: IncomingDLCOfferHandlingApi =
|
||||
walletApi.incomingOfferHandling
|
||||
|
||||
override def rescanHandling: RescanHandlingApi = wallet.rescanHandling
|
||||
override def accountHandling: AccountHandlingApi = walletApi.accountHandling
|
||||
|
||||
override def rescanHandling: RescanHandlingApi = walletApi.rescanHandling
|
||||
|
||||
override def fundTxHandling: FundTransactionHandlingApi =
|
||||
wallet.fundTxHandling
|
||||
walletApi.fundTxHandling
|
||||
|
||||
override def utxoHandling: UtxoHandlingApi = wallet.utxoHandling
|
||||
override def utxoHandling: UtxoHandlingApi = walletApi.utxoHandling
|
||||
|
||||
override def addressHandling: AddressHandlingApi = wallet.addressHandling
|
||||
override def addressHandling: AddressHandlingApi = walletApi.addressHandling
|
||||
|
||||
override def transactionProcessing: TransactionProcessingApi =
|
||||
wallet.transactionProcessing
|
||||
walletApi.transactionProcessing
|
||||
|
||||
override def sendFundsHandling: SendFundsHandlingApi =
|
||||
wallet.sendFundsHandling
|
||||
walletApi.sendFundsHandling
|
||||
def isInitialized: Boolean = synchronized {
|
||||
walletOpt.isDefined
|
||||
}
|
||||
@ -76,7 +78,7 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
|
||||
|
||||
private def delegate[T]
|
||||
: (DLCNeutrinoHDWalletApi => Future[T]) => Future[T] = {
|
||||
Future(wallet).flatMap[T](_)
|
||||
Future(walletApi).flatMap[T](_)
|
||||
}
|
||||
|
||||
override def getNewAddress(): Future[BitcoinAddress] = delegate(
|
||||
@ -93,10 +95,10 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
|
||||
|
||||
override def isRescanning(): Future[Boolean] = delegate(_.isRescanning())
|
||||
|
||||
override lazy val nodeApi: NodeApi = wallet.nodeApi
|
||||
override lazy val chainQueryApi: ChainQueryApi = wallet.chainQueryApi
|
||||
override lazy val feeRateApi: FeeRateApi = wallet.feeRateApi
|
||||
override lazy val creationTime: Instant = wallet.creationTime
|
||||
override lazy val nodeApi: NodeApi = walletApi.nodeApi
|
||||
override lazy val chainQueryApi: ChainQueryApi = walletApi.chainQueryApi
|
||||
override lazy val feeRateApi: FeeRateApi = walletApi.feeRateApi
|
||||
override lazy val creationTime: Instant = walletApi.creationTime
|
||||
|
||||
override def getConfirmedBalance(): Future[CurrencyUnit] = delegate(
|
||||
_.getConfirmedBalance()
|
||||
@ -231,48 +233,6 @@ class WalletHolder(initWalletOpt: Option[DLCNeutrinoHDWalletApi])(implicit
|
||||
_.getWalletAccounting()
|
||||
)
|
||||
|
||||
override def registerIncomingDLCOffer(
|
||||
offerTLV: DLCOfferTLV,
|
||||
peer: Option[String],
|
||||
message: Option[String]
|
||||
): Future[Sha256Digest] = delegate(
|
||||
_.registerIncomingDLCOffer(offerTLV, peer, message)
|
||||
)
|
||||
|
||||
override def listIncomingDLCOffers(): Future[Vector[IncomingDLCOfferDb]] =
|
||||
delegate(_.listIncomingDLCOffers())
|
||||
|
||||
override def rejectIncomingDLCOffer(offerHash: Sha256Digest): Future[Unit] =
|
||||
delegate(_.rejectIncomingDLCOffer(offerHash))
|
||||
|
||||
override def findIncomingDLCOffer(
|
||||
offerHash: Sha256Digest
|
||||
): Future[Option[IncomingDLCOfferDb]] = delegate(
|
||||
_.findIncomingDLCOffer(offerHash)
|
||||
)
|
||||
|
||||
override def listDLCContacts(): Future[Vector[DLCContactDb]] = delegate(
|
||||
_.listDLCContacts()
|
||||
)
|
||||
|
||||
override def addDLCContact(contact: DLCContactDb): Future[Unit] = delegate(
|
||||
_.addDLCContact(contact)
|
||||
)
|
||||
|
||||
override def removeDLCContact(address: InetSocketAddress): Future[Unit] =
|
||||
delegate(_.removeDLCContact(address))
|
||||
|
||||
override def findDLCContacts(alias: String): Future[Vector[DLCContactDb]] =
|
||||
delegate(_.findDLCContacts(alias))
|
||||
|
||||
override def addDLCContactMapping(
|
||||
dlcId: Sha256Digest,
|
||||
contactId: InetSocketAddress
|
||||
): Future[Unit] = delegate(_.addDLCContactMapping(dlcId, contactId))
|
||||
|
||||
override def removeDLCContactMapping(dlcId: Sha256Digest): Future[Unit] =
|
||||
delegate(_.removeDLCContactMapping(dlcId))
|
||||
|
||||
override def listDLCsByContact(
|
||||
address: InetSocketAddress
|
||||
): Future[Vector[DLCStatus]] = delegate(_.listDLCsByContact(address))
|
||||
|
@ -345,7 +345,7 @@ case class WalletAppConfig(
|
||||
def createHDWallet(
|
||||
nodeApi: NodeApi,
|
||||
chainQueryApi: ChainQueryApi
|
||||
)(implicit system: ActorSystem): Future[Wallet] = {
|
||||
): Future[Wallet] = {
|
||||
WalletAppConfig.createHDWallet(
|
||||
nodeApi = nodeApi,
|
||||
chainQueryApi = chainQueryApi
|
||||
|
@ -50,22 +50,6 @@ case class AddressHandling(
|
||||
private val scriptPubKeyDAO: ScriptPubKeyDAO = walletDAOs.scriptPubKeyDAO
|
||||
private val networkParameters: NetworkParameters = walletConfig.network
|
||||
|
||||
def contains(
|
||||
address: BitcoinAddress,
|
||||
accountOpt: Option[(AccountHandlingApi, HDAccount)]
|
||||
): Future[Boolean] = {
|
||||
val possibleAddressesF = accountOpt match {
|
||||
case Some((ah, account)) =>
|
||||
ah.listAddresses(account)
|
||||
case None =>
|
||||
listAddresses()
|
||||
}
|
||||
|
||||
possibleAddressesF.map { possibleAddresses =>
|
||||
possibleAddresses.exists(_.address == address)
|
||||
}
|
||||
}
|
||||
|
||||
override def listAddresses(): Future[Vector[AddressDb]] =
|
||||
addressDAO.findAllAddresses()
|
||||
|
||||
@ -241,7 +225,7 @@ case class AddressHandling(
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
def getUnusedAddress: Future[BitcoinAddress] = {
|
||||
override def getUnusedAddress: Future[BitcoinAddress] = {
|
||||
for {
|
||||
account <- accountHandling.getDefaultAccount()
|
||||
addresses <- addressDAO.getUnusedAddresses(account.hdAccount)
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.bitcoins.wallet.models
|
||||
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
|
||||
case class WalletDAOs(
|
||||
accountDAO: AccountDAO,
|
||||
addressDAO: AddressDAO,
|
||||
@ -24,3 +26,36 @@ case class WalletDAOs(
|
||||
stateDescriptorDAO
|
||||
)
|
||||
}
|
||||
|
||||
object WalletDAOs {
|
||||
def fromWalletConfig(walletConfig: WalletAppConfig): WalletDAOs = {
|
||||
val addressDAO: AddressDAO = AddressDAO()(walletConfig.ec, walletConfig)
|
||||
val accountDAO: AccountDAO = AccountDAO()(walletConfig.ec, walletConfig)
|
||||
val spendingInfoDAO: SpendingInfoDAO =
|
||||
SpendingInfoDAO()(walletConfig.ec, walletConfig)
|
||||
val transactionDAO: TransactionDAO =
|
||||
TransactionDAO()(walletConfig.ec, walletConfig)
|
||||
val scriptPubKeyDAO: ScriptPubKeyDAO =
|
||||
ScriptPubKeyDAO()(walletConfig.ec, walletConfig)
|
||||
|
||||
val incomingTxDAO: IncomingTransactionDAO =
|
||||
IncomingTransactionDAO()(walletConfig.ec, walletConfig)
|
||||
|
||||
val outgoingTxDAO: OutgoingTransactionDAO =
|
||||
OutgoingTransactionDAO()(walletConfig.ec, walletConfig)
|
||||
val addressTagDAO: AddressTagDAO =
|
||||
AddressTagDAO()(walletConfig.ec, walletConfig)
|
||||
|
||||
val stateDescriptorDAO: WalletStateDescriptorDAO =
|
||||
WalletStateDescriptorDAO()(walletConfig.ec, walletConfig)
|
||||
WalletDAOs(accountDAO,
|
||||
addressDAO,
|
||||
addressTagDAO,
|
||||
spendingInfoDAO,
|
||||
transactionDAO,
|
||||
incomingTxDAO,
|
||||
outgoingTxDAO,
|
||||
scriptPubKeyDAO,
|
||||
stateDescriptorDAO)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user