-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ABW-3827] Resource view Pre-Authorization states #1377
Changes from 91 commits
2fcd3fb
ab48dba
4811e0c
24e8819
b30f519
3778a7f
957b8a3
bf90c75
6cdea3c
4dd4d35
69af0a6
c001881
a7711f8
c1ef09d
78924ad
a24e6ae
c49662f
58af003
68fec2b
4287c70
349c7dc
f406c97
1656031
76b65f4
650637e
c67c60f
6b89519
955c46f
5e5af4a
7fe96f2
5a50a88
8de0e95
9082805
e93cad5
c26ebef
72f3042
6ce9605
4ef9e88
38f4fd1
617c6eb
2af392c
5e63a95
ad311d9
f594f53
4ab916d
0901430
8c8e5ec
aa3cdd5
0cb5347
3b2f76e
7852725
d65e57d
dbba2c7
d692742
6ccdbdf
c785117
7ccad4b
b671c5f
0a57abe
37143e0
dac222a
6c3fef0
934974c
95ab08b
567943a
e9b81fc
c950cc0
06599e5
5776e0b
50f640c
29b100b
9cdf6db
0be24a3
7b4deac
de06242
3b86b48
30ced3d
1c13e0b
ee7d68c
eb3b78a
85b7b55
2917eb1
dd60106
bfec7d1
7fc86e7
f5c60a5
09d4db2
f2ddf2b
1a80281
433f6a5
d054493
30a7536
9ad60a0
7717550
bfd22fe
a8fb7ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -176,7 +176,7 @@ extension AccountPortfoliosClient.State { | |
|
||
// MARK: - Stake and Pool details handling | ||
extension AccountPortfoliosClient.State { | ||
func calculateWorth(_ gateway: Gateway) -> (ResourceAddress, ResourceAmount) -> FiatWorth? { | ||
func calculateWorth(_ gateway: Gateway) -> (ResourceAddress, ExactResourceAmount) -> FiatWorth? { | ||
{ resourceAddress, amount in | ||
let worth: FiatWorth.Worth? = { | ||
guard case let .success(tokenPrices) = self.tokenPrices else { | ||
|
@@ -247,62 +247,90 @@ private extension AccountPortfoliosClient.AccountPortfolio { | |
} | ||
} | ||
|
||
mutating func updateFiatWorth(_ change: (ResourceAddress, ResourceAmount) -> FiatWorth?) { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ExactResourceAmount) -> FiatWorth?) { | ||
account.fungibleResources.updateFiatWorth(change) | ||
stakeUnitDetails.mutateValue { $0.updateFiatWorth(change) } | ||
poolUnitDetails.mutateValue { $0.updateFiatWorth(change) } | ||
} | ||
} | ||
|
||
extension ResourceAmount { | ||
mutating func updateFiatWorth(resourceAddress: ResourceAddress, change: (ResourceAddress, ExactResourceAmount) -> FiatWorth?) { | ||
switch self { | ||
case let .exact(exactAmount): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor, you could probably use |
||
var updatedAmount = exactAmount | ||
updatedAmount.fiatWorth = change(resourceAddress, exactAmount) | ||
self = .exact(updatedAmount) | ||
case let .atLeast(exactAmount): | ||
var updatedAmount = exactAmount | ||
updatedAmount.fiatWorth = change(resourceAddress, exactAmount) | ||
self = .atLeast(updatedAmount) | ||
case let .atMost(exactAmount): | ||
var updatedAmount = exactAmount | ||
updatedAmount.fiatWorth = change(resourceAddress, exactAmount) | ||
self = .atMost(updatedAmount) | ||
case let .between(minExactAmount, maxExactAmount): | ||
var updatedMinAmount = minExactAmount | ||
updatedMinAmount.fiatWorth = change(resourceAddress, minExactAmount) | ||
var updatedMaxAmount = maxExactAmount | ||
updatedMaxAmount.fiatWorth = change(resourceAddress, maxExactAmount) | ||
self = .between(minimum: updatedMinAmount, maximum: updatedMaxAmount) | ||
case .unknown: | ||
return | ||
} | ||
} | ||
} | ||
|
||
private extension OnLedgerEntity.OwnedFungibleResources { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ResourceAmount) -> FiatWorth?) { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ExactResourceAmount) -> FiatWorth?) { | ||
xrdResource.mutate { resource in | ||
resource.amount.fiatWorth = change(.mainnetXRD, resource.amount) | ||
resource.amount.updateFiatWorth(resourceAddress: .mainnetXRD, change: change) | ||
} | ||
|
||
nonXrdResources.mutateAll { resource in | ||
resource.amount.fiatWorth = change(resource.resourceAddress, resource.amount) | ||
resource.amount.updateFiatWorth(resourceAddress: resource.resourceAddress, change: change) | ||
} | ||
|
||
nonXrdResources.sort(by: <) | ||
} | ||
} | ||
|
||
private extension MutableCollection where Element == OnLedgerEntitiesClient.OwnedResourcePoolDetails { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ResourceAmount) -> FiatWorth?) { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ExactResourceAmount) -> FiatWorth?) { | ||
mutateAll { detail in | ||
detail.xrdResource?.redemptionValue.mutate { amount in | ||
amount.fiatWorth = change(.mainnetXRD, amount) | ||
amount.updateFiatWorth(resourceAddress: .mainnetXRD, change: change) | ||
} | ||
|
||
detail.nonXrdResources.mutateAll { resource in | ||
let address = resource.resource.resourceAddress | ||
resource.redemptionValue.mutate { amount in | ||
amount.fiatWorth = change(address, amount) | ||
amount.updateFiatWorth(resourceAddress: address, change: change) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private extension MutableCollection where Element == OnLedgerEntitiesClient.OwnedStakeDetails { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ResourceAmount) -> FiatWorth?) { | ||
mutating func updateFiatWorth(_ change: (ResourceAddress, ExactResourceAmount) -> FiatWorth?) { | ||
mutateAll { detail in | ||
let xrdRedemptionValue = detail.xrdRedemptionValue | ||
detail.stakeUnitResource.mutate { | ||
$0.amount.fiatWorth = change( | ||
.mainnetXRD, | ||
.init( | ||
nominalAmount: xrdRedemptionValue, | ||
fiatWorth: $0.amount.fiatWorth | ||
var xrdRedemptionValue = detail.xrdRedemptionValue | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does not seem to be used. |
||
var stakeUnitResource = detail.stakeUnitResource | ||
stakeUnitResource.mutate { | ||
$0.amount.updateFiatWorth(resourceAddress: .mainnetXRD, change: { | ||
change( | ||
.mainnetXRD, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could be |
||
detail.xrdRedemptionValue(exactAmount: $1) | ||
) | ||
) | ||
}) | ||
} | ||
detail.stakeClaimTokens.mutate { | ||
$0.stakeClaims.mutateAll { token in | ||
token.claimAmount.fiatWorth = change(.mainnetXRD, token.claimAmount) | ||
} | ||
} | ||
detail.stakeUnitResource = stakeUnitResource | ||
} | ||
} | ||
} | ||
|
@@ -320,16 +348,16 @@ extension AccountPortfoliosClient.AccountPortfolio { | |
|
||
private extension OnLedgerEntity.OwnedFungibleResources { | ||
var fiatWorth: FiatWorth.Worth { | ||
let xrdFiatWorth = xrdResource?.amount.fiatWorth?.worth ?? .zero | ||
let nonXrdFiatWorth = nonXrdResources.compactMap(\.amount.fiatWorth?.worth).reduce(.zero, +) | ||
let xrdFiatWorth = xrdResource?.amount.exactAmount?.fiatWorth?.worth ?? .zero | ||
let nonXrdFiatWorth = nonXrdResources.compactMap(\.amount.exactAmount?.fiatWorth?.worth).reduce(.zero, +) | ||
return xrdFiatWorth + nonXrdFiatWorth | ||
} | ||
} | ||
|
||
private extension Collection<OnLedgerEntitiesClient.OwnedStakeDetails> { | ||
var fiatWorth: FiatWorth.Worth { | ||
reduce(.zero) { partialResult, stakeUnitDetail in | ||
let stakeUnitFiatWorth = stakeUnitDetail.stakeUnitResource?.amount.fiatWorth?.worth ?? .zero | ||
let stakeUnitFiatWorth = stakeUnitDetail.stakeUnitResource?.amount.exactAmount?.fiatWorth?.worth ?? .zero | ||
let stakeClaimsFiatWorth = stakeUnitDetail | ||
.stakeClaimTokens? | ||
.stakeClaims | ||
|
@@ -343,8 +371,8 @@ private extension Collection<OnLedgerEntitiesClient.OwnedStakeDetails> { | |
private extension Collection<OnLedgerEntitiesClient.OwnedResourcePoolDetails> { | ||
var fiatWorth: FiatWorth.Worth { | ||
reduce(.zero) { partialResult, poolUnitDetail in | ||
let xrdFiatWorth = poolUnitDetail.xrdResource?.redemptionValue?.fiatWorth?.worth ?? .zero | ||
let nonXrdFiatWorth = poolUnitDetail.nonXrdResources.compactMap(\.redemptionValue?.fiatWorth?.worth).reduce(.zero, +) | ||
let xrdFiatWorth = poolUnitDetail.xrdResource?.redemptionValue?.exactAmount?.fiatWorth?.worth ?? .zero | ||
let nonXrdFiatWorth = poolUnitDetail.nonXrdResources.compactMap(\.redemptionValue?.exactAmount?.fiatWorth?.worth).reduce(.zero, +) | ||
return partialResult + xrdFiatWorth + nonXrdFiatWorth | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,13 +25,10 @@ extension OnLedgerEntitiesClient { | |
resourceAssociatedDapps: InteractionReview.Sections.ResourceAssociatedDapps? = nil, | ||
networkID: NetworkID, | ||
defaultDepositGuarantee: Decimal192 = 1 | ||
) async throws -> ResourceBalance { | ||
) async throws -> KnownResourceBalance { | ||
let amount = resourceQuantifier.amount | ||
let resourceAddress = resource.resourceAddress | ||
|
||
@Dependency(\.resourcesVisibilityClient) var resourcesVisibilityClient | ||
let hiddenResources = try await resourcesVisibilityClient.getHidden() | ||
|
||
let guarantee: TransactionGuarantee? = { () -> TransactionGuarantee? in | ||
guard case let .predicted(predictedAmount) = resourceQuantifier else { return nil } | ||
let guaranteedAmount = defaultDepositGuarantee * predictedAmount.value | ||
|
@@ -44,11 +41,35 @@ extension OnLedgerEntitiesClient { | |
) | ||
}() | ||
|
||
return try await fungibleResourceBalance( | ||
resource, | ||
resourceAmount: .exact(.init(nominalAmount: amount)), | ||
guarantee: guarantee, | ||
networkID: networkID | ||
) | ||
} | ||
|
||
func fungibleResourceBalance( | ||
_ resource: OnLedgerEntity.Resource, | ||
resourceAmount: ResourceAmount, | ||
guarantee: TransactionGuarantee? = nil, | ||
poolContributions: [some TrackedPoolInteraction] = [] as [TrackedPoolContribution], | ||
validatorStakes: [TrackedValidatorStake] = [], | ||
entities: InteractionReview.Sections.ResourcesInfo = [:], | ||
resourceAssociatedDapps: InteractionReview.Sections.ResourceAssociatedDapps? = nil, | ||
networkID: NetworkID, | ||
defaultDepositGuarantee: Decimal192 = 1 | ||
) async throws -> KnownResourceBalance { | ||
let resourceAddress = resource.resourceAddress | ||
|
||
@Dependency(\.resourcesVisibilityClient) var resourcesVisibilityClient | ||
let hiddenResources = try await resourcesVisibilityClient.getHidden() | ||
GhenadieVP marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Check if the fungible resource is a pool unit resource | ||
if await isPoolUnitResource(resource) { | ||
return try await poolUnit( | ||
resource, | ||
amount: amount, | ||
amount: resourceAmount, | ||
poolContributions: poolContributions, | ||
entities: entities, | ||
resourceAssociatedDapps: resourceAssociatedDapps, | ||
|
@@ -62,7 +83,7 @@ extension OnLedgerEntitiesClient { | |
if let validator = await isLiquidStakeUnit(resource) { | ||
return try await liquidStakeUnit( | ||
resource, | ||
amount: amount, | ||
amount: resourceAmount, | ||
validator: validator, | ||
validatorStakes: validatorStakes, | ||
guarantee: guarantee | ||
|
@@ -72,24 +93,27 @@ extension OnLedgerEntitiesClient { | |
// Normal fungible resource | ||
let isXRD = resourceAddress.isXRD(on: networkID) | ||
let isHidden = hiddenResources.contains(.fungible(resourceAddress)) | ||
let details: ResourceBalance.Fungible = .init(isXRD: isXRD, amount: .init(nominalAmount: amount), guarantee: guarantee) | ||
let details: KnownResourceBalance.Fungible = .init(isXRD: isXRD, amount: resourceAmount, guarantee: guarantee) | ||
|
||
return .init(resource: resource, details: .fungible(details), isHidden: isHidden) | ||
} | ||
|
||
private func poolUnit( | ||
_ resource: OnLedgerEntity.Resource, | ||
amount: Decimal192, | ||
amount: ResourceAmount, | ||
poolContributions: [some TrackedPoolInteraction] = [], | ||
entities: InteractionReview.Sections.ResourcesInfo = [:], | ||
resourceAssociatedDapps: InteractionReview.Sections.ResourceAssociatedDapps? = nil, | ||
networkID: NetworkID, | ||
guarantee: TransactionGuarantee?, | ||
hiddenResources: [ResourceIdentifier] | ||
) async throws -> ResourceBalance { | ||
) async throws -> KnownResourceBalance { | ||
let resourceAddress = resource.resourceAddress | ||
|
||
if let poolContribution = poolContributions.first(where: { $0.poolUnitsResourceAddress == resourceAddress }) { | ||
guard let amount = amount.exactAmount?.nominalAmount else { | ||
fatalError("Not possible") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a better message as to why this is not possible. Still, it may be worth investigating if we could have separate functions that are called when resolving the sections for manifestSummary or from executionSummary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did the separation here |
||
} | ||
// If this transfer does not contain all the pool units, scale the resource amounts pro rata | ||
let adjustmentFactor = amount != poolContribution.poolUnitsAmount ? (amount / poolContribution.poolUnitsAmount) : 1 | ||
var xrdResource: OwnedResourcePoolDetails.ResourceWithRedemptionValue? | ||
|
@@ -101,7 +125,7 @@ extension OnLedgerEntitiesClient { | |
|
||
let resource = OwnedResourcePoolDetails.ResourceWithRedemptionValue( | ||
resource: .init(resourceAddress: address, metadata: entity.metadata), | ||
redemptionValue: .init(nominalAmount: resourceAmount * adjustmentFactor) | ||
redemptionValue: .exact(.init(nominalAmount: resourceAmount * adjustmentFactor)) | ||
) | ||
|
||
if address.isXRD(on: networkID) { | ||
|
@@ -119,7 +143,11 @@ extension OnLedgerEntitiesClient { | |
details: .init( | ||
address: poolContribution.poolAddress, | ||
dAppName: resourceAssociatedDapps?[resourceAddress]?.name, | ||
poolUnitResource: .init(resource: resource, amount: .init(nominalAmount: amount)), | ||
poolUnitResource: .init( | ||
resource: resource, | ||
amount: .exact(.init(nominalAmount: amount)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seeing this multiple times, maybe worth declaring a function on ResourceAmount like: static func exact(_ nominalAmount: Decimal) -> Self |
||
guarantee: guarantee?.amount | ||
), | ||
xrdResource: xrdResource, | ||
nonXrdResources: nonXrdResources | ||
), | ||
|
@@ -128,7 +156,7 @@ extension OnLedgerEntitiesClient { | |
isHidden: isHidden | ||
) | ||
} else { | ||
guard let details = try await getPoolUnitDetails(resource, forAmount: amount) else { | ||
guard let details = try await getPoolUnitDetails(resource, forAmount: amount, guarantee: guarantee?.amount) else { | ||
throw FailedToGetPoolUnitDetails() | ||
} | ||
|
||
|
@@ -147,38 +175,41 @@ extension OnLedgerEntitiesClient { | |
|
||
private func liquidStakeUnit( | ||
_ resource: OnLedgerEntity.Resource, | ||
amount: Decimal192, | ||
amount: ResourceAmount, | ||
validator: OnLedgerEntity.Validator, | ||
validatorStakes: [TrackedValidatorStake] = [], | ||
guarantee: TransactionGuarantee? | ||
) async throws -> ResourceBalance { | ||
let worth: Decimal192 | ||
) async throws -> KnownResourceBalance { | ||
let worth: ResourceAmount | ||
if validatorStakes.isEmpty { | ||
guard let totalSupply = resource.totalSupply, totalSupply.isPositive else { | ||
throw MissingPositiveTotalSupply() | ||
} | ||
|
||
worth = amount * validator.xrdVaultBalance / totalSupply | ||
worth = amount.adjustedNominalAmount { $0 * validator.xrdVaultBalance / totalSupply } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. token arithmetic ought best be done in Sargon, would that makes sense? And with unit tests... |
||
} else { | ||
guard let exactAmount = amount.exactAmount else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above. |
||
fatalError("Not possible") | ||
} | ||
if let stake = validatorStakes.first(where: { $0.validatorAddress == validator.address }) { | ||
guard stake.liquidStakeUnitAddress == validator.stakeUnitResourceAddress else { | ||
throw StakeUnitAddressMismatch() | ||
} | ||
// Distribute the worth in proportion to the amounts, if needed | ||
if stake.liquidStakeUnitAmount == amount { | ||
worth = stake.xrdAmount | ||
if stake.liquidStakeUnitAmount == exactAmount.nominalAmount { | ||
worth = .exact(.init(nominalAmount: stake.xrdAmount)) | ||
} else { | ||
worth = (amount / stake.liquidStakeUnitAmount) * stake.xrdAmount | ||
worth = .exact(.init(nominalAmount: (exactAmount.nominalAmount / stake.liquidStakeUnitAmount) * stake.xrdAmount)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. possible to move token amount arithmetic to Sargon? |
||
} | ||
} else { | ||
throw MissingTrackedValidatorStake() | ||
} | ||
} | ||
|
||
let details = ResourceBalance.LiquidStakeUnit( | ||
let details = KnownResourceBalance.LiquidStakeUnit( | ||
resource: resource, | ||
amount: amount, | ||
worth: .init(nominalAmount: worth), | ||
worth: worth, | ||
validator: validator, | ||
guarantee: guarantee | ||
) | ||
|
@@ -191,12 +222,11 @@ extension OnLedgerEntitiesClient { | |
func nonFungibleResourceBalances( | ||
_ resourceInfo: InteractionReview.Sections.ResourceInfo, | ||
resourceAddress: ResourceAddress, | ||
resourceQuantifier: NonFungibleResourceIndicator, | ||
ids: [NonFungibleLocalId], | ||
unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], | ||
newlyCreatedNonFungibles: [NonFungibleGlobalId] = [] | ||
) async throws -> [ResourceBalance] { | ||
let ids = resourceQuantifier.ids | ||
let result: [ResourceBalance] | ||
) async throws -> [KnownResourceBalance] { | ||
let result: [KnownResourceBalance] | ||
|
||
switch resourceInfo { | ||
case let .left(resource): | ||
|
@@ -237,7 +267,7 @@ extension OnLedgerEntitiesClient { | |
} else { | ||
result = tokens.map { token in | ||
let isHidden = hiddenResources.contains(.nonFungible(token.id.resourceAddress)) | ||
return ResourceBalance(resource: resource, details: .nonFungible(token), isHidden: isHidden) | ||
return KnownResourceBalance(resource: resource, details: .nonFungible(.token(token)), isHidden: isHidden) | ||
} | ||
|
||
guard result.count == ids.count else { | ||
|
@@ -258,7 +288,7 @@ extension OnLedgerEntitiesClient { | |
) | ||
} | ||
.map { id in | ||
ResourceBalance(resource: resource, details: .nonFungible(.init(id: id, data: nil)), isHidden: false) | ||
KnownResourceBalance(resource: resource, details: .nonFungible(.token(.init(id: id, data: nil))), isHidden: false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
guard result.count == ids.count else { | ||
|
@@ -274,7 +304,7 @@ extension OnLedgerEntitiesClient { | |
stakeClaimValidator: OnLedgerEntity.Validator, | ||
unstakeData: [NonFungibleGlobalId: UnstakeData], | ||
tokens: [OnLedgerEntity.NonFungibleToken] | ||
) throws -> ResourceBalance { | ||
) throws -> KnownResourceBalance { | ||
let stakeClaimTokens: [OnLedgerEntitiesClient.StakeClaim] = if unstakeData.isEmpty { | ||
try tokens.map { token in | ||
guard let data = token.data else { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer line breaks for long signatures - try
CTRL + M
in Xcode :)