mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-02-23 22:56:52 +01:00
Bump Fee Cli commands (#2415)
* Bump Fee Cli commands * Clarify fee rate, add to docs
This commit is contained in:
parent
1e394737c6
commit
4da53d5569
5 changed files with 165 additions and 1 deletions
|
@ -718,6 +718,56 @@ object ConsoleCli {
|
|||
case other => other
|
||||
}))
|
||||
),
|
||||
cmd("bumpfeecpfp")
|
||||
.action((_, conf) =>
|
||||
conf.copy(command = BumpFeeCPFP(DoubleSha256DigestBE.empty,
|
||||
SatoshisPerVirtualByte.zero)))
|
||||
.text("Bump the fee of the given transaction id with a child tx using the given fee rate")
|
||||
.children(
|
||||
arg[DoubleSha256DigestBE]("txid")
|
||||
.text("Id of transaction to bump fee")
|
||||
.required()
|
||||
.action((txid, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
case cpfp: BumpFeeCPFP =>
|
||||
cpfp.copy(txId = txid)
|
||||
case other => other
|
||||
})),
|
||||
arg[SatoshisPerVirtualByte]("feerate")
|
||||
.text("Fee rate in sats per virtual byte of the child transaction")
|
||||
.required()
|
||||
.action((feeRate, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
case cpfp: BumpFeeCPFP =>
|
||||
cpfp.copy(feeRate = feeRate)
|
||||
case other => other
|
||||
}))
|
||||
),
|
||||
cmd("bumpfeerbf")
|
||||
.action((_, conf) =>
|
||||
conf.copy(command = BumpFeeRBF(DoubleSha256DigestBE.empty,
|
||||
SatoshisPerVirtualByte.zero)))
|
||||
.text("Replace given transaction with one with the new fee rate")
|
||||
.children(
|
||||
arg[DoubleSha256DigestBE]("txid")
|
||||
.text("Id of transaction to bump fee")
|
||||
.required()
|
||||
.action((txid, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
case rbf: BumpFeeRBF =>
|
||||
rbf.copy(txId = txid)
|
||||
case other => other
|
||||
})),
|
||||
arg[SatoshisPerVirtualByte]("feerate")
|
||||
.text("New fee rate in sats per virtual byte")
|
||||
.required()
|
||||
.action((feeRate, conf) =>
|
||||
conf.copy(command = conf.command match {
|
||||
case rbf: BumpFeeRBF =>
|
||||
rbf.copy(feeRate = feeRate)
|
||||
case other => other
|
||||
}))
|
||||
),
|
||||
cmd("gettransaction")
|
||||
.action((_, conf) =>
|
||||
conf.copy(command = GetTransaction(DoubleSha256DigestBE.empty)))
|
||||
|
@ -1418,6 +1468,10 @@ object ConsoleCli {
|
|||
up.writeJs(bitcoins),
|
||||
up.writeJs(feeRateOpt),
|
||||
up.writeJs(algo)))
|
||||
case BumpFeeCPFP(txId, feeRate) =>
|
||||
RequestParam("bumpfeecpfp", Seq(up.writeJs(txId), up.writeJs(feeRate)))
|
||||
case BumpFeeRBF(txId, feeRate) =>
|
||||
RequestParam("bumpfeerbf", Seq(up.writeJs(txId), up.writeJs(feeRate)))
|
||||
case OpReturnCommit(message, hashMessage, satoshisPerVirtualByte) =>
|
||||
RequestParam("opreturncommit",
|
||||
Seq(up.writeJs(message),
|
||||
|
@ -1715,6 +1769,16 @@ object CliCommand {
|
|||
feeRateOpt: Option[SatoshisPerVirtualByte])
|
||||
extends CliCommand
|
||||
|
||||
case class BumpFeeCPFP(
|
||||
txId: DoubleSha256DigestBE,
|
||||
feeRate: SatoshisPerVirtualByte)
|
||||
extends CliCommand
|
||||
|
||||
case class BumpFeeRBF(
|
||||
txId: DoubleSha256DigestBE,
|
||||
feeRate: SatoshisPerVirtualByte)
|
||||
extends CliCommand
|
||||
|
||||
case class SignPSBT(psbt: PSBT) extends CliCommand
|
||||
|
||||
case class LockUnspent(
|
||||
|
|
|
@ -1032,6 +1032,50 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
|
|||
}
|
||||
}
|
||||
|
||||
"bump fee with rbf" in {
|
||||
(mockWalletApi
|
||||
.bumpFeeRBF(_: DoubleSha256DigestBE, _: FeeUnit))
|
||||
.expects(DoubleSha256DigestBE.empty, SatoshisPerVirtualByte.one)
|
||||
.returning(Future.successful(EmptyTransaction))
|
||||
|
||||
(mockWalletApi.broadcastTransaction _)
|
||||
.expects(EmptyTransaction)
|
||||
.returning(FutureUtil.unit)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
val route = walletRoutes.handleCommand(
|
||||
ServerCommand("bumpfeerbf",
|
||||
Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1))))
|
||||
|
||||
Post() ~> route ~> check {
|
||||
assert(contentType == `application/json`)
|
||||
assert(
|
||||
responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""")
|
||||
}
|
||||
}
|
||||
|
||||
"bump fee with CPFP" in {
|
||||
(mockWalletApi
|
||||
.bumpFeeCPFP(_: DoubleSha256DigestBE, _: FeeUnit))
|
||||
.expects(DoubleSha256DigestBE.empty, SatoshisPerVirtualByte.one)
|
||||
.returning(Future.successful(EmptyTransaction))
|
||||
|
||||
(mockWalletApi.broadcastTransaction _)
|
||||
.expects(EmptyTransaction)
|
||||
.returning(FutureUtil.unit)
|
||||
.anyNumberOfTimes()
|
||||
|
||||
val route = walletRoutes.handleCommand(
|
||||
ServerCommand("bumpfeecpfp",
|
||||
Arr(Str(DoubleSha256DigestBE.empty.hex), Num(1))))
|
||||
|
||||
Post() ~> route ~> check {
|
||||
assert(contentType == `application/json`)
|
||||
assert(
|
||||
responseAs[String] == """{"result":"0000000000000000000000000000000000000000000000000000000000000000","error":null}""")
|
||||
}
|
||||
}
|
||||
|
||||
"return the peer list" in {
|
||||
val route =
|
||||
nodeRoutes.handleCommand(ServerCommand("getpeers", Arr()))
|
||||
|
|
|
@ -689,6 +689,30 @@ object OpReturnCommit extends ServerJsonModels {
|
|||
}
|
||||
}
|
||||
|
||||
case class BumpFee(txId: DoubleSha256DigestBE, feeRate: SatoshisPerVirtualByte)
|
||||
|
||||
object BumpFee extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[BumpFee] = {
|
||||
jsArr.arr.toList match {
|
||||
case txIdJs :: feeRateJs :: Nil =>
|
||||
Try {
|
||||
val txId = DoubleSha256DigestBE(txIdJs.str)
|
||||
val feeRate = SatoshisPerVirtualByte(Satoshis(feeRateJs.num.toLong))
|
||||
BumpFee(txId, feeRate)
|
||||
}
|
||||
case Nil =>
|
||||
Failure(
|
||||
new IllegalArgumentException("Missing txId and fee rate arguments"))
|
||||
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length}. Expected: 2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Oracle Models
|
||||
|
||||
case class CreateEvent(
|
||||
|
|
|
@ -321,6 +321,32 @@ case class WalletRoutes(wallet: AnyHDWalletApi)(implicit
|
|||
}
|
||||
}
|
||||
|
||||
case ServerCommand("bumpfeerbf", arr) =>
|
||||
BumpFee.fromJsArr(arr) match {
|
||||
case Failure(exception) =>
|
||||
reject(ValidationRejection("failure", Some(exception)))
|
||||
case Success(BumpFee(txId, feeRate)) =>
|
||||
complete {
|
||||
for {
|
||||
tx <- wallet.bumpFeeRBF(txId, feeRate)
|
||||
_ <- wallet.broadcastTransaction(tx)
|
||||
} yield Server.httpSuccess(tx.txIdBE)
|
||||
}
|
||||
}
|
||||
|
||||
case ServerCommand("bumpfeecpfp", arr) =>
|
||||
BumpFee.fromJsArr(arr) match {
|
||||
case Failure(exception) =>
|
||||
reject(ValidationRejection("failure", Some(exception)))
|
||||
case Success(BumpFee(txId, feeRate)) =>
|
||||
complete {
|
||||
for {
|
||||
tx <- wallet.bumpFeeCPFP(txId, feeRate)
|
||||
_ <- wallet.broadcastTransaction(tx)
|
||||
} yield Server.httpSuccess(tx.txIdBE)
|
||||
}
|
||||
}
|
||||
|
||||
case ServerCommand("rescan", arr) =>
|
||||
Rescan.fromJsArr(arr) match {
|
||||
case Failure(exception) =>
|
||||
|
|
|
@ -183,7 +183,13 @@ For more information on how to use our built in `cli` to interact with the serve
|
|||
- `opreturncommit` `message` `[options]` - Creates OP_RETURN commitment transaction
|
||||
- `message` - message to put into OP_RETURN commitment
|
||||
- `--hashMessage` - should the message be hashed before commitment
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `--feerate <value>` - Fee rate in sats per virtual byte
|
||||
- `bumpfeecpfp` `txid` `feerate` - Bump the fee of the given transaction id with a child tx using the given fee rate
|
||||
- `txid` - Id of transaction to bump fee
|
||||
- `feerate` - Fee rate in sats per virtual byte of the child transaction
|
||||
- `bumpfeerbf` `txid` `feerate` - Replace given transaction with one with the new fee rate
|
||||
- `txid` - Id of transaction to bump fee
|
||||
- `feerate` - New fee rate in sats per virtual byte
|
||||
- `gettransaction` `txid` - Get detailed information about in-wallet transaction <txid>
|
||||
- `txid` - The transaction id
|
||||
- `lockunspent` `unlock` `transactions` - Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.
|
||||
|
|
Loading…
Add table
Reference in a new issue