mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 10:39:19 +01:00
Added bitgo fee provider (#237)
* added bitgo fee provider and set it as default, keeping `earn.com` as fallback.
This commit is contained in:
parent
8b151eb5c0
commit
40b18aed8b
@ -107,8 +107,8 @@ class Setup(datadir: File, overrideDefaults: Config = ConfigFactory.empty(), act
|
||||
logger.info(s"initial feeratesPerByte=${Globals.feeratesPerByte.get()}")
|
||||
val feeProvider = (chain, bitcoin) match {
|
||||
case ("regtest", _) => new ConstantFeeProvider(defaultFeerates)
|
||||
case (_, Bitcoind(client)) => new FallbackFeeProvider(new EarnDotComFeeProvider() :: new BitcoinCoreFeeProvider(client.rpcClient, defaultFeerates) :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
case _ => new FallbackFeeProvider(new EarnDotComFeeProvider() :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
case (_, Bitcoind(client)) => new FallbackFeeProvider(new BitgoFeeProvider() :: new EarnDotComFeeProvider() :: new BitcoinCoreFeeProvider(client.rpcClient, defaultFeerates) :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
case _ => new FallbackFeeProvider(new BitgoFeeProvider() :: new EarnDotComFeeProvider() :: new ConstantFeeProvider(defaultFeerates) :: Nil) // order matters!
|
||||
}
|
||||
system.scheduler.schedule(0 seconds, 10 minutes)(feeProvider.getFeerates.map {
|
||||
case feerates: FeeratesPerByte =>
|
||||
|
@ -0,0 +1,58 @@
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.http.scaladsl.Http
|
||||
import akka.http.scaladsl.model._
|
||||
import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||
import akka.stream.ActorMaterializer
|
||||
import de.heikoseeberger.akkahttpjson4s.Json4sSupport._
|
||||
import org.json4s.JsonAST.{JArray, JInt, JValue}
|
||||
import org.json4s.{DefaultFormats, jackson}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class BitgoFeeProvider(implicit system: ActorSystem, ec: ExecutionContext) extends FeeProvider {
|
||||
|
||||
import BitgoFeeProvider._
|
||||
|
||||
implicit val materializer = ActorMaterializer()
|
||||
val httpClient = Http(system)
|
||||
implicit val serialization = jackson.Serialization
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
override def getFeerates: Future[FeeratesPerByte] =
|
||||
for {
|
||||
httpRes <- httpClient.singleRequest(HttpRequest(uri = Uri("https://www.bitgo.com/api/v1/tx/fee"), method = HttpMethods.GET))
|
||||
json <- Unmarshal(httpRes).to[JValue]
|
||||
feeRanges = parseFeeRanges(json)
|
||||
} yield extractFeerates(feeRanges)
|
||||
}
|
||||
|
||||
object BitgoFeeProvider {
|
||||
|
||||
case class BlockTarget(block: Int, fee: Long)
|
||||
|
||||
def parseFeeRanges(json: JValue): Seq[BlockTarget] = {
|
||||
val blockTargets = json \ "feeByBlockTarget"
|
||||
blockTargets.foldField(Seq.empty[BlockTarget]) {
|
||||
case (list, (strBlockTarget, JInt(feePerKb))) => list :+ BlockTarget(strBlockTarget.toInt, feePerKb.longValue() / 1024)
|
||||
}
|
||||
}
|
||||
|
||||
def extractFeerate(feeRanges: Seq[BlockTarget], maxBlockDelay: Int): Long = {
|
||||
// first we keep only fee ranges with a max block delay below the limit
|
||||
val belowLimit = feeRanges.filter(_.block <= maxBlockDelay)
|
||||
// out of all the remaining fee ranges, we select the one with the minimum higher bound
|
||||
belowLimit.map(_.fee).min
|
||||
}
|
||||
|
||||
def extractFeerates(feeRanges: Seq[BlockTarget]): FeeratesPerByte =
|
||||
FeeratesPerByte(
|
||||
block_1 = extractFeerate(feeRanges, 1),
|
||||
blocks_2 = extractFeerate(feeRanges, 2),
|
||||
blocks_6 = extractFeerate(feeRanges, 6),
|
||||
blocks_12 = extractFeerate(feeRanges, 12),
|
||||
blocks_36 = extractFeerate(feeRanges, 36),
|
||||
blocks_72 = extractFeerate(feeRanges, 72))
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package fr.acinq.eclair.blockchain.fee
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.util.Timeout
|
||||
import org.json4s.DefaultFormats
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
||||
import scala.concurrent.Await
|
||||
|
||||
/**
|
||||
* Created by PM on 27/01/2017.
|
||||
*/
|
||||
@RunWith(classOf[JUnitRunner])
|
||||
class BitgoFeeProviderSpec extends FunSuite {
|
||||
|
||||
import BitgoFeeProvider._
|
||||
import org.json4s.jackson.JsonMethods.parse
|
||||
|
||||
implicit val formats = DefaultFormats
|
||||
|
||||
val sample_response =
|
||||
"""
|
||||
{"feePerKb":136797,"cpfpFeePerKb":136797,"numBlocks":2,"confidence":80,"multiplier":1,"feeByBlockTarget":{"1":149453,"2":136797,"5":122390,"6":105566,"8":100149,"9":96254,"10":122151,"13":116855,"15":110860,"17":87402,"27":82635,"33":71098,"42":105782,"49":68182,"73":59207,"97":17336,"121":16577,"193":13545,"313":12268,"529":11122,"553":9139,"577":5395,"793":5070}}
|
||||
"""
|
||||
|
||||
test("parse test") {
|
||||
val json = parse(sample_response)
|
||||
val feeRanges = parseFeeRanges(json)
|
||||
assert(feeRanges.size === 23)
|
||||
}
|
||||
|
||||
test("extract fee for a particular block delay") {
|
||||
val json = parse(sample_response)
|
||||
val feeRanges = parseFeeRanges(json)
|
||||
val fee = extractFeerate(feeRanges, 6)
|
||||
assert(fee === 103)
|
||||
}
|
||||
|
||||
test("extract all fees") {
|
||||
val json = parse(sample_response)
|
||||
val feeRanges = parseFeeRanges(json)
|
||||
val feerates = extractFeerates(feeRanges)
|
||||
val ref = FeeratesPerByte(
|
||||
block_1 = 145,
|
||||
blocks_2 = 133,
|
||||
blocks_6 = 103,
|
||||
blocks_12 = 93,
|
||||
blocks_36 = 69,
|
||||
blocks_72 = 66)
|
||||
assert(feerates === ref)
|
||||
}
|
||||
|
||||
test("make sure API hasn't changed") {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
implicit val system = ActorSystem()
|
||||
implicit val timeout = Timeout(30 seconds)
|
||||
val provider = new BitgoFeeProvider()
|
||||
Await.result(provider.getFeerates, 10 seconds)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user