Skip to content
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

refactor: separate vesting from timelock #1750

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/wallet-dashboard/lib/constants/vesting.constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { Timelocked, TimelockedStakedIota } from '../interfaces';
import { TimelockedObject, TimelockedStakedIota } from '../interfaces';
import { DAYS_PER_WEEK, DAYS_PER_YEAR, MILLISECONDS_PER_DAY } from './time.constants';

export const SUPPLY_INCREASE_VESTING_PAYOUT_SCHEDULE = 2 * DAYS_PER_WEEK;
Expand All @@ -18,7 +18,7 @@ export const SUPPLY_INCREASE_INVESTOR_VESTING_DURATION = 4; // Years
export const SUPPLY_INCREASE_VESTING_LABEL =
'000000000000000000000000000000000000000000000000000000000000107a::stardust_upgrade_label::STARDUST_UPGRADE_LABEL';

export const MOCKED_SUPPLY_INCREASE_VESTING_TIMELOCKED_OBJECTS: Timelocked[] = [
export const MOCKED_SUPPLY_INCREASE_VESTING_TIMELOCKED_OBJECTS: TimelockedObject[] = [
{
id: {
id: '0xfe755ca67e3a0714f97ec3c49cfc6f3ecdab2673d96b5840294d3a5db376c99',
Expand Down Expand Up @@ -680,7 +680,7 @@ export const MOCKED_VESTING_TIMELOCKED_STAKED_OBJECTS: TimelockedStakedIota[] =
];

export const MOCKED_VESTING_TIMELOCKED_AND_TIMELOCK_STAKED_OBJECTS: (
| Timelocked
| TimelockedObject
| TimelockedStakedIota
)[] = [
{
Expand Down
1 change: 1 addition & 0 deletions apps/wallet-dashboard/lib/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
// SPDX-License-Identifier: Apache-2.0

export * from './transactions.interface';
export * from './timelock.interface';
export * from './vesting.interface';
38 changes: 38 additions & 0 deletions apps/wallet-dashboard/lib/interfaces/timelock.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export interface UID {
id: string;
}

export interface Balance {
value: number;
}

export interface TimelockedObject {
id: UID;
locked: Balance; // TODO: extend to support other types of locked assets
expirationTimestampMs: number;
label?: string;
}

export interface TimelockedIotaResponse {
id: UID;
locked: string;
expiration_timestamp_ms: string;
label?: string;
}

export interface StakedIota {
id: UID;
poolId: string;
stakeActivationEpoch: number;
principal: Balance;
}

export interface TimelockedStakedIota {
id: UID;
stakedIota: StakedIota;
expirationTimestampMs: number;
label?: string | null | undefined;
}
36 changes: 0 additions & 36 deletions apps/wallet-dashboard/lib/interfaces/vesting.interface.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,6 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

export interface UID {
id: string;
}

export interface Balance {
value: number;
}

export interface Timelocked {
id: UID;
locked: Balance;
expirationTimestampMs: number;
label?: string;
}

export interface TimelockedIotaResponse {
id: UID;
locked: string;
expiration_timestamp_ms: string;
label?: string;
}

export interface StakedIota {
id: UID;
poolId: string;
stakeActivationEpoch: number;
principal: Balance;
}

export interface TimelockedStakedIota {
id: UID;
stakedIota: StakedIota;
expirationTimestampMs: number;
label?: string | null | undefined;
}

export enum SupplyIncreaseUserType {
Staker = 'Staker',
Entity = 'Entity',
Expand Down
15 changes: 6 additions & 9 deletions apps/wallet-dashboard/lib/utils/timelock.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
// Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

import { SUPPLY_INCREASE_VESTING_LABEL } from '../constants';
import { Timelocked, TimelockedStakedIota } from '../interfaces';
import { TimelockedObject, TimelockedStakedIota } from '../interfaces';

export function isTimelockedStakedIota(
obj: Timelocked | TimelockedStakedIota,
obj: TimelockedObject | TimelockedStakedIota,
): obj is TimelockedStakedIota {
const referenceProperty: keyof TimelockedStakedIota = 'stakedIota';
return referenceProperty in obj;
}

export function isTimelocked(obj: Timelocked | TimelockedStakedIota): obj is Timelocked {
const referenceProperty: keyof Timelocked = 'locked';
export function isTimelockedObject(
obj: TimelockedObject | TimelockedStakedIota,
): obj is TimelockedObject {
const referenceProperty: keyof TimelockedObject = 'locked';
return referenceProperty in obj;
}

export function isVesting(obj: Timelocked | TimelockedStakedIota): boolean {
return obj.label === SUPPLY_INCREASE_VESTING_LABEL;
}
4 changes: 2 additions & 2 deletions apps/wallet-dashboard/lib/utils/vesting/vesting.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '../../constants';

import { SupplyIncreaseUserType, SupplyIncreaseVestingPayout } from '../../interfaces';
import { isTimelocked, isTimelockedStakedIota } from '../timelock';
import { isTimelockedObject, isTimelockedStakedIota } from '../timelock';

import {
getVestingOverview,
Expand Down Expand Up @@ -220,7 +220,7 @@ describe('vesting overview', () => {
.reduce((acc, current) => acc + current.stakedIota.principal.value, 0);
expect(vestingOverview.totalStaked).toEqual(totalStaked);

const timelockObjects = mixedObjects.filter(isTimelocked);
const timelockObjects = mixedObjects.filter(isTimelockedObject);
const availableClaiming = timelockObjects.reduce(
(acc, current) =>
current.expirationTimestampMs <= Date.now() ? acc + current.locked.value : acc,
Expand Down
30 changes: 18 additions & 12 deletions apps/wallet-dashboard/lib/utils/vesting/vesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ import {
SUPPLY_INCREASE_INVESTOR_VESTING_DURATION,
SUPPLY_INCREASE_STAKER_VESTING_DURATION,
SUPPLY_INCREASE_STARTING_VESTING_YEAR,
SUPPLY_INCREASE_VESTING_LABEL,
SUPPLY_INCREASE_VESTING_PAYOUTS_IN_1_YEAR,
SUPPLY_INCREASE_VESTING_PAYOUT_SCHEDULE_MILLISECONDS,
} from '../../constants';

import {
SupplyIncreaseUserType,
SupplyIncreaseVestingPayout,
SupplyIncreaseVestingPortfolio,
Timelocked,
TimelockedIotaResponse,
TimelockedObject,
TimelockedStakedIota,
VestingOverview,
} from '../../interfaces';
import { isTimelocked, isTimelockedStakedIota, isVesting } from '../timelock';
import { isTimelockedObject, isTimelockedStakedIota } from '../timelock';

export function getLastSupplyIncreaseVestingPayout(
objects: (Timelocked | TimelockedStakedIota)[],
objects: (TimelockedObject | TimelockedStakedIota)[],
): SupplyIncreaseVestingPayout | undefined {
const vestingObjects = objects.filter(isVesting);
const vestingObjects = objects.filter(isSupplyIncreaseVestingObject);

if (vestingObjects.length === 0) {
return undefined;
Expand All @@ -38,14 +38,14 @@ export function getLastSupplyIncreaseVestingPayout(
}

function supplyIncreaseVestingObjectsToPayoutMap(
vestingObjects: (Timelocked | TimelockedStakedIota)[],
vestingObjects: (TimelockedObject | TimelockedStakedIota)[],
): Map<number, SupplyIncreaseVestingPayout> {
const expirationToVestingPayout = new Map<number, SupplyIncreaseVestingPayout>();

for (const vestingObject of vestingObjects) {
let objectValue = 0;
if (isTimelocked(vestingObject)) {
objectValue = (vestingObject as Timelocked).locked.value;
if (isTimelockedObject(vestingObject)) {
objectValue = (vestingObject as TimelockedObject).locked.value;
} else if (isTimelockedStakedIota(vestingObject)) {
objectValue = (vestingObject as TimelockedStakedIota).stakedIota.principal.value;
}
Expand Down Expand Up @@ -111,10 +111,10 @@ export function buildSupplyIncreaseVestingSchedule(
}

export function getVestingOverview(
objects: (Timelocked | TimelockedStakedIota)[],
objects: (TimelockedObject | TimelockedStakedIota)[],
currentEpochTimestamp: number,
): VestingOverview {
const vestingObjects = objects.filter(isVesting);
const vestingObjects = objects.filter(isSupplyIncreaseVestingObject);
const latestPayout = getLastSupplyIncreaseVestingPayout(vestingObjects);

if (vestingObjects.length === 0 || !latestPayout) {
Expand Down Expand Up @@ -148,7 +148,7 @@ export function getVestingOverview(
0,
);

const timelockedObjects = vestingObjects.filter(isTimelocked);
const timelockedObjects = vestingObjects.filter(isTimelockedObject);

const totalAvailableClaimingAmount = timelockedObjects.reduce(
(acc, current) =>
Expand Down Expand Up @@ -185,7 +185,7 @@ export function getSupplyIncreaseVestingPayoutsCount(userType: SupplyIncreaseUse
return SUPPLY_INCREASE_VESTING_PAYOUTS_IN_1_YEAR * vestingDuration;
}

export function mapTimelockObjects(iotaObjects: IotaObjectData[]): Timelocked[] {
export function mapTimelockObjects(iotaObjects: IotaObjectData[]): TimelockedObject[] {
return iotaObjects.map((iotaObject) => {
if (!iotaObject?.content?.dataType || iotaObject.content.dataType !== 'moveObject') {
return {
Expand Down Expand Up @@ -226,3 +226,9 @@ export function timelockObjectsFromIotaObjects(
});
return result;
}

export function isSupplyIncreaseVestingObject(
obj: TimelockedObject | TimelockedStakedIota,
): boolean {
return obj.label === SUPPLY_INCREASE_VESTING_LABEL;
}
Loading