diff --git a/server/app/com/xsn/explorer/models/TransactionDetails.scala b/server/app/com/xsn/explorer/models/TransactionDetails.scala index fdaae48..345fc4a 100644 --- a/server/app/com/xsn/explorer/models/TransactionDetails.scala +++ b/server/app/com/xsn/explorer/models/TransactionDetails.scala @@ -10,11 +10,11 @@ case class TransactionDetails( time: Long, blocktime: Long, confirmations: Confirmations, - input: Option[TransactionValue], + input: List[TransactionValue], output: List[TransactionValue]) { lazy val fee: BigDecimal = { - val vin = input.map(_.value).getOrElse(BigDecimal(0)) + val vin = input.map(_.value).sum val vout = output.map(_.value).sum (vin - vout) max 0 } @@ -22,13 +22,7 @@ case class TransactionDetails( object TransactionDetails { - def from(tx: Transaction, previous: Transaction): TransactionDetails = { - val input = tx.vin.flatMap { vin => - val voutMaybe = previous.vout.find(_.n == vin.voutIndex) - - voutMaybe.flatMap(TransactionValue.from) - } - + def from(tx: Transaction, input: List[TransactionValue]): TransactionDetails = { TransactionDetails .from(tx) .copy(input = input) @@ -37,7 +31,7 @@ object TransactionDetails { def from(tx: Transaction): TransactionDetails = { val output = tx.vout.flatMap(TransactionValue.from) - TransactionDetails(tx.id, tx.size, tx.blockhash, tx.time, tx.blocktime, tx.confirmations, None, output) + TransactionDetails(tx.id, tx.size, tx.blockhash, tx.time, tx.blocktime, tx.confirmations, List.empty, output) } implicit val writes: Writes[TransactionDetails] = Json.writes[TransactionDetails] diff --git a/server/app/com/xsn/explorer/models/rpc/Transaction.scala b/server/app/com/xsn/explorer/models/rpc/Transaction.scala index ae1e39f..b7bf469 100644 --- a/server/app/com/xsn/explorer/models/rpc/Transaction.scala +++ b/server/app/com/xsn/explorer/models/rpc/Transaction.scala @@ -11,7 +11,7 @@ case class Transaction( time: Long, blocktime: Long, confirmations: Confirmations, - vin: Option[TransactionVIN], + vin: List[TransactionVIN], vout: List[TransactionVOUT], ) @@ -28,7 +28,6 @@ object Transaction { (__ \ 'vin).readNullable[List[JsValue]] .map(_ getOrElse List.empty) .map { list => list.flatMap(_.asOpt[TransactionVIN]) } - .map(_.headOption) builder.apply { (id, size, blockHash, time, blockTime, confirmations, vout, vin) => Transaction(id, size, blockHash, time, blockTime, confirmations, vin, vout) diff --git a/server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala b/server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala index 5ba919d..b2b1625 100644 --- a/server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala +++ b/server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala @@ -1,18 +1,25 @@ package com.xsn.explorer.models.rpc -import com.xsn.explorer.models.TransactionId +import com.xsn.explorer.models.{Address, TransactionId} import play.api.libs.functional.syntax._ import play.api.libs.json.{Reads, __} -case class TransactionVIN(txid: TransactionId, voutIndex: Int) +case class TransactionVIN( + txid: TransactionId, + voutIndex: Int, + value: Option[BigDecimal], + address: Option[Address]) object TransactionVIN { implicit val reads: Reads[TransactionVIN] = { - val builder = (__ \ 'txid).read[TransactionId] and (__ \ 'vout).read[Int] + val builder = (__ \ 'txid).read[TransactionId] and + (__ \ 'vout).read[Int] and + (__ \ 'value).readNullable[BigDecimal] and + (__ \ 'address).readNullable[Address] - builder.apply { (txid, index) => - TransactionVIN(txid, index) + builder.apply { (txid, index, value, address) => + TransactionVIN(txid, index, value, address) } } } diff --git a/server/app/com/xsn/explorer/services/TransactionService.scala b/server/app/com/xsn/explorer/services/TransactionService.scala index a6085db..15e68b2 100644 --- a/server/app/com/xsn/explorer/services/TransactionService.scala +++ b/server/app/com/xsn/explorer/services/TransactionService.scala @@ -4,8 +4,10 @@ import javax.inject.Inject import com.alexitc.playsonify.core.FutureApplicationResult import com.alexitc.playsonify.core.FutureOr.Implicits.{FutureOps, OrOps} -import com.xsn.explorer.errors.TransactionFormatError -import com.xsn.explorer.models.{TransactionDetails, TransactionId} +import com.xsn.explorer.errors.{TransactionFormatError, TransactionNotFoundError} +import com.xsn.explorer.models.rpc.TransactionVIN +import com.xsn.explorer.models.{TransactionDetails, TransactionId, TransactionValue} +import com.xsn.explorer.util.Extensions.FutureApplicationResultExt import org.scalactic.{Good, One, Or} import scala.concurrent.{ExecutionContext, Future} @@ -21,19 +23,40 @@ class TransactionService @Inject() (xsnService: XSNService)(implicit ec: Executi transaction <- xsnService.getTransaction(txid).toFutureOr - previousMaybe <- transaction + input <- transaction .vin - .map(_.txid) - .map(xsnService.getTransaction) - .map { f => f.toFutureOr.map(Option.apply).toFuture } - .getOrElse { Future.successful(Good(Option.empty))} + .map(getTransactionValue) .toFutureOr - } yield { - previousMaybe - .map { previous => TransactionDetails.from(transaction, previous) } - .getOrElse { TransactionDetails.from(transaction) } - } + } yield TransactionDetails.from(transaction, input) result.toFuture } + + private def getTransactionValue(vin: TransactionVIN): FutureApplicationResult[TransactionValue] = { + val valueMaybe = for { + value <- vin.value + address <- vin.address + } yield TransactionValue(address, value) + + valueMaybe + .map(Good(_)) + .map(Future.successful) + .getOrElse { + val txid = vin.txid + + val result = for { + tx <- xsnService.getTransaction(txid).toFutureOr + r <- { + val maybe = tx + .vout + .find(_.n == vin.voutIndex) + .flatMap(TransactionValue.from) + + Or.from(maybe, One(TransactionNotFoundError)).toFutureOr + } + } yield r + + result.toFuture + } + } } diff --git a/server/app/com/xsn/explorer/services/logic/TransactionLogic.scala b/server/app/com/xsn/explorer/services/logic/TransactionLogic.scala index 81fa726..9a3b0ac 100644 --- a/server/app/com/xsn/explorer/services/logic/TransactionLogic.scala +++ b/server/app/com/xsn/explorer/services/logic/TransactionLogic.scala @@ -14,7 +14,7 @@ class TransactionLogic { } def getVIN(tx: Transaction, error: ApplicationError): ApplicationResult[TransactionVIN] = { - val maybe = tx.vin + val maybe = tx.vin.headOption Or.from(maybe, One(error)) } diff --git a/server/app/com/xsn/explorer/util/Extensions.scala b/server/app/com/xsn/explorer/util/Extensions.scala index c7f7ed1..ca04c50 100644 --- a/server/app/com/xsn/explorer/util/Extensions.scala +++ b/server/app/com/xsn/explorer/util/Extensions.scala @@ -1,5 +1,10 @@ package com.xsn.explorer.util +import com.alexitc.playsonify.core.{FutureApplicationResult, FutureOr} +import org.scalactic.{Bad, Good} + +import scala.concurrent.{ExecutionContext, Future} + object Extensions { private val SatoshiScale = 100000000L @@ -9,4 +14,26 @@ object Extensions { inner / SatoshiScale } } + + implicit class FutureApplicationResultExt[+A](val inner: List[FutureApplicationResult[A]]) extends AnyVal { + def toFutureOr(implicit ec: ExecutionContext): FutureOr[List[A]] = { + val futureList = Future.sequence(inner) + + val future = futureList.map { resultList => + val errorsMaybe = resultList + .flatMap(_.swap.toOption) + .reduceLeftOption(_ ++ _) + .map(_.distinct) + + errorsMaybe + .map(Bad(_)) + .getOrElse { + val valueList = resultList.flatMap(_.toOption) + Good(valueList) + } + } + + new FutureOr(future) + } + } } diff --git a/server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala b/server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala index f80c375..f984ce8 100644 --- a/server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala +++ b/server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala @@ -93,7 +93,8 @@ class XSNServiceRPCImplSpec extends WordSpec with MustMatchers with ScalaFutures val tx = result.get tx.id.string mustEqual txid.string - tx.vin.value.txid.string mustEqual "585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9" + tx.vin.size mustEqual 1 + tx.vin.head.txid.string mustEqual "585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9" tx.vout.size mustEqual 3 } } diff --git a/server/test/controllers/TransactionsControllerSpec.scala b/server/test/controllers/TransactionsControllerSpec.scala index 2a4b004..f703dcd 100644 --- a/server/test/controllers/TransactionsControllerSpec.scala +++ b/server/test/controllers/TransactionsControllerSpec.scala @@ -3,7 +3,7 @@ package controllers import com.alexitc.playsonify.PublicErrorRenderer import com.alexitc.playsonify.core.FutureApplicationResult import com.xsn.explorer.errors.TransactionNotFoundError -import com.xsn.explorer.helpers.{DummyXSNService, TransactionLoader} +import com.xsn.explorer.helpers.{DataHelper, DummyXSNService, TransactionLoader} import com.xsn.explorer.models._ import com.xsn.explorer.models.rpc.Transaction import com.xsn.explorer.services.XSNService @@ -17,15 +17,19 @@ import scala.concurrent.Future class TransactionsControllerSpec extends MyAPISpec { + import DataHelper._ + val coinbaseTx = TransactionLoader.get("024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c") val nonCoinbaseTx = TransactionLoader.get("0834641a7d30d8a2d2b451617599670445ee94ed7736e146c13be260c576c641") val nonCoinbasePreviousTx = TransactionLoader.get("585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9") + val severalInputsTx = TransactionLoader.get("a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb") val customXSNService = new DummyXSNService { val map = Map( coinbaseTx.id -> coinbaseTx, nonCoinbaseTx.id -> nonCoinbaseTx, - nonCoinbasePreviousTx.id -> nonCoinbasePreviousTx + nonCoinbasePreviousTx.id -> nonCoinbasePreviousTx, + severalInputsTx.id -> severalInputsTx ) override def getTransaction(txid: TransactionId): FutureApplicationResult[Transaction] = { @@ -69,7 +73,12 @@ class TransactionsControllerSpec extends MyAPISpec { "return non-coinbase transaction" in { val tx = nonCoinbaseTx - val details = TransactionDetails.from(nonCoinbaseTx, nonCoinbasePreviousTx) + val input = List( + TransactionValue( + createAddress("XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL"), + BigDecimal("2343749.965625")) + ) + val details = TransactionDetails.from(nonCoinbaseTx, input) val response = GET(url(tx.id.string)) status(response) mustEqual OK @@ -81,9 +90,12 @@ class TransactionsControllerSpec extends MyAPISpec { (json \ "blocktime").as[Long] mustEqual tx.blocktime (json \ "confirmations").as[Confirmations] mustEqual tx.confirmations - val inputJson = (json \ "input").as[JsValue] - (inputJson \ "address").as[String] mustEqual details.input.get.address.string - (inputJson \ "value").as[BigDecimal] mustEqual details.input.get.value + val inputJsonList = (json \ "input").as[List[JsValue]] + inputJsonList.size mustEqual 1 + + val inputJson = inputJsonList.head + (inputJson \ "address").as[String] mustEqual details.input.head.address.string + (inputJson \ "value").as[BigDecimal] mustEqual details.input.head.value val outputJsonList = (json \ "output").as[List[JsValue]] outputJsonList.size mustEqual 2 @@ -97,6 +109,43 @@ class TransactionsControllerSpec extends MyAPISpec { (outputJson2 \ "value").as[BigDecimal] mustEqual details.output.drop(1).head.value } + "return a transaction with several inputs" in { + val tx = severalInputsTx + val inputValue = TransactionValue( + createAddress("XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL"), + BigDecimal("73242.18642578")) + + val response = GET(url(tx.id.string)) + + status(response) mustEqual OK + val json = contentAsJson(response) + (json \ "id").as[String] mustEqual tx.id.string + (json \ "blockhash").as[String] mustEqual tx.blockhash.string + (json \ "size").as[Size] mustEqual tx.size + (json \ "time").as[Long] mustEqual tx.time + (json \ "blocktime").as[Long] mustEqual tx.blocktime + (json \ "confirmations").as[Confirmations] mustEqual tx.confirmations + + val inputJsonList = (json \ "input").as[List[JsValue]] + inputJsonList.size mustEqual 11 + + inputJsonList.foreach { inputJson => + (inputJson \ "address").as[String] mustEqual inputValue.address.string + (inputJson \ "value").as[BigDecimal] mustEqual inputValue.value + } + + val outputJsonList = (json \ "output").as[List[JsValue]] + outputJsonList.size mustEqual 2 + + val outputJson = outputJsonList.head + (outputJson \ "address").as[String] mustEqual "XcmqLX4qptMgAigXTVH4SJRVb6ZKmq8rjH" + (outputJson \ "value").as[BigDecimal] mustEqual BigDecimal("55664.05066658") + + val outputJson2 = outputJsonList.drop(1).head + (outputJson2 \ "address").as[String] mustEqual "XvUAd4vQtFtZ7v2Uo8e6aSsiRLAwyq1jwb" + (outputJson2 \ "value").as[BigDecimal] mustEqual BigDecimal("750000.00000000") + } + "fail on wrong transaction format" in { // 63 characters val txid = "000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c" diff --git a/server/test/resources/transactions/a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb b/server/test/resources/transactions/a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb new file mode 100644 index 0000000..835a9fb --- /dev/null +++ b/server/test/resources/transactions/a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb @@ -0,0 +1,182 @@ +{ + "hex": "010000000ba6ec9e87158b7f938fc0e5015b5bbd681ad52efeb69f45c6af35f85b7b0b0e10010000006a47304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1fefffffffe93099e481eb4af7309d3a21b41e1100c0fa37d2b73627e5591904b57d36113020000006a473044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff4a35e69f21408809dd92c75f2ce3b9f25ac329bf853e906e58a4019d4d84e156010000006a47304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff347bfc3e91604e4bda1217ed0b5816386bf2897e6de969d9f58d1dbf93965363010000006b483045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff0cd69c1ad6437a2e7ffa940dbfc2771480a8341b4a0b930624f9e0eeb6ae4379020000006b483045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff8d8af7a190c8b4161011ac358b7d512bbde95161d2c6579a4da47775ebc30d98010000006a47304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffffe53f8f0867dfe460193cd637318efd8561ad3b1eb64ede438be5667ff83acfa70200000069463043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffffbabc509d23139cd2f95f1f52db8a41f6ca7de19df3b5bc8d04cb544c8c430eb2020000006a473044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff6c8c824db640dadf8064fca68ecc69e09b029b8579777b345f3ad7435f5a71bd020000006a47304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff1a94f9e4cbe60afcfa68160369bd99ab7178d236f6ee02670fb21c7b03f81ada010000006a473044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff88718b1747d17d2119f58598dbcb4a86a7dd6534fb14245fe7e70ff137fa6ce6020000006b483045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff02a2bf9807100500001976a91416e1eaf6643ce8947b03cf6b8cedb18af941b03888ac00b05b4c364400001976a914d8fccb0f4638a314e2248d99ed8b8531c63179eb88ace8780000", + "txid": "a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb", + "size": 1697, + "version": 1, + "locktime": 30952, + "vin": [ + { + "txid": "100e0b7b5bf835afc6459fb6fe2ed51a68bd5b5b01e5c08f937f8b15879eeca6", + "vout": 1, + "scriptSig": { + "asm": "304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "47304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "1361d3574b9091557e62732b7da30f0c10e1411ba2d30973afb41e489e0993fe", + "vout": 2, + "scriptSig": { + "asm": "3044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "473044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "56e1844d9d01a4586e903e85bf29c35af2b9e32c5fc792dd098840219fe6354a", + "vout": 1, + "scriptSig": { + "asm": "304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "47304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "63539693bf1d8df5d969e96d7e89f26b3816580bed1712da4b4e60913efc7b34", + "vout": 1, + "scriptSig": { + "asm": "3045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "483045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "7943aeb6eee0f92406930b4a1b34a8801477c2bf0d94fa7f2e7a43d61a9cd60c", + "vout": 2, + "scriptSig": { + "asm": "3045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "483045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "980dc3eb7577a44d9a57c6d26151e9bd2b517d8b35ac111016b4c890a1f78a8d", + "vout": 1, + "scriptSig": { + "asm": "304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "47304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "a7cf3af87f66e58b43de4eb61e3bad6185fd8e3137d63c1960e4df67088f3fe5", + "vout": 2, + "scriptSig": { + "asm": "3043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "463043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "b20e438c4c54cb048dbcb5f39de17dcaf6418adb521f5ff9d29c13239d50bcba", + "vout": 2, + "scriptSig": { + "asm": "3044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "473044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "bd715a5f43d73a5f347b7779859b029be069cc8ea6fc6480dfda40b64d828c6c", + "vout": 2, + "scriptSig": { + "asm": "304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "47304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "da1af8037b1cb20f6702eef636d27871ab99bd69031668fafc0ae6cbe4f9941a", + "vout": 1, + "scriptSig": { + "asm": "3044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "473044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + }, + { + "txid": "e66cfa37f10fe7e75f2414fb3465dda7864acbdb9885f519217dd147178b7188", + "vout": 2, + "scriptSig": { + "asm": "3045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1", + "hex": "483045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1" + }, + "value": 73242.18642578, + "valueSat": 7324218642578, + "address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL", + "sequence": 4294967294 + } + ], + "vout": [ + { + "value": 55664.05066658, + "valueSat": 5566405066658, + "n": 0, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 16e1eaf6643ce8947b03cf6b8cedb18af941b038 OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a91416e1eaf6643ce8947b03cf6b8cedb18af941b03888ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "XcmqLX4qptMgAigXTVH4SJRVb6ZKmq8rjH" + ] + }, + "spentTxId": "a645956bee96351d86d860ce71b793ab0aa4c2c0d2c1d687321beaca414313ea", + "spentIndex": 5, + "spentHeight": 33257 + }, + { + "value": 750000.00000000, + "valueSat": 75000000000000, + "n": 1, + "scriptPubKey": { + "asm": "OP_DUP OP_HASH160 d8fccb0f4638a314e2248d99ed8b8531c63179eb OP_EQUALVERIFY OP_CHECKSIG", + "hex": "76a914d8fccb0f4638a314e2248d99ed8b8531c63179eb88ac", + "reqSigs": 1, + "type": "pubkeyhash", + "addresses": [ + "XvUAd4vQtFtZ7v2Uo8e6aSsiRLAwyq1jwb" + ] + }, + "spentTxId": "d840d65a9666fa0ed756ebea07c7256f318634df735ff1852ebb159c28e7d6c2", + "spentIndex": 0, + "spentHeight": 30958 + } + ], + "blockhash": "d91ae20bcab3074715cd401fa854c35d011a8f393323a7938baf687038b563a1", + "height": 30953, + "confirmations": 3093, + "time": 1522271123, + "blocktime": 1522271123 +} \ No newline at end of file