Skip to content

Commit

Permalink
feat: create delegation activity (#8366)
Browse files Browse the repository at this point in the history
* feat: add delegation activity

* fix: minor improvements

* feat: create delegation tile and details component

* feat: improvements

* feat: add delegatioon tab details

* feat: add account address

* minor fix

* fix storage deposti and giftedStorageDeposit

---------

Co-authored-by: cpl121 <[email protected]>
Co-authored-by: cpl121 <[email protected]>
  • Loading branch information
3 people authored Apr 16, 2024
1 parent 602a13c commit cff7a2e
Show file tree
Hide file tree
Showing 20 changed files with 209 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
NftActivityDetails,
Text,
TextType,
DelegationActivityDetails,
TextHint,
} from '@ui'
import { TextHintVariant } from '@ui/enums'
Expand Down Expand Up @@ -155,6 +156,8 @@
<NftActivityDetails {activity} />
{:else if activity.type === ActivityType.Account}
<AccountActivityDetails {activity} />
{:else if activity.type === ActivityType.Delegation}
<DelegationActivityDetails {activity} />
{/if}
<ActivityInformation {activity} />
</activity-details>
Expand Down
6 changes: 6 additions & 0 deletions packages/shared/components/ActivityInformation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
ConsolidationActivityInformation,
NftMetadataInformation,
SmartContractActivityInformation,
DelegationActivityInformation,
} from '@ui'
import { Tab } from '@ui/enums'
import { ActivityType, Activity } from '@core/wallet'
Expand Down Expand Up @@ -43,6 +44,9 @@
case ActivityType.Account:
tabs = [Tab.Transaction, Tab.Account]
break
case ActivityType.Delegation:
tabs = [Tab.Transaction, Tab.Delegation]
break
case ActivityType.Nft:
tabs = [
Tab.Transaction,
Expand Down Expand Up @@ -82,5 +86,7 @@
<NftMetadataInformation {activity} />
{:else if activeTab === Tab.SmartContract}
<SmartContractActivityInformation {activity} />
{:else if activeTab === Tab.Delegation}
<DelegationActivityInformation {activity} />
{/if}
</activity-details>
20 changes: 20 additions & 0 deletions packages/shared/components/DelegationActivityDetails.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script lang="ts">
import { AddressBox, ActivityInclusionStatusPill, AmountBox } from '@ui'
import { DelegationActivity, getAssetFromPersistedAssets } from '@core/wallet'
import { getBaseToken, getCoinType } from '@core/profile'
export let activity: DelegationActivity
const asset = getAssetFromPersistedAssets(getCoinType())
const unit = getBaseToken().unit
$: amount = activity.delegatedAmount
</script>

<main-content class="flex flex-auto w-full flex-col items-center justify-center space-y-3">
<AmountBox {amount} {asset} {unit} />
<account-status class="flex flex-row w-full space-x-2 justify-center">
<ActivityInclusionStatusPill localizationKey={'delegation.creation'} inclusionState={activity.inclusionState} />
</account-status>
<AddressBox clearBackground clearPadding isCopyable address={activity.transactionId} />
</main-content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { KeyValueBox } from '@ui'
import { localize } from '@core/i18n'
import { DelegationActivity, EMPTY_HEX_ID, formatTokenAmountBestMatch } from '@core/wallet'
import { getBaseToken } from 'shared/lib/core/profile'
import { api } from '@core/api'
import { onMount } from 'svelte'
export let activity: DelegationActivity
const formattedAmount = formatTokenAmountBestMatch(activity.delegatedAmount, getBaseToken()).toString()
let delegationId = activity.delegationId
let detailsList: { [key in string]: string }
onMount(() => {
if (delegationId === EMPTY_HEX_ID) {
delegationId = api.computeDelegationId(activity.outputId)
}
})
$: detailsList = {
validatorAddress: activity.validatorAddress,
delegatedAmount: formattedAmount,
delegationId: delegationId,
startEpoch: activity.startEpoch.toString(),
}
</script>

{#each Object.entries(detailsList) as [key, value]}
<KeyValueBox keyText={localize(`general.${key}`)} valueText={value} isCopyable />
{/each}
1 change: 1 addition & 0 deletions packages/shared/components/activity-info/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { default as TokenActivityInformation } from './TokenActivityInformation'
export { default as NftActivityInformation } from './NftActivityInformation'
export { default as NftMetadataInformation } from './NftMetadataInformation'
export { default as SmartContractActivityInformation } from './SmartContractActivityInformation'
export { default as DelegationActivityInformation } from './DelegationActivityInformation'
1 change: 1 addition & 0 deletions packages/shared/components/enums/tab.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export enum Tab {
Governance = 'general.governance',
NftMetadata = 'general.metadata',
SmartContract = 'general.smartContract',
Delegation = 'general.delegation',
}
1 change: 1 addition & 0 deletions packages/shared/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export { default as TextHint } from './TextHint.svelte'
export { default as Toast } from './Toast.svelte'
export { default as Tooltip } from './Tooltip.svelte'
export { default as Transition } from './Transition.svelte'
export { default as DelegationActivityDetails } from './DelegationActivityDetails.svelte'

export * from './enums'
export * from './inputs'
Expand Down
3 changes: 3 additions & 0 deletions packages/shared/components/tiles/ActivityTile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
TimelockActivityTileFooter,
TransactionActivityTileContent,
VestingActivityTileContent,
DelegationActivityTileContent,
} from '@ui'
export let activity: Activity
Expand Down Expand Up @@ -76,6 +77,8 @@
<ConsolidationActivityTileContent {activity} />
{:else if activity.type === ActivityType.Vesting}
<VestingActivityTileContent {activity} />
{:else if activity.type === ActivityType.Delegation}
<DelegationActivityTileContent {activity} />
{:else}
<FoundryActivityTileContent {activity} />
{/if}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script lang="ts">
import { localize } from '@core/i18n'
import { DelegationActivity, getActivityTileTitle } from '@core/wallet'
import { truncateString } from '@core/utils'
import { ActivityTileContent } from '@ui'
import { Icon } from '@lib/auxiliary/icon'
export let activity: DelegationActivity
$: action = localize(getActivityTileTitle(activity))
$: formattedAsset = {
text: truncateString(activity.accountAddress, 6, 6),
color: 'blue-700',
}
</script>

<ActivityTileContent icon={Icon.Account} {action} subject={localize('general.internalTransaction')} {formattedAsset} />
1 change: 1 addition & 0 deletions packages/shared/components/tiles/tileContents/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { default as TransactionActivityTileContent } from './TransactionActivity
export { default as FoundryActivityTileContent } from './FoundryActivityTileContent.svelte'
export { default as NftActivityTileContent } from './NftActivityTileContent.svelte'
export { default as VestingActivityTileContent } from './VestingActivityTileContent.svelte'
export { default as DelegationActivityTileContent } from './DelegationActivityTileContent.svelte'
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export enum ActivityAction {
Burn = 'burn',
Mint = 'mint',
Unknown = 'unknown',
Create = 'create',
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export enum ActivityType {
Nft = 'nft',
Vesting = 'vesting',
Anchor = 'anchor',
Delegation = 'delegation',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ActivityType } from '@core/wallet/enums'
import { BaseActivity } from './base-activity.type'

export type DelegationActivity = BaseActivity & {
type: ActivityType.Delegation
validatorAddress: string
delegatedAmount: number
delegationId: string
startEpoch: number
accountAddress: string
}
1 change: 1 addition & 0 deletions packages/shared/lib/core/wallet/types/activities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './governance-activity.type'
export * from './nft-activity.type'
export * from './transaction-activity.type'
export * from './vesting-activity.type'
export * from './delegation-activity.type'
2 changes: 2 additions & 0 deletions packages/shared/lib/core/wallet/types/activity.type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AccountActivity,
ConsolidationActivity,
DelegationActivity,
FoundryActivity,
GovernanceActivity,
NftActivity,
Expand All @@ -16,3 +17,4 @@ export type Activity =
| GovernanceActivity
| ConsolidationActivity
| VestingActivity
| DelegationActivity
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { OutputType } from '@iota/sdk/out/types'
import { generateVestingActivity } from './generateVestingActivity'
import { generateSingleAnchorActivity } from './generateSingleAnchorActivity'
import { generateActivitiesFromAnchorOutputs } from './generateActivitiesFromAnchorOutputs'
import { generateActivitiesFromDelegationOutputs } from './generateActivitiesFromDelegationOutputs'
import { generateSingleDelegationActivity } from './generateSingleDelegationActivity'

export async function generateActivities(
processedTransaction: IProcessedTransaction,
Expand Down Expand Up @@ -78,14 +80,23 @@ async function generateActivitiesFromProcessedTransactionsWithInputs(
activities.push(...anchorActivities)
}

const containsDelegationActivity = outputs.some((output) => output.output.type === OutputType.Delegation)
if (containsDelegationActivity) {
const delegationActivities = await generateActivitiesFromDelegationOutputs(processedTransaction, wallet)
activities.push(...delegationActivities)
}

if (
(!containsFoundryActivity && !containsNftActivity && !containsAccountActivity && !governanceOutput) ||
(!containsFoundryActivity &&
!containsNftActivity &&
!containsAccountActivity &&
!governanceOutput &&
!containsDelegationActivity) ||
isSentToImplicitAccountCreationAddress
) {
const basicActivities = await generateActivitiesFromBasicOutputs(processedTransaction, wallet)
activities.push(...basicActivities)
}

return activities
}

Expand Down Expand Up @@ -121,6 +132,8 @@ async function generateActivitiesFromProcessedTransactionsWithoutInputs(
return generateVestingActivity(wallet, params)
case ActivityType.Anchor:
return generateSingleAnchorActivity(wallet, params)
case ActivityType.Delegation:
return generateSingleDelegationActivity(wallet, params)
default:
throw new Error(`Unknown activity type: ${params.type}`)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { IWalletState } from '@core/wallet/interfaces'
import { ActivityAction, DelegationActivity, IProcessedTransaction } from '@core/wallet'
import { Activity } from '@core/wallet/types'
import { generateSingleDelegationActivity } from './generateSingleDelegationActivity'
import { OutputType } from '@iota/sdk/out/types'

export async function generateActivitiesFromDelegationOutputs(
processedTransaction: IProcessedTransaction,
wallet: IWalletState
): Promise<Activity[]> {
const outputs = processedTransaction.outputs
const activities: DelegationActivity[] = []

const delegationOutputs = outputs.filter((output) => output.output.type === OutputType.Delegation)
for (const delegationOutput of delegationOutputs) {
const activity = await generateSingleDelegationActivity(wallet, {
action: ActivityAction.Create,
processedTransaction,
wrappedOutput: delegationOutput,
})
activities.push(activity)
}
return activities
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ActivityType } from '@core/wallet/enums'
import { IActivityGenerationParameters, IWalletState } from '@core/wallet/interfaces'
import { DelegationActivity } from '@core/wallet/types'
import { getAsyncDataFromOutput, getSendingInformation, getStorageDepositFromOutput } from './helper'
import { DelegationOutput } from '@iota/sdk/out/types'
import { AddressConverter } from '../AddressConverter'

export async function generateSingleDelegationActivity(
wallet: IWalletState,
{ action, processedTransaction, wrappedOutput }: IActivityGenerationParameters
): Promise<DelegationActivity> {
const { transactionId, direction, time, claimingData, inclusionState, mana } = processedTransaction
const output = wrappedOutput.output as DelegationOutput
const { storageDeposit, giftedStorageDeposit } = await getStorageDepositFromOutput(output)
const outputId = wrappedOutput.outputId
const id = outputId || transactionId
const isHidden = false
const isAssetHidden = false
const containsValue = true
const delegatedAmount = Number(output.delegatedAmount)
const delegationId = output.delegationId
const validatorAddress = AddressConverter.addressToBech32(output?.validatorAddress)
const asyncData = await getAsyncDataFromOutput(output, outputId, claimingData, wallet)
const sendingInfo = getSendingInformation(processedTransaction, output, wallet)
const startEpoch = output.startEpoch
const accountAddress = AddressConverter.addressToBech32(output.unlockConditions[0]?.address)
return {
type: ActivityType.Delegation,
id,
outputId,
transactionId,
direction,
action,
isHidden,
isAssetHidden,
time,
inclusionState,
containsValue,
mana,
delegatedAmount,
storageDeposit,
giftedStorageDeposit,
delegationId,
validatorAddress,
asyncData,
accountAddress,
startEpoch,
...sendingInfo,
}
}
3 changes: 3 additions & 0 deletions packages/shared/lib/core/wallet/utils/getActivityTileTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export function getActivityTileTitle(activity: Activity): string {
if (activity.type === ActivityType.Vesting) {
return 'general.vestingReward'
}
if (activity.type === ActivityType.Delegation) {
return 'general.delegationCreated'
}
if (activity.type === ActivityType.Governance) {
if (activity.governanceAction === GovernanceAction.IncreaseVotingPower) {
return isConfirmed ? 'general.increased' : 'general.increasing'
Expand Down
19 changes: 16 additions & 3 deletions packages/shared/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1751,7 +1751,13 @@
"availableMana": "Available Mana",
"insufficientMana": "Generating mana... {timeRemaining}.",
"secondsToRefreshManaCost": "Mana cost will be refreshed after {time, plural, one {# second} other {# seconds}}",
"mana": "Mana"
"mana": "Mana",
"delegationCreated": "Delegation created",
"delegation": "Delegation",
"delegationId": "Delegation ID",
"validatorAddress": "Validator Address",
"delegatedAmount": "Delegated amount",
"startEpoch": "Start epoch"
},
"filters":{
"title": "Filters",
Expand Down Expand Up @@ -2404,11 +2410,18 @@
},
"account": {
"creation": {
"Pending": "creating account",
"Confirmed": "account created",
"Pending": "Creating account",
"Confirmed": "Account created",
"Conflicting": "Failed to create account"
}
},
"delegation": {
"creation": {
"Pending": "Creating delegation",
"Confirmed": "Delegation created",
"Failed": "Failed to create delegation"
}
},
"networkHealth": {
"down": "Down",
"degraded": "Degraded",
Expand Down

0 comments on commit cff7a2e

Please sign in to comment.