mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
2021 11 30 issue 3847 (#3862)
* Start pulling over accept serializers from dlc message spec PR * Get sign tlv json serialization working * Implement decodeaccept,decodesign in CoreRoutes * Move messages to DLCTestUtil, add documentation
This commit is contained in:
parent
169222a306
commit
d393848cc2
@ -0,0 +1,60 @@
|
||||
package org.bitcoins.commons.json
|
||||
|
||||
import org.bitcoins.commons.serializers.Picklers
|
||||
import org.bitcoins.core.protocol.tlv.DLCAcceptTLV
|
||||
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
|
||||
|
||||
class DLCAcceptJsonSerializerTest extends BitcoinSUnitTest {
|
||||
|
||||
behavior of "DLCAcceptJsonSerializer"
|
||||
|
||||
private val testString: String =
|
||||
s"""
|
||||
|{
|
||||
| "temporaryContractId": "bdc5286cd4b56c2b2525bc9e0e3dda1d6a2a130cc7fd8ca8a38d401ef9a5d3e7",
|
||||
| "acceptCollateral": 100000000,
|
||||
| "fundingPubkey": "0208dfffdda2a61c78c906f5d76afdb0b8fe0555e6a3644c41f53b511427f80f0a",
|
||||
| "payoutSpk": "001463c84b34fcf37ee58566aa6daf0747f74e509970",
|
||||
| "payoutSerialId": "11859227771650291066",
|
||||
| "fundingInputs": [
|
||||
| {
|
||||
| "inputSerialId": "6134040349072004330",
|
||||
| "prevTx": "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000160014c87d38bcd3a468680e7c0abeeb7821d6302df9120000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
| "prevTxVout": 0,
|
||||
| "sequence": 4294967295,
|
||||
| "maxWitnessLen": 107,
|
||||
| "redeemScript": ""
|
||||
| }
|
||||
| ],
|
||||
| "changeSpk": "001481467abc1d30f5139fe8ff8c1ca7f7cb3f5bc031",
|
||||
| "changeSerialId": "13987689245506757418",
|
||||
| "cetAdaptorSignatures": {
|
||||
| "ecdsaAdaptorSignatures": [
|
||||
| {
|
||||
| "signature": "02b7dda1b4030e0f85a98eb15a6806f1ffb72b578a508f671f4e6bbd954aa2d5b9022a01536f70340da9ba2b0e034deec1a0b658cbec2432f2fa2a96de09000eafaafb586eec1375c85737bb7e9fde1cb7fcf3a8a970e698d0e5da55297ea64a45b8ffb2b705974b91e8e3d9b0e46573c648122fda1ef941980ba845ab09d1e7a43949add788ed79e4a23b832b1418c3b54251b0d3c83e791ce24c2e30544456d3b8"
|
||||
| },
|
||||
| {
|
||||
| "signature": "02d510a07687553f7dd26ff6124cdccbf73ccd8661ae9bd6a59a25cedac04727fd03fb8955cb520fde3dc30fbf095054a87f8c3e87f027238e3bc435b0dc6df2532af475c531e234ee045d6119d989a62d8b29bdfdbdcdf8d6761b0cb5fbd1eb6ef71fa04c7a993801e2d02d5659c08f629f7d5ef02173ce5b1fcec361d99b9aee79549a085c14bb3f7df507e891a35089b3d9886e7c81b7367cac8c75bbb9432861"
|
||||
| },
|
||||
| {
|
||||
| "signature": "0328ca81f2f281c39eda04fb69456f6b104f09d920d57def9e396aa60de6c0b38c03e73ec3891966e5d339ea154bf17e265f80cb75bfc922b83d79102f44479a69e281a485c8e99abc382aad656983f8f92a5836437156c783e261bfe0bf7eec9e3bb83ff8b4d948458b3d8fdfbc74b23cd02a72b06b84aa156a7bf6a578757c205257aa86a728b6b8022c303c9b01164f0332d6bc5aaa17014c7bb87d598b83af5d"
|
||||
| },
|
||||
| {
|
||||
| "signature": "0337e4ce2c5b3fb9d70663bac8797f8e7a1493af23f74ac9ace7449a35d59c757a02676f9cc3adf9d3d03ef5a4daf704c5d178dae12364f0297ab09982d5da08145010fc26c71166e6a2e651e4c351916f2e7d538c14adeccbd2f21c18f1d4ddea619120af9bcef67dcda0ed5b8d5c4dddee167107263becf05c91e0a13c2e653cd9722674531031610ef6b8cd80b205fc78834db55cf08e45d37616a6e218b7e09c"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "refundSignature": "304402202c9b25719f0a22d7372c54c36f916e44f445135809433585636417fe18b9316c0220125584711c7238d0adf4a494e30a166fef35edf3d0d1718955abd73b76a26e9d",
|
||||
| "negotiationFields": null
|
||||
| }
|
||||
|""".stripMargin
|
||||
|
||||
it must "have serialization symmetry for a accept json message" in {
|
||||
val accept = upickle.default.read[DLCAcceptTLV](testString)(
|
||||
Picklers.dlcAcceptTLVPickler)
|
||||
val json: String =
|
||||
upickle.default.write(accept)(Picklers.dlcAcceptTLVPickler)
|
||||
assert(json == testString.replaceAll("\\s", ""))
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package org.bitcoins.commons.json
|
||||
|
||||
import org.bitcoins.commons.serializers.Picklers
|
||||
import org.bitcoins.core.protocol.tlv.{DLCSignTLV, LnMessage}
|
||||
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
|
||||
|
||||
class DLCSignJsonSerializerTest extends BitcoinSUnitTest {
|
||||
behavior of "DLCAcceptJsonSerializer"
|
||||
|
||||
private val testString: String = {
|
||||
s"""
|
||||
|{
|
||||
| "contractId": "afcd7e786c0b9085784a6d063c7f4e7291784f9be3ba23cd8734559040fd2202",
|
||||
| "cetAdaptorSignatures": {
|
||||
| "ecdsaAdaptorSignatures": [
|
||||
| {
|
||||
| "signature": "02feee4c75948830549fd19efd93cd4e00d4f538041ecf2f2cb6820c78c0a57fc9034d9ce5849e0abe235b8c3137506745508aa17c7a3064ec4172e76c88e66ca27257c5ec09f99201c9bc95b8ab345aff9b32b89c328d21a6ca5553f287a650320162381ef95042d9ac57f66f39dc6904f17a472671d3828f75ef29fbddcd31119b69adb216dac9b5960b91b3e3d83b9310484ef667d19f4bed01964ff063a2acbd"
|
||||
| },
|
||||
| {
|
||||
| "signature": "025e840169038f0d046cc5005d9d622fd19ec2dd84d15a022f3eff4a781c6f404602cf8ec975191b73ecc3944786f5cca2a01ba3e71bbde9ea6932083c23591dfb6e3e06489cde6415c39cc9e187283f7a9b76227b157572dc62f1a5b130b4fc6b68c14ea07deddb2865d634a244839a87f158145c59d9aecb51b082c3a2ef0cb0201bc65252a3876f7253855ce4d3e72cd650bc275dd878f920162af74865b0346b"
|
||||
| },
|
||||
| {
|
||||
| "signature": "03ea132cd20738f1a6640f98dc5664d12952e000feb69bbb3c4929c9054b3ca965030b788e83098f906cd3b088ad297e8149d08eb02442f42bd2b9e4455d5a19a96fd329625e1f1d0db9b9f625a6242f1fc53f56ec8090575c704e364518bdf7d690386d0f4a7bfea6c263c5fbc91631b0f0323a92c51f43f3228c9649c5441b338f2e37cbad0d10ce0d80429e2a6a528e4a0e9700188b86c267246b5049ce7da031"
|
||||
| },
|
||||
| {
|
||||
| "signature": "02c2ec44af74653bdad7db89a38ab61d3dabf0646acdfab1bd5906d4a75f8d7a0c03051281626d4c8c84a5b7d09717c69f1c5340300be5ef6d94a4efe4d1baebbf820f8891a3b86d0f4a9a42d3fa0a44f7d711a5e65cc887b0424530e9b7e49f8d3a21d89762d535c7f121bc057b01b67372ea19762fad714580767ea6a091771808c3806b273382e0792573f624a90e15004a3b852e627f422c07209fd876c38169"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "refundSignature": "3044022005d4dcc449db1a5997b82f2aabaffb3414ad1e10c159fc3fcbd6dab121a3cb98022037583d39f66aa347a8170dba12cf88102997f460bb27d70365f7f85cd4ce5ee2",
|
||||
| "fundingSignatures": {
|
||||
| "fundingSignatures": [
|
||||
| {
|
||||
| "witnessElements": [
|
||||
| {
|
||||
| "witness": "304402204bbe45fd65402ad89784062c2af0f0c88a55f1de4509e4491f7933ada30fbab102207144fe9b8d621d2bef5c226d6f2f8ff43548f4c0bb9ea221a0c2a034a069c74f01"
|
||||
| },
|
||||
| {
|
||||
| "witness": "03bdb496d31a30d8e87ab7767fd26bfdfa7f6d06a0cfaea082a91af1ae1814f251"
|
||||
| }
|
||||
| ]
|
||||
| }
|
||||
| ]
|
||||
| }
|
||||
| }
|
||||
|""".stripMargin
|
||||
}
|
||||
|
||||
it must "have serialization symmetry for dlc sign messages" in {
|
||||
val sign =
|
||||
upickle.default.read[DLCSignTLV](testString)(Picklers.dlcSignTLVPickler)
|
||||
println(s"accept=${LnMessage(sign).hex}")
|
||||
val json: String =
|
||||
upickle.default.write(sign)(Picklers.dlcSignTLVPickler)
|
||||
assert(json == testString.replaceAll("\\s", ""))
|
||||
}
|
||||
}
|
@ -7,9 +7,15 @@ import org.bitcoins.core.crypto._
|
||||
import org.bitcoins.core.currency.{Bitcoins, Satoshis}
|
||||
import org.bitcoins.core.dlc.accounting.DLCWalletAccounting
|
||||
import org.bitcoins.core.hd.AddressType
|
||||
import org.bitcoins.core.number.UInt32
|
||||
import org.bitcoins.core.number.{UInt16, UInt32, UInt64}
|
||||
import org.bitcoins.core.protocol.dlc.models.DLCStatus._
|
||||
import org.bitcoins.core.protocol.dlc.models._
|
||||
import org.bitcoins.core.protocol.script.{
|
||||
ScriptPubKey,
|
||||
ScriptWitness,
|
||||
ScriptWitnessV0,
|
||||
WitnessScriptPubKey
|
||||
}
|
||||
import org.bitcoins.core.protocol.tlv._
|
||||
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutPoint}
|
||||
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
|
||||
@ -123,16 +129,234 @@ object Picklers {
|
||||
implicit val lnMessageDLCOfferTLVPickler: ReadWriter[LnMessage[DLCOfferTLV]] =
|
||||
readwriter[String].bimap(_.hex, LnMessageFactory(DLCOfferTLV).fromHex)
|
||||
|
||||
implicit val dlcAcceptTLVPickler: ReadWriter[DLCAcceptTLV] =
|
||||
readwriter[String].bimap(_.hex, DLCAcceptTLV.fromHex)
|
||||
private def parseU64(str: ujson.Str): UInt64 = {
|
||||
UInt64(BigInt(str.str))
|
||||
}
|
||||
|
||||
private def parseFundingInput(obj: ujson.Obj): FundingInputTLV = {
|
||||
val inputSerialId = parseU64(obj(PicklerKeys.inputSerialIdKey).str)
|
||||
val prevTx = Transaction.fromHex(obj(PicklerKeys.prevTxKey).str)
|
||||
val prevTxVout = obj(PicklerKeys.prevTxVoutKey).num.toLong
|
||||
val sequence = UInt32(obj(PicklerKeys.sequenceKey).num.toLong)
|
||||
val maxWitnessLen = UInt16(obj(PicklerKeys.maxWitnessLenKey).num.toLong)
|
||||
val redeemScriptStr = obj(PicklerKeys.redeemScriptKey).str
|
||||
val redeemScriptOpt = if (redeemScriptStr.nonEmpty) {
|
||||
val spk =
|
||||
WitnessScriptPubKey.fromAsmHex(obj(PicklerKeys.redeemScriptKey).str)
|
||||
Some(spk)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
FundingInputV0TLV(
|
||||
inputSerialId,
|
||||
prevTx,
|
||||
UInt32(prevTxVout),
|
||||
sequence,
|
||||
maxWitnessLen,
|
||||
redeemScriptOpt
|
||||
)
|
||||
}
|
||||
|
||||
private def parseFundingInputs(arr: ujson.Arr): Vector[FundingInputTLV] = {
|
||||
arr.value.toVector.map {
|
||||
case inputObj: ujson.Obj =>
|
||||
parseFundingInput(inputObj)
|
||||
case x: ujson.Value =>
|
||||
sys.error(s"Expected obj, got=$x")
|
||||
}
|
||||
}
|
||||
|
||||
private def parseCetAdaptorSignatures(obj: ujson.Obj): CETSignaturesTLV = {
|
||||
val ecAdaptorSignaturesArr = obj(PicklerKeys.ecdsaAdaptorSignaturesKey).arr
|
||||
val adaptorSigs = parseAdaptorSignatures(ecAdaptorSignaturesArr)
|
||||
CETSignaturesV0TLV(adaptorSigs)
|
||||
}
|
||||
|
||||
private def parseAdaptorSignatures(
|
||||
arr: ujson.Arr): Vector[ECAdaptorSignature] = {
|
||||
arr.value.toVector.map {
|
||||
case obj: ujson.Obj =>
|
||||
ECAdaptorSignature.fromHex(obj(PicklerKeys.signatureKey).str)
|
||||
case x: ujson.Value =>
|
||||
sys.error(s"Excpected string for ecdsa adaptor siganture, got obj=$x")
|
||||
}
|
||||
}
|
||||
|
||||
private def writeAdaptorSignatures(
|
||||
sigs: Vector[ECAdaptorSignature]): Vector[ujson.Obj] = {
|
||||
sigs.map { sig =>
|
||||
ujson.Obj(PicklerKeys.signatureKey -> Str(sig.hex))
|
||||
}
|
||||
}
|
||||
|
||||
private def writeCetAdaptorSigs(
|
||||
cetSignaturesTLV: CETSignaturesTLV): ujson.Obj = {
|
||||
cetSignaturesTLV match {
|
||||
case v0: CETSignaturesV0TLV =>
|
||||
val sigsVec = writeAdaptorSignatures(v0.sigs)
|
||||
ujson.Obj(
|
||||
PicklerKeys.ecdsaAdaptorSignaturesKey -> ujson.Arr.from(sigsVec))
|
||||
}
|
||||
}
|
||||
|
||||
private def readAcceptTLV(obj: ujson.Obj): DLCAcceptTLV = {
|
||||
val tempContractId =
|
||||
Sha256Digest.fromHex(obj(PicklerKeys.temporaryContractIdKey).str)
|
||||
val acceptCollateral = Satoshis(
|
||||
obj(PicklerKeys.acceptCollateralKey).num.toLong)
|
||||
val fundingPubKey =
|
||||
ECPublicKey.fromHex(obj(PicklerKeys.fundingPubKeyKey).str)
|
||||
val payoutSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.payoutSpkKey).str)
|
||||
val payoutSerialId = parseU64(obj(PicklerKeys.payoutSerialIdKey).str)
|
||||
val fundingInputs = parseFundingInputs(
|
||||
obj(PicklerKeys.fundingInputsKey).arr)
|
||||
val changeSpk = ScriptPubKey.fromAsmHex(obj(PicklerKeys.changeSpkKey).str)
|
||||
val changeSerialId = parseU64(obj(PicklerKeys.changeSerialIdKey).str)
|
||||
val cetAdaptorSigs = parseCetAdaptorSignatures(
|
||||
obj(PicklerKeys.cetAdaptorSignaturesKey).obj)
|
||||
val refundSignature =
|
||||
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
||||
val negotiationFields = {
|
||||
obj(PicklerKeys.negotiationFieldsKey).strOpt match {
|
||||
case Some(str) =>
|
||||
sys.error(s"Don't know how to parse negotiation fields, got=$str")
|
||||
case None => NegotiationFieldsTLV.empty
|
||||
}
|
||||
}
|
||||
|
||||
val acceptTLV = DLCAcceptTLV(
|
||||
tempContractId = tempContractId,
|
||||
totalCollateralSatoshis = acceptCollateral,
|
||||
fundingPubKey = fundingPubKey,
|
||||
payoutSPK = payoutSpk,
|
||||
payoutSerialId = payoutSerialId,
|
||||
fundingInputs = fundingInputs,
|
||||
changeSPK = changeSpk,
|
||||
changeSerialId = changeSerialId,
|
||||
cetSignatures = cetAdaptorSigs,
|
||||
refundSignature = refundSignature,
|
||||
negotiationFields = negotiationFields
|
||||
)
|
||||
|
||||
acceptTLV
|
||||
}
|
||||
|
||||
private def writeAcceptTLV(accept: DLCAcceptTLV): ujson.Obj = {
|
||||
Obj(
|
||||
PicklerKeys.tempContractIdKey -> Str(accept.tempContractId.hex),
|
||||
PicklerKeys.acceptCollateralKey -> Num(
|
||||
accept.totalCollateralSatoshis.toLong.toDouble),
|
||||
PicklerKeys.fundingPubKeyKey -> Str(accept.fundingPubKey.hex),
|
||||
PicklerKeys.payoutSpkKey -> Str(accept.payoutSPK.asmHex),
|
||||
PicklerKeys.payoutSerialIdKey -> Str(
|
||||
accept.payoutSerialId.toBigInt.toString()),
|
||||
PicklerKeys.fundingInputsKey -> writeJs(accept.fundingInputs),
|
||||
PicklerKeys.changeSpkKey -> Str(accept.changeSPK.asmHex),
|
||||
PicklerKeys.changeSerialIdKey -> Str(
|
||||
accept.changeSerialId.toBigInt.toString()),
|
||||
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
||||
accept.cetSignatures),
|
||||
PicklerKeys.refundSignatureKey -> Str(accept.refundSignature.hex),
|
||||
PicklerKeys.negotiationFieldsKey -> ujson.Null
|
||||
)
|
||||
}
|
||||
|
||||
private def parseFundingSignatures(obj: ujson.Obj): FundingSignaturesTLV = {
|
||||
val fundingSignatures: Vector[ujson.Value] = obj(
|
||||
PicklerKeys.fundingSignaturesKey).arr.toVector
|
||||
val witV0 = paresFundingSignaturesArr(fundingSignatures)
|
||||
FundingSignaturesV0TLV(witV0)
|
||||
}
|
||||
|
||||
private def paresFundingSignaturesArr(
|
||||
arr: Vector[ujson.Value]): Vector[ScriptWitnessV0] = {
|
||||
arr.map {
|
||||
case obj: ujson.Obj =>
|
||||
val witnessElementsArr = obj(PicklerKeys.witnessElementsKey).arr
|
||||
val witnesses: Vector[ByteVector] = {
|
||||
parseWitnessElements(witnessElementsArr)
|
||||
}
|
||||
|
||||
val scriptWitnessV0 = ScriptWitness
|
||||
.apply(witnesses.reverse)
|
||||
.asInstanceOf[ScriptWitnessV0]
|
||||
scriptWitnessV0
|
||||
case x =>
|
||||
sys.error(s"Expected array of objects for funding signatures, got=$x")
|
||||
}
|
||||
}
|
||||
|
||||
private def parseWitnessElements(arr: ujson.Arr): Vector[ByteVector] = {
|
||||
arr.value.toVector.map {
|
||||
case obj: ujson.Obj =>
|
||||
val witnessStr = obj(PicklerKeys.witnessKey).str
|
||||
ByteVector.fromValidHex(witnessStr)
|
||||
case x: ujson.Value =>
|
||||
sys.error(s"Expected witness json object, got=$x")
|
||||
}
|
||||
}
|
||||
|
||||
private def writeWitnessElements(witness: ScriptWitness): ujson.Obj = {
|
||||
val vec: Vector[ujson.Obj] = witness.stack.reverse.map { w =>
|
||||
ujson.Obj(PicklerKeys.witnessKey -> Str(w.toHex))
|
||||
}.toVector
|
||||
|
||||
ujson.Obj(PicklerKeys.witnessElementsKey -> ujson.Arr.from(vec))
|
||||
}
|
||||
|
||||
private def writeFundingSignatures(
|
||||
fundingSigs: FundingSignaturesTLV): ujson.Obj = {
|
||||
val sigs: Vector[ujson.Obj] = fundingSigs match {
|
||||
case v0: FundingSignaturesV0TLV =>
|
||||
val witnessJson: Vector[ujson.Obj] =
|
||||
v0.witnesses.map(writeWitnessElements)
|
||||
witnessJson
|
||||
}
|
||||
ujson.Obj(
|
||||
PicklerKeys.fundingSignaturesKey -> ujson.Arr.from(sigs)
|
||||
)
|
||||
}
|
||||
|
||||
private def readSignTLV(obj: ujson.Obj): DLCSignTLV = {
|
||||
val contractId = ByteVector.fromValidHex(obj(PicklerKeys.contractIdKey).str)
|
||||
val adaptorSigs = parseCetAdaptorSignatures(
|
||||
obj(PicklerKeys.cetAdaptorSignaturesKey).obj)
|
||||
val refundSignature =
|
||||
ECDigitalSignature.fromHex(obj(PicklerKeys.refundSignatureKey).str)
|
||||
val fundingSignatures = parseFundingSignatures(
|
||||
obj(PicklerKeys.fundingSignaturesKey).obj)
|
||||
|
||||
val signTLV =
|
||||
DLCSignTLV(contractId, adaptorSigs, refundSignature, fundingSignatures)
|
||||
|
||||
signTLV
|
||||
|
||||
}
|
||||
|
||||
private def writeSignTLV(sign: DLCSignTLV): ujson.Obj = {
|
||||
ujson.Obj(
|
||||
PicklerKeys.contractIdKey -> sign.contractId.toHex,
|
||||
PicklerKeys.cetAdaptorSignaturesKey -> writeCetAdaptorSigs(
|
||||
sign.cetSignatures),
|
||||
PicklerKeys.refundSignatureKey -> ujson.Str(sign.refundSignature.hex),
|
||||
PicklerKeys.fundingSignaturesKey ->
|
||||
writeFundingSignatures(sign.fundingSignatures)
|
||||
)
|
||||
}
|
||||
|
||||
implicit val dlcAcceptTLVPickler: ReadWriter[DLCAcceptTLV] = {
|
||||
readwriter[ujson.Obj].bimap(writeAcceptTLV, readAcceptTLV)
|
||||
}
|
||||
|
||||
implicit val dlcSignTLVPickler: ReadWriter[DLCSignTLV] = {
|
||||
readwriter[ujson.Obj].bimap(writeSignTLV, readSignTLV)
|
||||
}
|
||||
|
||||
implicit val lnMessageDLCAcceptTLVPickler: ReadWriter[
|
||||
LnMessage[DLCAcceptTLV]] =
|
||||
readwriter[String].bimap(_.hex, LnMessageFactory(DLCAcceptTLV).fromHex)
|
||||
|
||||
implicit val dlcSignTLVPickler: ReadWriter[DLCSignTLV] =
|
||||
readwriter[String].bimap(_.hex, DLCSignTLV.fromHex)
|
||||
|
||||
implicit val lnMessageDLCSignTLVPickler: ReadWriter[LnMessage[DLCSignTLV]] =
|
||||
readwriter[String].bimap(_.hex, LnMessageFactory(DLCSignTLV).fromHex)
|
||||
|
||||
@ -227,11 +451,11 @@ object Picklers {
|
||||
|
||||
val redeemScriptJson = redeemScriptOpt match {
|
||||
case Some(rs) => Str(rs.hex)
|
||||
case None => ujson.Null
|
||||
case None => Str("")
|
||||
}
|
||||
|
||||
Obj(
|
||||
"inputSerialId" -> Num(inputSerialId.toBigInt.toDouble),
|
||||
"inputSerialId" -> Str(inputSerialId.toBigInt.toString()),
|
||||
"prevTx" -> Str(prevTx.hex),
|
||||
"prevTxVout" -> Num(prevTxVout.toLong.toDouble),
|
||||
"sequence" -> Num(sequence.toLong.toDouble),
|
||||
@ -433,7 +657,7 @@ object Picklers {
|
||||
totalCollateralSatoshis.toLong.toDouble),
|
||||
"fundingInputs" -> fundingInputs.map(i => writeJs(i)),
|
||||
"changeSPK" -> Str(changeSPK.hex),
|
||||
"changeSerialId" -> Num(changeSerialId.toBigInt.toDouble),
|
||||
"changeSerialId" -> Str(changeSerialId.toBigInt.toString()),
|
||||
"fundOutputSerialId" -> Num(fundOutputSerialId.toBigInt.toDouble),
|
||||
"feeRatePerVb" -> Num(feeRate.toLong.toDouble),
|
||||
"cetLocktime" -> Num(contractMaturityBound.toUInt32.toLong.toDouble),
|
||||
|
@ -0,0 +1,46 @@
|
||||
package org.bitcoins.server
|
||||
|
||||
import akka.http.scaladsl.model.ContentTypes
|
||||
import akka.http.scaladsl.testkit.ScalatestRouteTest
|
||||
import org.bitcoins.server.routes.ServerCommand
|
||||
import org.bitcoins.testkit.BitcoinSTestAppConfig
|
||||
import org.bitcoins.testkitcore.dlc.DLCTestUtil
|
||||
import org.scalamock.scalatest.MockFactory
|
||||
import org.scalatest.wordspec.AnyWordSpec
|
||||
|
||||
class CoreRoutesSpec
|
||||
extends AnyWordSpec
|
||||
with ScalatestRouteTest
|
||||
with MockFactory {
|
||||
|
||||
implicit val conf: BitcoinSAppConfig =
|
||||
BitcoinSTestAppConfig.getSpvTestConfig()
|
||||
val coreRoutes = CoreRoutes()
|
||||
|
||||
"Core routes" should {
|
||||
"decode an accept message" in {
|
||||
val args = ujson.Arr(DLCTestUtil.acceptHex)
|
||||
val route =
|
||||
coreRoutes.handleCommand(ServerCommand("decodeaccept", args))
|
||||
|
||||
Post() ~> route ~> check {
|
||||
assert(contentType == ContentTypes.`application/json`)
|
||||
val actualJson = ujson.read(responseAs[String])
|
||||
assert(actualJson == DLCTestUtil.expectedAccept)
|
||||
}
|
||||
}
|
||||
|
||||
"decode a sign message" in {
|
||||
val args = ujson.Arr(DLCTestUtil.signHex)
|
||||
val route =
|
||||
coreRoutes.handleCommand(ServerCommand("decodesign", args))
|
||||
|
||||
Post() ~> route ~> check {
|
||||
assert(contentType == ContentTypes.`application/json`)
|
||||
val actualJson = ujson.read(responseAs[String])
|
||||
assert(actualJson == DLCTestUtil.expectedSign)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -24,7 +24,7 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig)
|
||||
extends ServerRoute {
|
||||
import system.dispatcher
|
||||
|
||||
def handleCommand: PartialFunction[ServerCommand, Route] = {
|
||||
override def handleCommand: PartialFunction[ServerCommand, Route] = {
|
||||
case ServerCommand("finalizepsbt", arr) =>
|
||||
withValidServerCommand(FinalizePSBT.fromJsArr(arr)) {
|
||||
case FinalizePSBT(psbt) =>
|
||||
@ -153,7 +153,20 @@ case class CoreRoutes()(implicit system: ActorSystem, config: BitcoinSAppConfig)
|
||||
Server.httpSuccess(writeJs(offerTLV))
|
||||
}
|
||||
}
|
||||
|
||||
case ServerCommand("decodeaccept", arr) =>
|
||||
withValidServerCommand(DecodeAccept.fromJsArr(arr)) {
|
||||
case DecodeAccept(accept) =>
|
||||
complete {
|
||||
Server.httpSuccess(writeJs(accept))
|
||||
}
|
||||
}
|
||||
case ServerCommand("decodesign", arr) =>
|
||||
withValidServerCommand(DecodeSign.fromJsArr(arr)) {
|
||||
case DecodeSign(accept) =>
|
||||
complete {
|
||||
Server.httpSuccess(writeJs(accept))
|
||||
}
|
||||
}
|
||||
case ServerCommand("decodecontractinfo", arr) =>
|
||||
withValidServerCommand(DecodeContractInfo.fromJsArr(arr)) {
|
||||
case DecodeContractInfo(contractInfo) =>
|
||||
|
@ -735,6 +735,66 @@ object DecodeOffer extends ServerJsonModels {
|
||||
}
|
||||
}
|
||||
|
||||
case class DecodeAccept(accept: DLCAcceptTLV)
|
||||
|
||||
object DecodeAccept extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[DecodeAccept] = {
|
||||
jsArr.arr.toList match {
|
||||
case acceptJs :: Nil =>
|
||||
Try {
|
||||
val accept: LnMessage[DLCAcceptTLV] =
|
||||
LnMessageFactory(DLCAcceptTLV).fromHex(acceptJs.str)
|
||||
DecodeAccept(accept.tlv)
|
||||
} match {
|
||||
case Success(value) =>
|
||||
Success(value)
|
||||
case Failure(_) =>
|
||||
Try {
|
||||
val accept = DLCAcceptTLV.fromHex(acceptJs.str)
|
||||
DecodeAccept(accept)
|
||||
}
|
||||
}
|
||||
case Nil =>
|
||||
Failure(new IllegalArgumentException(s"Missing accept announcement"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length} Expected: 1"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class DecodeSign(sign: DLCSignTLV)
|
||||
|
||||
object DecodeSign extends ServerJsonModels {
|
||||
|
||||
def fromJsArr(jsArr: ujson.Arr): Try[DecodeSign] = {
|
||||
jsArr.arr.toList match {
|
||||
case signJs :: Nil =>
|
||||
Try {
|
||||
val accept: LnMessage[DLCSignTLV] =
|
||||
LnMessageFactory(DLCSignTLV).fromHex(signJs.str)
|
||||
DecodeSign(accept.tlv)
|
||||
} match {
|
||||
case Success(value) =>
|
||||
Success(value)
|
||||
case Failure(_) =>
|
||||
Try {
|
||||
val sign = DLCSignTLV.fromHex(signJs.str)
|
||||
DecodeSign(sign)
|
||||
}
|
||||
}
|
||||
case Nil =>
|
||||
Failure(new IllegalArgumentException(s"Missing accept announcement"))
|
||||
case other =>
|
||||
Failure(
|
||||
new IllegalArgumentException(
|
||||
s"Bad number of arguments: ${other.length} Expected: 1"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case class DecodeAnnouncement(announcement: OracleAnnouncementTLV)
|
||||
|
||||
object DecodeAnnouncement extends ServerJsonModels {
|
||||
|
@ -32,4 +32,5 @@ abstract class Script extends NetworkElement {
|
||||
/** The full byte serialization for a script on the network */
|
||||
override val bytes: ByteVector = compactSizeUInt.bytes ++ asmBytes
|
||||
|
||||
lazy val asmHex: String = asmBytes.toHex
|
||||
}
|
||||
|
@ -1535,6 +1535,8 @@ sealed trait NegotiationFieldsTLV extends DLCSetupPieceTLV
|
||||
|
||||
object NegotiationFieldsTLV extends TLVParentFactory[NegotiationFieldsTLV] {
|
||||
|
||||
final val empty: NoNegotiationFieldsTLV.type = NoNegotiationFieldsTLV
|
||||
|
||||
override val allFactories: Vector[TLVFactory[NegotiationFieldsTLV]] =
|
||||
Vector(NoNegotiationFieldsTLVFactory, NegotiationFieldsV1TLV)
|
||||
|
||||
|
@ -21,9 +21,96 @@ object PicklerKeys {
|
||||
//offers
|
||||
final val protocolVersionKey: String = "protocolVersion"
|
||||
|
||||
//accepts
|
||||
final val tempContractIdKey: String = "temporaryContractId"
|
||||
final val fundingPubKeyKey: String = "fundingPubkey"
|
||||
final val acceptCollateralKey: String = "acceptCollateral"
|
||||
final val payoutSpkKey: String = "payoutSpk"
|
||||
final val payoutSerialIdKey: String = "payoutSerialId"
|
||||
final val fundingInputsKey: String = "fundingInputs"
|
||||
final val changeSpkKey = "changeSpk"
|
||||
final val changeSerialIdKey: String = "changeSerialId"
|
||||
final val negotiationFieldsKey: String = "negotiationFields"
|
||||
|
||||
//contract info
|
||||
final val totalCollateralKey = "totalCollateral"
|
||||
final val contractDescriptorKey = "contractDescriptor"
|
||||
final val oracleInfoKey = "oracleInfo"
|
||||
final val pairsKey = "pairs"
|
||||
|
||||
val contractFlagsKey = "contractFlags"
|
||||
val chainHashKey = "chainHash"
|
||||
|
||||
val contractInfoKey = "contractInfo"
|
||||
val singleContractInfoKey = "singleContractInfo"
|
||||
|
||||
val enumeratedContractDescriptorKey = "enumeratedContractDescriptor"
|
||||
val numericOutcomeContractDescriptorKey = "numericOutcomeContractDescriptor"
|
||||
val payoutsKey = "payouts"
|
||||
|
||||
//numeric contract descriptor
|
||||
val numDigitsKey = "numDigits"
|
||||
val payFunctionKey = "payoutFunction"
|
||||
val payoutFunctionPiecesKey = "payoutFunctionPieces"
|
||||
val leftEndPointKey = "leftEndPoint"
|
||||
val eventOutcomeKey = "eventOutcome"
|
||||
val outcomePayoutKey = "outcomePayout"
|
||||
|
||||
val payoutCurvePieceKey = "payoutCurvePiece"
|
||||
val polynomialPayoutCurvePieceKey = "polynomialPayoutCurvePiece"
|
||||
val payoutPointsKey = "payoutPoints"
|
||||
|
||||
val lastEndpointKey = "lastEndpoint"
|
||||
|
||||
val roundingIntervalsKey = "roundingIntervals"
|
||||
val intervalsKey = "intervals"
|
||||
val beginIntervalKey = "beginInterval"
|
||||
val roundingModKey = "roundingMod"
|
||||
|
||||
val singleKey = "single"
|
||||
|
||||
val oracleAnnouncementKey = "oracleAnnouncement"
|
||||
val announcementSignatureKey = "announcementSignature"
|
||||
val oraclePublicKeyKey = "oraclePublicKey"
|
||||
val oracleEventKey = "oracleEvent"
|
||||
val oracleNoncesKey = "oracleNonces"
|
||||
val eventMaturityEpochKey = "eventMaturityEpoch"
|
||||
val eventDescriptorKey = "eventDescriptor"
|
||||
val enumEventKey = "enumEvent"
|
||||
|
||||
val digitDecompositionEventKey = "digitDecompositionEvent"
|
||||
val baseKey = "base"
|
||||
val isSignedKey = "isSigned"
|
||||
val unitKey = "unit"
|
||||
val precisionKey = "precision"
|
||||
val nbDigitsKey = "nbDigits"
|
||||
|
||||
val eventIdKey = "eventId"
|
||||
|
||||
val offerCollateralKey = "offerCollateral"
|
||||
|
||||
val fundOutputSerialIdKey = "fundOutputSerialId"
|
||||
val feeRatePerKbKey = "feeRatePerVb"
|
||||
val contractMaturityBoundKey = "contractMaturityBound"
|
||||
val contractTimeoutKey = "contractTimeout"
|
||||
|
||||
val acceptMessageKey = "accept_message"
|
||||
val temporaryContractIdKey = "temporaryContractId"
|
||||
val inputSerialIdKey = "inputSerialId"
|
||||
val prevTxKey = "prevTx"
|
||||
val prevTxVoutKey = "prevTxVout"
|
||||
val sequenceKey = "sequence"
|
||||
val maxWitnessLenKey = "maxWitnessLen"
|
||||
val redeemScriptKey = "redeemScript"
|
||||
val cetAdaptorSignaturesKey = "cetAdaptorSignatures"
|
||||
val ecdsaAdaptorSignaturesKey = "ecdsaAdaptorSignatures"
|
||||
val signatureKey = "signature"
|
||||
val refundSignatureKey = "refundSignature"
|
||||
|
||||
val signMessageKey = "sign_message"
|
||||
val contractIdKey = "contractId"
|
||||
val fundingSignaturesKey = "fundingSignatures"
|
||||
val witnessElementsKey = "witnessElements"
|
||||
val witnessKey = "witness"
|
||||
val serializedKey = "serialized"
|
||||
}
|
||||
|
@ -241,6 +241,10 @@ the `-p 9999:9999` port mapping on the docker container to adjust for this.
|
||||
- `contractinfo` - Hex encoded contract info
|
||||
- `decodeoffer` `offer` - Decodes an offer message into json
|
||||
- `offer` - Hex encoded dlc offer message
|
||||
- `decodeaccept` `accept` - Decodes an accept message into json
|
||||
- `accept` - Hex encoded dlc accept message
|
||||
- `decodesign` `sign` - Decodes a sign message into json
|
||||
- `sign` - Hex encoded dlc sign message
|
||||
- `decodeannouncement` `announcement` - Decodes an oracle announcement message into json
|
||||
- `announcement` - Hex encoded oracle announcement message
|
||||
- `decodeattestments` `attestments` - Decodes an oracle attestments message into json
|
||||
|
@ -99,4 +99,103 @@ object DLCTestUtil {
|
||||
val remoteInfo = info.flip(totalCollateral.satoshis)
|
||||
(info, remoteInfo)
|
||||
}
|
||||
|
||||
val acceptHex: String =
|
||||
"a71cd1dc7596d2a2f14a2542f2b7e563c149c910ba2238b59532b9fc1ebf6f8465f1000000000000ea60037dbfd3eb9296d1bd537c4008794989893821d48a163b0f3b7b01433599e8121100160014cb62b501146622502837f5cd898a657feba867eb9701e48dde0387770001fda714f4e2f7667f1f20d72700de02000000000101433df2df0297e1de67283fd8d369a16be5179f3a696fe36bf601337426408af50100000000000000000280f0fa0200000000160014d431e458cc852e7f2f21a6055751b5d2f30b7bcac190f30200000000160014aba424ac1cdf6c4ff53dcc76c1458c2e8bb7c71702473044022049911e914325d2c21f1f7a52d0bef9f50362cf130a87d73a30e61863fa72582502205338e9fa57b6172c821cb9e2530e7b0bf27812e2110ffa7adf277da1be31872d012103cf091ac1820aabeb4399d63bacb5b1c58310166a8b9466bc5efb4dbb678aba1e0000000000000000ffffffff006b0000001600145097a3a31e88036a7396728b6e3ea47c70780f8db68e98eec3ad4f26fda716fd01e70302834a87e2019a7c431db58235abd00ce62ca5a36e8b5e60bc6dd895045e9d936302e00d2ff673cf117f8bc3e6cbbbdc9efeb6b641d55c32c58ca46422c7279db2a3d07fa999360ba675ad6d342d21997e8644f60509a106df667f85f948f1d73ca5de082db23a50f07d9180e253bd8879567d1e4110f07de6f57ef75cf32206edc4d0656f6dcd738f0301d4baf73182aac102a1917b9688dcb7b74bcdcc85374b9203e9a2eb7600712af2236b80ebceb644d5bad65f3ccbcdcf8f2a649a48fd8a3b72023a6a694000be8df5519f7d5e11414b73274377300655be6ad1cc0da6c0eedf1fe36e4e82f3125c8ba40a1bcda444b4ec528d1674e6cee5e61d71f92586212ab2b5afdc90fe4744db5c9873eb240dfaf1952b41b3f3fa7e7a86def2a691bcbae5ad968459f712041a6ea8f39314c19545f8b5b501250aae6d09d0cfff7d9f79f403293e081859a95c05ab7a6fb6b5e960c928a199b89166188d4db5c4546fa8baef03a08004a37d041bcb10ceb94d3797814789ac192c2c79d9ddd41397cb0d0e6af84fcb15cdc885df164aaa81e2dbc95af76d4ca71017b81b2b20307c4a067d844c427f1e5c06da2082911203f61bc44d5983a203861f06e48241d407d56b72bb612792014ff77d8e2288699225241ca75d35823e563f71118851bd5f4f1aebf94c76d380d9f9315a822ef2054c1e234def6087ec7504e7423d51adcf6ed199a317199dbb561ee6ba7ecc736c5cd746fc17fa3609c6b0e1f19c4323d9e77ac67d92fdd82600"
|
||||
|
||||
val expectedAcceptJsonString: String = {
|
||||
s"""
|
||||
|{
|
||||
| "result":
|
||||
| {
|
||||
| "temporaryContractId": "d1dc7596d2a2f14a2542f2b7e563c149c910ba2238b59532b9fc1ebf6f8465f1",
|
||||
| "acceptCollateral": 60000,
|
||||
| "fundingPubkey": "037dbfd3eb9296d1bd537c4008794989893821d48a163b0f3b7b01433599e81211",
|
||||
| "payoutSpk": "0014cb62b501146622502837f5cd898a657feba867eb",
|
||||
| "payoutSerialId": "10881229472670123895",
|
||||
| "fundingInputs": [
|
||||
| {
|
||||
| "inputSerialId": "16354653267988371239",
|
||||
| "prevTx": "02000000000101433df2df0297e1de67283fd8d369a16be5179f3a696fe36bf601337426408af50100000000000000000280f0fa0200000000160014d431e458cc852e7f2f21a6055751b5d2f30b7bcac190f30200000000160014aba424ac1cdf6c4ff53dcc76c1458c2e8bb7c71702473044022049911e914325d2c21f1f7a52d0bef9f50362cf130a87d73a30e61863fa72582502205338e9fa57b6172c821cb9e2530e7b0bf27812e2110ffa7adf277da1be31872d012103cf091ac1820aabeb4399d63bacb5b1c58310166a8b9466bc5efb4dbb678aba1e00000000",
|
||||
| "prevTxVout": 0,
|
||||
| "sequence": 4294967295,
|
||||
| "maxWitnessLen": 107,
|
||||
| "redeemScript": ""
|
||||
| }
|
||||
| ],
|
||||
| "changeSpk": "00145097a3a31e88036a7396728b6e3ea47c70780f8d",
|
||||
| "changeSerialId": "13154619712848351014",
|
||||
| "cetAdaptorSignatures": {
|
||||
| "ecdsaAdaptorSignatures": [
|
||||
| {
|
||||
| "signature": "02834a87e2019a7c431db58235abd00ce62ca5a36e8b5e60bc6dd895045e9d936302e00d2ff673cf117f8bc3e6cbbbdc9efeb6b641d55c32c58ca46422c7279db2a3d07fa999360ba675ad6d342d21997e8644f60509a106df667f85f948f1d73ca5de082db23a50f07d9180e253bd8879567d1e4110f07de6f57ef75cf32206edc4d0656f6dcd738f0301d4baf73182aac102a1917b9688dcb7b74bcdcc85374b92"
|
||||
| },
|
||||
| {
|
||||
| "signature": "03e9a2eb7600712af2236b80ebceb644d5bad65f3ccbcdcf8f2a649a48fd8a3b72023a6a694000be8df5519f7d5e11414b73274377300655be6ad1cc0da6c0eedf1fe36e4e82f3125c8ba40a1bcda444b4ec528d1674e6cee5e61d71f92586212ab2b5afdc90fe4744db5c9873eb240dfaf1952b41b3f3fa7e7a86def2a691bcbae5ad968459f712041a6ea8f39314c19545f8b5b501250aae6d09d0cfff7d9f79f4"
|
||||
| },
|
||||
| {
|
||||
| "signature": "03293e081859a95c05ab7a6fb6b5e960c928a199b89166188d4db5c4546fa8baef03a08004a37d041bcb10ceb94d3797814789ac192c2c79d9ddd41397cb0d0e6af84fcb15cdc885df164aaa81e2dbc95af76d4ca71017b81b2b20307c4a067d844c427f1e5c06da2082911203f61bc44d5983a203861f06e48241d407d56b72bb612792014ff77d8e2288699225241ca75d35823e563f71118851bd5f4f1aebf94c"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "refundSignature": "3044022076d380d9f9315a822ef2054c1e234def6087ec7504e7423d51adcf6ed199a3170220199dbb561ee6ba7ecc736c5cd746fc17fa3609c6b0e1f19c4323d9e77ac67d92",
|
||||
| "negotiationFields": null
|
||||
| },
|
||||
|
|
||||
| "error": null
|
||||
|}
|
||||
|""".stripMargin
|
||||
}
|
||||
|
||||
val expectedAccept: ujson.Value = ujson.read(expectedAcceptJsonString)
|
||||
|
||||
val signHex =
|
||||
"a71eafcd7e786c0b9085784a6d063c7f4e7291784f9be3ba23cd8734559040fd2202fda716fd02890402feee4c75948830549fd19efd93cd4e00d4f538041ecf2f2cb6820c78c0a57fc9034d9ce5849e0abe235b8c3137506745508aa17c7a3064ec4172e76c88e66ca27257c5ec09f99201c9bc95b8ab345aff9b32b89c328d21a6ca5553f287a650320162381ef95042d9ac57f66f39dc6904f17a472671d3828f75ef29fbddcd31119b69adb216dac9b5960b91b3e3d83b9310484ef667d19f4bed01964ff063a2acbd025e840169038f0d046cc5005d9d622fd19ec2dd84d15a022f3eff4a781c6f404602cf8ec975191b73ecc3944786f5cca2a01ba3e71bbde9ea6932083c23591dfb6e3e06489cde6415c39cc9e187283f7a9b76227b157572dc62f1a5b130b4fc6b68c14ea07deddb2865d634a244839a87f158145c59d9aecb51b082c3a2ef0cb0201bc65252a3876f7253855ce4d3e72cd650bc275dd878f920162af74865b0346b03ea132cd20738f1a6640f98dc5664d12952e000feb69bbb3c4929c9054b3ca965030b788e83098f906cd3b088ad297e8149d08eb02442f42bd2b9e4455d5a19a96fd329625e1f1d0db9b9f625a6242f1fc53f56ec8090575c704e364518bdf7d690386d0f4a7bfea6c263c5fbc91631b0f0323a92c51f43f3228c9649c5441b338f2e37cbad0d10ce0d80429e2a6a528e4a0e9700188b86c267246b5049ce7da03102c2ec44af74653bdad7db89a38ab61d3dabf0646acdfab1bd5906d4a75f8d7a0c03051281626d4c8c84a5b7d09717c69f1c5340300be5ef6d94a4efe4d1baebbf820f8891a3b86d0f4a9a42d3fa0a44f7d711a5e65cc887b0424530e9b7e49f8d3a21d89762d535c7f121bc057b01b67372ea19762fad714580767ea6a091771808c3806b273382e0792573f624a90e15004a3b852e627f422c07209fd876c3816905d4dcc449db1a5997b82f2aabaffb3414ad1e10c159fc3fcbd6dab121a3cb9837583d39f66aa347a8170dba12cf88102997f460bb27d70365f7f85cd4ce5ee2fda71870000100020047304402204bbe45fd65402ad89784062c2af0f0c88a55f1de4509e4491f7933ada30fbab102207144fe9b8d621d2bef5c226d6f2f8ff43548f4c0bb9ea221a0c2a034a069c74f01002103bdb496d31a30d8e87ab7767fd26bfdfa7f6d06a0cfaea082a91af1ae1814f251"
|
||||
|
||||
val expectedSignJsonString: String = {
|
||||
s"""
|
||||
|{
|
||||
| "result":
|
||||
|
|
||||
|{
|
||||
| "contractId": "afcd7e786c0b9085784a6d063c7f4e7291784f9be3ba23cd8734559040fd2202",
|
||||
| "cetAdaptorSignatures": {
|
||||
| "ecdsaAdaptorSignatures": [
|
||||
| {
|
||||
| "signature": "02feee4c75948830549fd19efd93cd4e00d4f538041ecf2f2cb6820c78c0a57fc9034d9ce5849e0abe235b8c3137506745508aa17c7a3064ec4172e76c88e66ca27257c5ec09f99201c9bc95b8ab345aff9b32b89c328d21a6ca5553f287a650320162381ef95042d9ac57f66f39dc6904f17a472671d3828f75ef29fbddcd31119b69adb216dac9b5960b91b3e3d83b9310484ef667d19f4bed01964ff063a2acbd"
|
||||
| },
|
||||
| {
|
||||
| "signature": "025e840169038f0d046cc5005d9d622fd19ec2dd84d15a022f3eff4a781c6f404602cf8ec975191b73ecc3944786f5cca2a01ba3e71bbde9ea6932083c23591dfb6e3e06489cde6415c39cc9e187283f7a9b76227b157572dc62f1a5b130b4fc6b68c14ea07deddb2865d634a244839a87f158145c59d9aecb51b082c3a2ef0cb0201bc65252a3876f7253855ce4d3e72cd650bc275dd878f920162af74865b0346b"
|
||||
| },
|
||||
| {
|
||||
| "signature": "03ea132cd20738f1a6640f98dc5664d12952e000feb69bbb3c4929c9054b3ca965030b788e83098f906cd3b088ad297e8149d08eb02442f42bd2b9e4455d5a19a96fd329625e1f1d0db9b9f625a6242f1fc53f56ec8090575c704e364518bdf7d690386d0f4a7bfea6c263c5fbc91631b0f0323a92c51f43f3228c9649c5441b338f2e37cbad0d10ce0d80429e2a6a528e4a0e9700188b86c267246b5049ce7da031"
|
||||
| },
|
||||
| {
|
||||
| "signature": "02c2ec44af74653bdad7db89a38ab61d3dabf0646acdfab1bd5906d4a75f8d7a0c03051281626d4c8c84a5b7d09717c69f1c5340300be5ef6d94a4efe4d1baebbf820f8891a3b86d0f4a9a42d3fa0a44f7d711a5e65cc887b0424530e9b7e49f8d3a21d89762d535c7f121bc057b01b67372ea19762fad714580767ea6a091771808c3806b273382e0792573f624a90e15004a3b852e627f422c07209fd876c38169"
|
||||
| }
|
||||
| ]
|
||||
| },
|
||||
| "refundSignature": "3044022005d4dcc449db1a5997b82f2aabaffb3414ad1e10c159fc3fcbd6dab121a3cb98022037583d39f66aa347a8170dba12cf88102997f460bb27d70365f7f85cd4ce5ee2",
|
||||
| "fundingSignatures": {
|
||||
| "fundingSignatures": [
|
||||
| {
|
||||
| "witnessElements": [
|
||||
| {
|
||||
| "witness": "304402204bbe45fd65402ad89784062c2af0f0c88a55f1de4509e4491f7933ada30fbab102207144fe9b8d621d2bef5c226d6f2f8ff43548f4c0bb9ea221a0c2a034a069c74f01"
|
||||
| },
|
||||
| {
|
||||
| "witness": "03bdb496d31a30d8e87ab7767fd26bfdfa7f6d06a0cfaea082a91af1ae1814f251"
|
||||
| }
|
||||
| ]
|
||||
| }
|
||||
| ]
|
||||
| }
|
||||
| },
|
||||
|
|
||||
| "error": null
|
||||
|}
|
||||
|""".stripMargin
|
||||
}
|
||||
|
||||
val expectedSign: ujson.Value = ujson.read(expectedSignJsonString)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user