Skip to content
This repository was archived by the owner on Apr 13, 2023. It is now read-only.

Commit 0b21c69

Browse files
authored
Add muxed_id support for JSON responses (#470)
1 parent fe346d6 commit 0b21c69

37 files changed

+398
-354
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ As this project is pre 1.0, breaking changes may happen for minor version bumps.
88
- Added the ability to list operations associated with a claimable balance.
99
- Added the ability to list transactions associated with a claimable balance.
1010

11+
### Breaking
12+
13+
- Many instances of `PublicKey` fields on response classes have been upgraded to `AccountId`s to reflect Horizon's
14+
improved support for multiplexed addresses. Changes are present in Operation, Transaction and Effect classes.
15+
1116
## 0.20.0
1217

1318
- Updated for core protocol v17/CAP35:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![Build](https://github.com/Synesso/scala-stellar-sdk/workflows/Build/badge.svg?branch=master)](https://github.com/Synesso/scala-stellar-sdk/actions/workflows/scala.yml)
44
[![Coverage](https://img.shields.io/codecov/c/gh/Synesso/scala-stellar-sdk.svg)](https://codecov.io/gh/Synesso/scala-stellar-sdk)
55
[![Issues](https://img.shields.io/github/issues/Synesso/scala-stellar-sdk.svg)](https://github.com/Synesso/scala-stellar-sdk/issues)
6-
![Supports Stellar Horizon v2.2.0](https://img.shields.io/badge/Horizon-v2.2.0-blue.svg)
6+
![Supports Stellar Horizon v2.6.1](https://img.shields.io/badge/Horizon-v2.6.1-blue.svg)
77
![Supports Stellar Core v17](https://img.shields.io/badge/Core-v17-blue.svg)
88
[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-brightgreen.svg?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)
99

src/it/scala/stellar/sdk/LocalNetworkIntegrationSpec.scala

Lines changed: 50 additions & 50 deletions
Large diffs are not rendered by default.

src/it/scala/stellar/sdk/TestAccounts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class TestAccounts(quantity: Int = 20) extends LazyLogging {
6464
val ops = for {
6565
friendBotAccountId <- friendBot.get.map(_.get)
6666
allKps <- unused.get.flatMap(kps => borrowed.get.map(_ ++ kps))
67-
allOps = allKps.map { kp => AccountMergeOperation(friendBotAccountId, Some(kp)) }
67+
allOps = allKps.map { kp => AccountMergeOperation(friendBotAccountId, Some(kp.toAccountId)) }
6868
} yield allKps.zip(allOps).toMap
6969
val opsMap = ops.unsafeRunSync()
7070
val response = for {

src/main/scala/stellar/sdk/auth/AuthChallenger.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ class AuthChallenger(
4040
WriteDataOperation(
4141
name = s"$homeDomain auth",
4242
value = generateDataKey,
43-
sourceAccount = Some(accountId.publicKey)
43+
sourceAccount = Some(accountId)
4444
),
4545
WriteDataOperation(
4646
name = "web_auth_domain",
4747
value = webAuthDomain.getBytes(Charsets.UTF_8),
48-
sourceAccount = Some(accountId.publicKey)
48+
sourceAccount = Some(accountId)
4949
)
5050
),
5151
timeBounds = TimeBounds.timeout(timeout, clock),

src/main/scala/stellar/sdk/auth/Challenge.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ case class Challenge(
7575

7676
private def checkSignedByClient(answer: SignedTransaction): Option[ChallengeResult] = {
7777
// FIXME - deal with 0 or multi operations. Deal with no source account.
78-
if (answer.verify(transaction.operations.head.sourceAccount.get)) None
78+
if (answer.verify(transaction.operations.head.sourceAccount.get.publicKey)) None
7979
else Some(ChallengeNotSignedByClient)
8080
}
8181

src/main/scala/stellar/sdk/model/StrKey.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
package stellar.sdk.model
22

3-
import java.nio.ByteBuffer
43
import org.apache.commons.codec.binary.Base32
4+
import org.json4s.Formats
5+
import org.json4s.JsonAST.JObject
56
import org.stellar.xdr.{AccountID, CryptoKeyType, MuxedAccount, PublicKeyType, SignerKey, SignerKeyType, Uint256, Uint64, PublicKey => XPublicKey}
67
import stellar.sdk.model.StrKey.codec
78
import stellar.sdk.util.ByteArrays
89
import stellar.sdk.{KeyPair, PublicKey}
910

10-
import scala.util.Try
11+
import java.nio.ByteBuffer
1112

1213

1314
/**
@@ -77,6 +78,14 @@ object SignerStrKey {
7778
}
7879

7980
object AccountId {
81+
82+
/** Extract an account id from JSON */
83+
def parse(o: JObject, baseKeyName: String)(implicit formats: Formats): AccountId = {
84+
val pk = KeyPair.fromAccountId((o \ baseKeyName).extract[String])
85+
val multiplexedId = (o \ s"${baseKeyName}_muxed_id").extractOpt[String].map(_.toLong)
86+
AccountId(pk.publicKey, multiplexedId)
87+
}
88+
8089
def decodeXdr(accountId: AccountID): AccountId =
8190
AccountId(KeyPair.fromPublicKey(accountId.getAccountID.getEd25519.getUint256).publicKey)
8291

src/main/scala/stellar/sdk/model/op/Operation.scala

Lines changed: 52 additions & 44 deletions
Large diffs are not rendered by default.

src/main/scala/stellar/sdk/model/response/EffectResponse.scala

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,53 +13,53 @@ sealed trait EffectResponse {
1313
val createdAt: ZonedDateTime
1414
}
1515

16-
case class EffectAccountCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, startingBalance: NativeAmount) extends EffectResponse
16+
case class EffectAccountCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId, startingBalance: NativeAmount) extends EffectResponse
1717

18-
case class EffectAccountCredited(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, amount: Amount) extends EffectResponse
18+
case class EffectAccountCredited(id: String, createdAt: ZonedDateTime, accountId: AccountId, amount: Amount) extends EffectResponse
1919

20-
case class EffectAccountDebited(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, amount: Amount) extends EffectResponse
20+
case class EffectAccountDebited(id: String, createdAt: ZonedDateTime, accountId: AccountId, amount: Amount) extends EffectResponse
2121

22-
case class EffectAccountInflationDestinationUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
22+
case class EffectAccountInflationDestinationUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
2323

24-
case class EffectAccountRemoved(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
24+
case class EffectAccountRemoved(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
2525

26-
case class EffectAccountSponsorshipCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
26+
case class EffectAccountSponsorshipCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
2727

28-
case class EffectAccountThresholdsUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, thresholds: Thresholds) extends EffectResponse
28+
case class EffectAccountThresholdsUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId, thresholds: Thresholds) extends EffectResponse
2929

30-
case class EffectAccountHomeDomainUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, domain: String) extends EffectResponse
30+
case class EffectAccountHomeDomainUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId, domain: String) extends EffectResponse
3131

32-
case class EffectAccountFlagsUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
32+
case class EffectAccountFlagsUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
3333

34-
case class EffectDataCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
34+
case class EffectDataCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
3535

36-
case class EffectDataRemoved(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
36+
case class EffectDataRemoved(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
3737

38-
case class EffectDataUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps) extends EffectResponse
38+
case class EffectDataUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId) extends EffectResponse
3939

40-
case class EffectSequenceBumped(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, newSeq: Long) extends EffectResponse
40+
case class EffectSequenceBumped(id: String, createdAt: ZonedDateTime, accountId: AccountId, newSeq: Long) extends EffectResponse
4141

42-
case class EffectSignerCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, weight: Short, publicKey: String) extends EffectResponse
42+
case class EffectSignerCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId, weight: Short, publicKey: String) extends EffectResponse
4343

44-
case class EffectSignerUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, weight: Short, publicKey: String) extends EffectResponse
44+
case class EffectSignerUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId, weight: Short, publicKey: String) extends EffectResponse
4545

46-
case class EffectSignerRemoved(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, publicKey: String) extends EffectResponse
46+
case class EffectSignerRemoved(id: String, createdAt: ZonedDateTime, accountId: AccountId, publicKey: String) extends EffectResponse
4747

48-
case class EffectSignerSponsorshipCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, signer: PublicKeyOps, newSponsor: PublicKeyOps) extends EffectResponse
48+
case class EffectSignerSponsorshipCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId, signer: PublicKeyOps, newSponsor: PublicKeyOps) extends EffectResponse
4949

50-
case class EffectSignerSponsorshipRemoved(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, signer: PublicKeyOps, formerSponsor: PublicKeyOps) extends EffectResponse
50+
case class EffectSignerSponsorshipRemoved(id: String, createdAt: ZonedDateTime, accountId: AccountId, signer: PublicKeyOps, formerSponsor: PublicKeyOps) extends EffectResponse
5151

52-
case class EffectSignerSponsorshipUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, signer: PublicKeyOps, formerSponsor: PublicKeyOps, newSponsor: PublicKeyOps) extends EffectResponse
52+
case class EffectSignerSponsorshipUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId, signer: PublicKeyOps, formerSponsor: PublicKeyOps, newSponsor: PublicKeyOps) extends EffectResponse
5353

54-
case class EffectTrustLineCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, limit: IssuedAmount) extends EffectResponse {
54+
case class EffectTrustLineCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId, limit: IssuedAmount) extends EffectResponse {
5555
val asset: NonNativeAsset = limit.asset
5656
}
5757

58-
case class EffectTrustLineUpdated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, limit: IssuedAmount) extends EffectResponse {
58+
case class EffectTrustLineUpdated(id: String, createdAt: ZonedDateTime, accountId: AccountId, limit: IssuedAmount) extends EffectResponse {
5959
val asset: NonNativeAsset = limit.asset
6060
}
6161

62-
case class EffectTrustLineRemoved(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, asset: NonNativeAsset) extends EffectResponse
62+
case class EffectTrustLineRemoved(id: String, createdAt: ZonedDateTime, accountId: AccountId, asset: NonNativeAsset) extends EffectResponse
6363

6464
case class EffectTrustLineAuthorized(id: String, createdAt: ZonedDateTime, trustor: PublicKeyOps, asset: NonNativeAsset) extends EffectResponse
6565

@@ -69,9 +69,9 @@ case class EffectTrustLineDeauthorized(id: String, createdAt: ZonedDateTime, tru
6969

7070
case class EffectTrustLineFlagsUpdated(id: String, createdAt: ZonedDateTime, trustor: PublicKey, asset: NonNativeAsset, authorized: Boolean, authorizedToMaintainLiabilities: Boolean, clawbackEnabled: Boolean) extends EffectResponse
7171

72-
case class EffectTrustLineSponsorshipCreated(id: String, createdAt: ZonedDateTime, account: PublicKeyOps, asset: NonNativeAsset, sponsor: PublicKeyOps) extends EffectResponse
72+
case class EffectTrustLineSponsorshipCreated(id: String, createdAt: ZonedDateTime, accountId: AccountId, asset: NonNativeAsset, sponsor: PublicKeyOps) extends EffectResponse
7373

74-
case class EffectTrade(id: String, createdAt: ZonedDateTime, offerId: Long, buyer: PublicKeyOps, bought: Amount, seller: PublicKeyOps, sold: Amount) extends EffectResponse
74+
case class EffectTrade(id: String, createdAt: ZonedDateTime, offerId: Long, buyer: AccountId, bought: Amount, seller: AccountId, sold: Amount) extends EffectResponse
7575

7676
case class EffectClaimableBalanceClawedBack(id: String, createdAt: ZonedDateTime, balanceId: Long) extends EffectResponse
7777

@@ -80,7 +80,9 @@ case class UnrecognisedEffect(id: String, createdAt: ZonedDateTime, json: String
8080
object EffectResponseDeserializer extends ResponseParser[EffectResponse]({ o: JObject =>
8181
implicit val formats = DefaultFormats
8282

83-
def account(accountKey: String = "account") = KeyPair.fromAccountId((o \ accountKey).extract[String])
83+
def pubKey(accountKey: String): PublicKey = KeyPair.fromAccountId((o \ accountKey).extract[String])
84+
85+
def account(accountKey: String = "account"): AccountId = AccountId.parse(o, accountKey)
8486

8587
def asset(prefix: String = "", issuerKey: String = "asset_issuer"): Asset = {
8688
def assetCode = (o \ s"${prefix}asset_code").extract[String]
@@ -153,35 +155,35 @@ object EffectResponseDeserializer extends ResponseParser[EffectResponse]({ o: JO
153155
case "signer_created" => EffectSignerCreated(id, createdAt, account(), weight, (o \ "public_key").extract[String])
154156
case "signer_removed" => EffectSignerRemoved(id, createdAt, account(), (o \ "public_key").extract[String])
155157
case "signer_sponsorship_created" => EffectSignerSponsorshipCreated(id, createdAt, account(),
156-
signer = account("signer"),
157-
newSponsor = account("sponsor")
158+
signer = pubKey("signer"),
159+
newSponsor = pubKey("sponsor")
158160
)
159161
case "signer_sponsorship_removed" => EffectSignerSponsorshipRemoved(id, createdAt, account(),
160-
signer = account("signer"),
161-
formerSponsor = account("former_sponsor")
162+
signer = pubKey("signer"),
163+
formerSponsor = pubKey("former_sponsor")
162164
)
163165
case "signer_sponsorship_updated" => EffectSignerSponsorshipUpdated(id, createdAt, account(),
164-
signer = account("signer"),
165-
formerSponsor = account("former_sponsor"),
166-
newSponsor = account("new_sponsor")
166+
signer = pubKey("signer"),
167+
formerSponsor = pubKey("former_sponsor"),
168+
newSponsor = pubKey("new_sponsor")
167169
)
168170
case "signer_updated" => EffectSignerUpdated(id, createdAt, account(), weight, (o \ "public_key").extract[String])
169171
case "trade" => EffectTrade(id, createdAt, (o \ "offer_id").extract[String].toLong, account(), amount("bought_"), account("seller"), amount("sold_"))
170-
case "trustline_authorized" => EffectTrustLineAuthorized(id, createdAt, account("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
171-
case "trustline_authorized_to_maintain_liabilities" => EffectTrustLineAuthorizedToMaintainLiabilities(id, createdAt, account("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
172+
case "trustline_authorized" => EffectTrustLineAuthorized(id, createdAt, pubKey("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
173+
case "trustline_authorized_to_maintain_liabilities" => EffectTrustLineAuthorizedToMaintainLiabilities(id, createdAt, pubKey("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
172174
case "trustline_created" => EffectTrustLineCreated(id, createdAt, account(), amount(key = "limit").asInstanceOf[IssuedAmount])
173-
case "trustline_deauthorized" => EffectTrustLineDeauthorized(id, createdAt, account("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
175+
case "trustline_deauthorized" => EffectTrustLineDeauthorized(id, createdAt, pubKey("trustor"), asset(issuerKey = "account").asInstanceOf[NonNativeAsset])
174176
case "trustline_flags_updated" => EffectTrustLineFlagsUpdated(
175177
id = id,
176178
createdAt = createdAt,
177-
trustor = account("trustor"),
179+
trustor = pubKey("trustor"),
178180
asset = asset().asInstanceOf[NonNativeAsset],
179181
authorized = maybeBool("authorized_flag"),
180182
authorizedToMaintainLiabilities = maybeBool("authorized_to_maintain_liabilites"),
181183
clawbackEnabled = maybeBool("clawback_enabled_flag")
182184
)
183185
case "trustline_removed" => EffectTrustLineRemoved(id, createdAt, account(), asset().asInstanceOf[NonNativeAsset])
184-
case "trustline_sponsorship_created" => EffectTrustLineSponsorshipCreated(id, createdAt, account(), issuedAsset(), account("sponsor"))
186+
case "trustline_sponsorship_created" => EffectTrustLineSponsorshipCreated(id, createdAt, account(), issuedAsset(), pubKey("sponsor"))
185187
case "trustline_sponsorship_removed" => UnrecognisedEffect(id, createdAt, JsonMethods.compact(JsonMethods.render(o)))
186188
case "trustline_sponsorship_updated" => UnrecognisedEffect(id, createdAt, JsonMethods.compact(JsonMethods.render(o)))
187189
case "trustline_updated" => EffectTrustLineUpdated(id, createdAt, account(), amount(key = "limit").asInstanceOf[IssuedAmount])

src/main/scala/stellar/sdk/model/result/TransactionHistory.scala

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,45 @@
11
package stellar.sdk.model.result
22

3-
import java.time.ZonedDateTime
4-
53
import okio.ByteString
64
import org.json4s.JsonAST.JObject
75
import org.json4s.{DefaultFormats, Formats}
6+
import stellar.sdk.Network
87
import stellar.sdk.model._
98
import stellar.sdk.model.ledger.{LedgerEntryChange, LedgerEntryChanges, TransactionLedgerEntries}
109
import stellar.sdk.model.response.ResponseParser
11-
import stellar.sdk.util.ByteArrays.base64
12-
import stellar.sdk.{KeyPair, Network, PublicKey}
1310

11+
import java.time.ZonedDateTime
1412
import scala.util.Try
1513

1614
/**
17-
* A transaction that has been included in the ledger sometime in the past.
18-
*/
19-
case class TransactionHistory(hash: String, ledgerId: Long, createdAt: ZonedDateTime, account: PublicKey,
20-
sequence: Long, maxFee: NativeAmount, feeCharged: NativeAmount, operationCount: Int,
21-
memo: Memo, signatures: Seq[String], envelopeXDR: String, resultXDR: String,
22-
resultMetaXDR: String, feeMetaXDR: String, validAfter: Option[ZonedDateTime],
23-
validBefore: Option[ZonedDateTime], feeBump: Option[FeeBumpHistory]) {
15+
* A transaction that has been included in the ledger sometime in the past.
16+
*/
17+
case class TransactionHistory(
18+
hash: String,
19+
ledgerId: Long,
20+
createdAt: ZonedDateTime,
21+
account: AccountId,
22+
sequence: Long,
23+
maxFee: NativeAmount,
24+
feeCharged: NativeAmount,
25+
operationCount: Int,
26+
memo: Memo,
27+
signatures: Seq[String],
28+
envelopeXDR: String,
29+
resultXDR: String,
30+
resultMetaXDR: String,
31+
feeMetaXDR: String,
32+
validAfter: Option[ZonedDateTime],
33+
validBefore: Option[ZonedDateTime],
34+
feeBump: Option[FeeBumpHistory]
35+
) {
2436

2537
lazy val result: TransactionResult = TransactionResult.decodeXdrString(resultXDR)
2638

2739
def ledgerEntries: TransactionLedgerEntries = TransactionLedgerEntries.decodeXDR(resultMetaXDR)
40+
2841
def feeLedgerEntries: Seq[LedgerEntryChange] = LedgerEntryChanges.decodeXDR(feeMetaXDR)
42+
2943
def transaction(network: Network): Transaction = Transaction.decodeXdrString(envelopeXDR)(network)
3044

3145
@deprecated("Replaced by `feeCharged`", "v0.7.2")
@@ -48,12 +62,11 @@ object TransactionHistoryDeserializer extends {
4862
maxFee <- (o \ "inner_transaction" \ "max_fee").extractOpt[Int].map(NativeAmount(_))
4963
signatures <- (o \ "inner_transaction" \ "signatures").extractOpt[List[String]]
5064
} yield (hash, maxFee, signatures)
51-
5265
TransactionHistory(
5366
hash = inner.map(_._1).getOrElse(hash),
5467
ledgerId = (o \ "ledger").extract[Long],
5568
createdAt = ZonedDateTime.parse((o \ "created_at").extract[String]),
56-
account = KeyPair.fromAccountId((o \ "source_account").extract[String]),
69+
account = AccountId.parse(o, "source_account"),
5770
sequence = (o \ "source_account_sequence").extract[String].toLong,
5871
maxFee = inner.map(_._2).getOrElse(maxFee),
5972
feeCharged = NativeAmount((o \ "fee_charged").extract[String].toInt),

0 commit comments

Comments
 (0)