Skip to content

Commit c36c9a9

Browse files
lazyninapoolcoke
andauthored
feature/proof-of-stake (#290)
* Add newline to make graphite happy * Lockups (#299) * Add transcoder for Register as validator transaction. Add support for approve component for this txn type * Add transcoder for Unregister as validator txn type. Add support for approve component for this new txn type * Add transcoder for stake transaction metadata. Add support for approve component for this new txn type. * Add transcoder for Unstake txn type. Add support for approve component for this new txn type. * Add transcoder for Unlock stake txn type. Add support for approve UI for this new txn type * Add transcoder for Unjail Validator txn type. Add approve UI support for this new txn type. * Add support for coin lockup txn types --------- Co-authored-by: Lazy Nina <> * PoS Spending Limits UI (#298) * Update computation of expiration block height (#300) * PoS Spending Limits UI * Update computation of expiration block height --------- Co-authored-by: Lazy Nina <> Co-authored-by: Jon Pollock <135658176+poolcoke@users.noreply.github.com>
1 parent 7952f60 commit c36c9a9

21 files changed

+898
-46
lines changed

Dockerfile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ COPY ./package.json .
88
COPY ./package-lock.json .
99
COPY ./.npmrc .
1010

11-
# use yarn to upgrade npm
12-
RUN yarn global add npm@7
13-
1411
# install frontend dependencies before copying the frontend code
1512
# into the container so we get docker cache benefits
1613
RUN npm install

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ After proper configuration of `environment.ts` and `environment.prod.ts`, run `n
1717
## Format
1818

1919
Formatting will happen upon commit. Developers can also run `npm run format` or `npx npm run format` if npm isn't installed to format all source files
20+

src/app/account.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,8 @@ export class AccountService {
351351
const btcDepositAddress = 'Not implemented yet';
352352
const ethDepositAddress = 'Not implemented yet';
353353

354-
// days * (24 hours / day) * (60 minutes / hour) * (1 block / 5 minutes) = blocks
355-
const numBlocksBeforeExpiration = (numDaysBeforeExpiration * 24 * 60) / 5;
354+
// days * (24 hours / day) * (60 minutes / hour) * (60 seconds / minute) * (1 block / second) = blocks
355+
const numBlocksBeforeExpiration = numDaysBeforeExpiration * 24 * 60 * 60;
356356

357357
// By default, we authorize this derived key for 8640 blocks, which is about 30 days.
358358
const expirationBlock = blockHeight + numBlocksBeforeExpiration;

src/app/app.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ import { TransactionSpendingLimitDaoCoinLimitOrderComponent } from './transactio
6060
import { TransactionSpendingLimitNftComponent } from './transaction-spending-limit/transaction-spending-limit-nft/transaction-spending-limit-nft.component';
6161
import { TransactionSpendingLimitSectionComponent } from './transaction-spending-limit/transaction-spending-limit-section/transaction-spending-limit-section.component';
6262
import { TransactionSpendingLimitComponent } from './transaction-spending-limit/transaction-spending-limit.component';
63+
import { TransactionSpendingLimitStakeComponent } from './transaction-spending-limit/transaction-spending-limit-stake/transaction-spending-limit-stake.component';
64+
import { TransactionSpendingLimitLockupComponent } from './transaction-spending-limit/transaction-spending-limit-lockup/transaction-spending-limit-lockup.component';
6365

6466
@NgModule({
6567
declarations: [
@@ -107,6 +109,8 @@ import { TransactionSpendingLimitComponent } from './transaction-spending-limit/
107109
RecoverySecretComponent,
108110
BackupSeedDialogComponent,
109111
RemoveAccountDialogComponent,
112+
TransactionSpendingLimitStakeComponent,
113+
TransactionSpendingLimitLockupComponent,
110114
],
111115
imports: [
112116
BrowserModule,

src/app/approve/approve.component.ts

Lines changed: 138 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ import {
3737
TransactionMetadataUpdateNFT,
3838
TransactionMetadataUpdateProfile,
3939
TransactionSpendingLimit,
40+
TransactionMetadataRegisterAsValidator,
41+
TransactionMetadataUnregisterAsValidator,
42+
TransactionMetadataStake,
43+
TransactionMetadataUnstake,
44+
TransactionMetadataUnlockStake,
45+
TransactionMetadataUnjailValidator,
46+
TransactionMetadataCoinLockup,
47+
TransactionMetadataUpdateCoinLockupParams,
48+
TransactionMetadataCoinLockupTransfer,
49+
TransactionMetadataCoinUnlock,
4050
} from '../../lib/deso/transaction';
4151
import { ExtraData } from '../../types/identity';
4252
import { AccountService } from '../account.service';
@@ -304,12 +314,12 @@ export class ApproveComponent implements OnInit {
304314
);
305315
publicKeys = [daoCoinPublicKey];
306316
if (daoCoinMetadata.operationType === 0) {
307-
const mintAmount = this.hexNanosToUnitString(
317+
const mintAmount = this.hexBaseUnitsToUnitString(
308318
daoCoinMetadata.coinsToMintNanos
309319
);
310320
description = `mint ${mintAmount} ${daoCoinPublicKey} DAO coins`;
311321
} else if (daoCoinMetadata.operationType === 1) {
312-
const burnAmount = this.hexNanosToUnitString(
322+
const burnAmount = this.hexBaseUnitsToUnitString(
313323
daoCoinMetadata.coinsToBurnNanos
314324
);
315325
description = `burn ${burnAmount} ${daoCoinPublicKey} DAO coins`;
@@ -322,7 +332,7 @@ export class ApproveComponent implements OnInit {
322332
case TransactionMetadataTransferDAOCoin:
323333
const daoCoinTransferMetadata = this.transaction
324334
.metadata as TransactionMetadataTransferDAOCoin;
325-
const daoCoinTransferAmount = this.hexNanosToUnitString(
335+
const daoCoinTransferAmount = this.hexBaseUnitsToUnitString(
326336
daoCoinTransferMetadata.daoCoinToTransferNanos
327337
);
328338
const daoCoinTransferPublicKey = this.base58KeyCheck(
@@ -388,6 +398,7 @@ export class ApproveComponent implements OnInit {
388398
this.hexScaledExchangeRateToFloat(
389399
daoCoinLimitOrderMetadata.scaledExchangeRateCoinsToSellPerCoinToBuy
390400
);
401+
// TODO: figure out if we need to use hexBaseUnitsToUnitString here.
391402
const quantityToFill = this.hexNanosToUnitString(
392403
daoCoinLimitOrderMetadata.quantityToFillInBaseUnits
393404
);
@@ -588,6 +599,120 @@ export class ApproveComponent implements OnInit {
588599
description = `unknown messaging action on ${messageType} to ${recipient}`;
589600
}
590601
break;
602+
case TransactionMetadataRegisterAsValidator:
603+
// TODO: Do we want any additional details in the approve component?
604+
description = 'register as a validator';
605+
break;
606+
case TransactionMetadataUnregisterAsValidator:
607+
description = 'unregister as a validator';
608+
break;
609+
case TransactionMetadataStake:
610+
const stakeMetadata = this.transaction
611+
.metadata as TransactionMetadataStake;
612+
const stakeValidatorPublicKey = this.base58KeyCheck(
613+
stakeMetadata.validatorPublicKey
614+
);
615+
publicKeys = [stakeValidatorPublicKey];
616+
const stakeAmountNanos = this.hexNanosToUnitString(
617+
stakeMetadata.stakeAmountNanos
618+
);
619+
description = `stake ${stakeAmountNanos} $DESO to ${stakeValidatorPublicKey}`;
620+
break;
621+
case TransactionMetadataUnstake:
622+
const unstakeMetadata = this.transaction
623+
.metadata as TransactionMetadataUnstake;
624+
const unstakeValidatorPublicKey = this.base58KeyCheck(
625+
unstakeMetadata.validatorPublicKey
626+
);
627+
publicKeys = [unstakeValidatorPublicKey];
628+
const unstakeAmountNanos = this.hexNanosToUnitString(
629+
unstakeMetadata.unstakeAmountNanos
630+
);
631+
description = `unstake ${unstakeAmountNanos} $DESO from ${unstakeValidatorPublicKey}`;
632+
break;
633+
case TransactionMetadataUnlockStake:
634+
const unlockStakeMetadata = this.transaction
635+
.metadata as TransactionMetadataUnlockStake;
636+
const unlockStakeValidatorPublicKey = this.base58KeyCheck(
637+
unlockStakeMetadata.validatorPublicKey
638+
);
639+
publicKeys = [unlockStakeValidatorPublicKey];
640+
description =
641+
`unlock stake from ${unlockStakeValidatorPublicKey}, ` +
642+
`starting from epochs ${unlockStakeMetadata.startEpochNumber} to ${unlockStakeMetadata.endEpochNumber}`;
643+
break;
644+
case TransactionMetadataUnjailValidator:
645+
description = 'unjail your validator';
646+
break;
647+
case TransactionMetadataCoinLockup:
648+
// NOTE: we don't need a special case for DESO right now
649+
// as lockups are not allowed for DESO at this time.
650+
const coinLockupMetadata = this.transaction
651+
.metadata as TransactionMetadataCoinLockup;
652+
const lockupAmount = this.hexBaseUnitsToUnitString(
653+
coinLockupMetadata.lockupAmountBaseUnits
654+
);
655+
const lockupProfilePubKey = this.base58KeyCheck(
656+
coinLockupMetadata.profilePublicKey
657+
);
658+
const lockUpRecipientPubKey = this.base58KeyCheck(
659+
coinLockupMetadata.recipientPublicKey
660+
);
661+
publicKeys = [lockupProfilePubKey, lockUpRecipientPubKey];
662+
description = `lockup ${lockupAmount} of your ${lockupProfilePubKey} coins`;
663+
break;
664+
case TransactionMetadataUpdateCoinLockupParams:
665+
const updateCoinLockupParamsMetadata = this.transaction
666+
.metadata as TransactionMetadataUpdateCoinLockupParams;
667+
description =
668+
`update your coin lockup params\n` +
669+
`${
670+
updateCoinLockupParamsMetadata.removeYieldCurvePoint
671+
? 'Remove'
672+
: 'Add'
673+
} yield curve point with
674+
${
675+
updateCoinLockupParamsMetadata.lockupYieldAPYBasisPoints / 100
676+
}% APY for a lockup of
677+
${
678+
updateCoinLockupParamsMetadata.lockupYieldDurationNanoSecs
679+
} nanoseconds
680+
${
681+
!updateCoinLockupParamsMetadata.newLockupTransferRestrictions
682+
? ''
683+
: 'and update your lockup transfer restrictions'
684+
}`;
685+
686+
break;
687+
case TransactionMetadataCoinLockupTransfer:
688+
// NOTE: we don't need a special case for DESO right now
689+
// as lockups are not allowed for DESO at this time.
690+
const coinLockupTransferMetadata = this.transaction
691+
.metadata as TransactionMetadataCoinLockupTransfer;
692+
const lockupTransferAmount = this.hexBaseUnitsToUnitString(
693+
coinLockupTransferMetadata.lockedCoinsToTransferBaseUnits
694+
);
695+
const lockupTransferProfilePubKey = this.base58KeyCheck(
696+
coinLockupTransferMetadata.profilePublicKey
697+
);
698+
const lockupTransferRecipientPubKey = this.base58KeyCheck(
699+
coinLockupTransferMetadata.recipientPublicKey
700+
);
701+
publicKeys = [
702+
lockupTransferProfilePubKey,
703+
lockupTransferRecipientPubKey,
704+
];
705+
description = `transfer ${lockupTransferAmount} of your locked ${lockupTransferProfilePubKey} coins to ${lockupTransferRecipientPubKey}`;
706+
break;
707+
case TransactionMetadataCoinUnlock:
708+
const coinUnlockMetadata = this.transaction
709+
.metadata as TransactionMetadataCoinUnlock;
710+
const unlockProfilePubKey = this.base58KeyCheck(
711+
coinUnlockMetadata.profilePublicKey
712+
);
713+
publicKeys = [unlockProfilePubKey];
714+
description = `unlock your locked ${unlockProfilePubKey} coins`;
715+
break;
591716
}
592717

593718
// Set the transaction description based on the description populated with public keys.
@@ -608,14 +733,24 @@ export class ApproveComponent implements OnInit {
608733
return bs58check.encode(Buffer.from([...prefix, ...keyBytes]));
609734
}
610735

736+
// uint256 to DESO nano conversions.
611737
hexNanosToUnitString(nanos: Buffer): string {
612738
return this.nanosToUnitString(parseInt(nanos.toString('hex'), 16));
613739
}
614740

741+
// unit256 to base unit conversions.
742+
hexBaseUnitsToUnitString(baseUnits: Buffer): string {
743+
return this.baseUnitsToUnitString(parseInt(baseUnits.toString('hex'), 16));
744+
}
745+
615746
nanosToUnitString(nanos: number): string {
616747
return this.toFixedLengthDecimalString(nanos / 1e9);
617748
}
618749

750+
baseUnitsToUnitString(baseUnits: number): string {
751+
return this.toFixedLengthDecimalString(baseUnits / 1e18);
752+
}
753+
619754
hexScaledExchangeRateToFloat(hex: Buffer): number {
620755
return parseInt(hex.toString('hex'), 16) / 1e38;
621756
}

src/app/backend-api.service.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ export type LimitOperationString =
147147
| NFTLimitOperationString
148148
| AssociationOperationString
149149
| AccessGroupOperationString
150-
| AccessGroupMemberOperationString;
150+
| AccessGroupMemberOperationString
151+
| LockupLimitOperationString;
151152
export type CreatorCoinOperationLimitMap =
152153
CoinOperationLimitMap<CreatorCoinLimitOperationString>;
153154
export type DAOCoinOperationLimitMap =
@@ -236,6 +237,42 @@ export type AccessGroupMemberLimitMapItem = {
236237
OpCount: number;
237238
};
238239

240+
export type StakeLimitMapItem = {
241+
ValidatorPublicKeyBase58Check: string;
242+
StakeLimit: string; // Hex string
243+
};
244+
245+
export type UnstakeLimitMapItem = {
246+
ValidatorPublicKeyBase58Check: string;
247+
UnstakeLimit: string; // Hex string
248+
};
249+
250+
export type UnlockStakeLimitMapItem = {
251+
ValidatorPublicKeyBase58Check: string;
252+
OpCount: number;
253+
};
254+
255+
export enum LockupLimitScopeType {
256+
ANY = 'AnyCoins',
257+
SCOPED = 'ScopedCoins',
258+
}
259+
260+
export enum LockupLimitOperationString {
261+
ANY = 'Any',
262+
COIN_LOCKUP = 'CoinLockup',
263+
UPDATE_COIN_LOCKUP_YIELD_CURVE = 'UpdateCoinLockupYieldCurve',
264+
UPDATE_COIN_LOCKUP_TRANSFER_RESTRICTIONS = 'UpdateCoinLockupTransferRestrictions',
265+
COIN_LOCKUP_TRANSFER = 'CoinLockupTransferOperationString',
266+
COIN_UNLOCK = 'CoinLockupUnlock',
267+
}
268+
269+
export type LockupLimitMapItem = {
270+
ProfilePublicKeyBase58Check: string;
271+
ScopeType: LockupLimitScopeType;
272+
Operation: LockupLimitOperationString;
273+
OpCount: number;
274+
};
275+
239276
export interface TransactionSpendingLimitResponse {
240277
GlobalDESOLimit: number;
241278
// TODO: make enum for transaction type string
@@ -247,6 +284,10 @@ export interface TransactionSpendingLimitResponse {
247284
AssociationLimitMap?: AssociationLimitMapItem[];
248285
AccessGroupLimitMap?: AccessGroupLimitMapItem[];
249286
AccessGroupMemberLimitMap?: AccessGroupMemberLimitMapItem[];
287+
StakeLimitMap?: StakeLimitMapItem[];
288+
UnstakeLimitMap?: UnstakeLimitMapItem[];
289+
UnlockStakeLimitMap?: UnlockStakeLimitMapItem[];
290+
LockupLimitMap?: LockupLimitMapItem[];
250291
IsUnlimited?: boolean;
251292
DerivedKeyMemo?: string;
252293
}

src/app/identity.service.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ import {
3535
TransactionMetadataUpdateGlobalParams,
3636
TransactionMetadataUpdateNFT,
3737
TransactionMetadataUpdateProfile,
38+
TransactionMetadataRegisterAsValidator,
39+
TransactionMetadataUnregisterAsValidator,
40+
TransactionMetadataStake,
41+
TransactionMetadataUnstake,
42+
TransactionMetadataUnlockStake,
43+
TransactionMetadataUnjailValidator,
44+
TransactionMetadataCoinLockup,
45+
TransactionMetadataUpdateCoinLockupParams,
46+
TransactionMetadataCoinLockupTransfer,
47+
TransactionMetadataCoinUnlock,
3848
} from '../lib/deso/transaction';
3949
import { SwalHelper } from '../lib/helpers/swal-helper';
4050
import { AccessLevel, PublicUserInfo } from '../types/identity';
@@ -518,6 +528,15 @@ export class IdentityService {
518528
case TransactionMetadataDAOCoin:
519529
case TransactionMetadataTransferDAOCoin:
520530
case TransactionMetadataDAOCoinLimitOrder:
531+
case TransactionMetadataRegisterAsValidator:
532+
case TransactionMetadataUnregisterAsValidator:
533+
case TransactionMetadataStake:
534+
case TransactionMetadataUnstake:
535+
case TransactionMetadataUnlockStake:
536+
case TransactionMetadataCoinLockup:
537+
case TransactionMetadataUpdateCoinLockupParams:
538+
case TransactionMetadataCoinLockupTransfer:
539+
case TransactionMetadataCoinUnlock:
521540
return AccessLevel.Full;
522541

523542
case TransactionMetadataFollow:
@@ -531,6 +550,7 @@ export class IdentityService {
531550
case TransactionMetadataAccessGroup:
532551
case TransactionMetadataAccessGroupMembers:
533552
case TransactionMetadataNewMessage:
553+
case TransactionMetadataUnjailValidator:
534554
return AccessLevel.ApproveLarge;
535555
}
536556

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<div class="display--flex justify--between margin-bottom--small">
2+
<div class="text--left width--25">
3+
<img
4+
class="avatar--medium avatar--rounded margin-right--xsmall"
5+
[appAvatar]="lockupLimitMapItem?.ProfilePublicKeyBase58Check"
6+
*ngIf="
7+
lockupLimitMapItem?.ProfilePublicKeyBase58Check &&
8+
appUser?.ProfileEntryResponse?.Username
9+
"
10+
/>
11+
{{
12+
appUser?.ProfileEntryResponse?.Username ||
13+
lockupLimitMapItem?.ProfilePublicKeyBase58Check ||
14+
(lockupLimitMapItem?.ScopeType === LockupLimitScopeType.ANY
15+
? 'Any Profile'
16+
: 'DESO') | truncateAddressOrUsername
17+
}}
18+
</div>
19+
<div class="display-flex justify--center width--50">
20+
<code>
21+
{{ getOperationString() }}
22+
</code>
23+
</div>
24+
<div class="width--25 text--right">
25+
<code>
26+
{{ globalVars.formatTxCountLimit(lockupLimitMapItem?.OpCount) }}
27+
</code>
28+
</div>
29+
</div>

src/app/transaction-spending-limit/transaction-spending-limit-lockup/transaction-spending-limit-lockup.component.scss

Whitespace-only changes.

0 commit comments

Comments
 (0)