Skip to content

Commit

Permalink
updated ux to not require destination (for stake/unstake) and not req…
Browse files Browse the repository at this point in the history
…uire a param for finalize unstake
  • Loading branch information
dsawali committed Apr 23, 2024
1 parent fba1fe3 commit 3655961
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 90 deletions.
24 changes: 12 additions & 12 deletions integration-tests/__tests__/contract/operations/staking.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,31 @@ import { CONFIGS } from "../../../config";

CONFIGS().forEach(({ lib, rpc, setup }) => {
const Tezos = lib;
let myPkh: string;

describe(`Staking pseudo operations: ${rpc}`, () => {

beforeAll(async () => {
await setup(true);

myPkh = await Tezos.signer.publicKeyHash();
console.log(myPkh);

const delegateOp = await Tezos.contract.setDelegate({
delegate: 'tz1PZY3tEWmXGasYeehXYqwXuw2Z3iZ6QDnA',
source: myPkh,
source: await Tezos.signer.publicKeyHash()
});

await delegateOp.confirmation();
});

it('should be able to inject the stake pseudo operation to a designated delegate', async () => {
it('should throw an error when the destination specified is not the same as source', async () => {
expect(async () => {
const op = await Tezos.contract.stake({
amount: 0.1,
to: 'tz1PZY3tEWmXGasYeehXYqwXuw2Z3iZ6QDnA'
});
}).rejects.toThrow();
});

it('should be able to stake funds to a designated delegate', async () => {
const op = await Tezos.contract.stake({
to: myPkh,
amount: 0.1
});
await op.confirmation();
Expand All @@ -33,7 +37,6 @@ CONFIGS().forEach(({ lib, rpc, setup }) => {

it('should be able to unstake funds from a designated delegate', async () => {
const op = await Tezos.contract.unstake({
to: myPkh,
amount: 0.1
});
await op.confirmation();
Expand All @@ -43,10 +46,7 @@ CONFIGS().forEach(({ lib, rpc, setup }) => {
});

it('should be able to finalize_unstake funds from a designated delegate', async () => {
const op = await Tezos.contract.finalizeUnstake({
to: myPkh,
amount: 0
});
const op = await Tezos.contract.finalizeUnstake({});
await op.confirmation();

expect(op.hash).toBeDefined();
Expand Down
22 changes: 22 additions & 0 deletions packages/taquito-core/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,28 @@ export class InvalidAddressError extends ParameterValidationError {
}
}

export class InvalidStakingAddressError extends ParameterValidationError {
constructor(
public readonly address: string,
public readonly errorDetail?: string
) {
super();
this.name = 'InvalidStakingAddressError';
this.message = `Invalid staking address "${address}", you can only stake to your own address`;
}
}

export class InvalidFinalizeUnstakeAmountError extends ParameterValidationError {
constructor(
public readonly address: string,
public readonly errorDetail?: string
) {
super();
this.name = 'InvalidFinalizeUnstakeAmountError';
this.message = `The amount can only be 0 when finalizing an unstake`;
}
}

/**
* @category Error
* @description Error that indicates an invalid block hash being passed or used
Expand Down
37 changes: 26 additions & 11 deletions packages/taquito/src/contract/rpc-contract-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import {
InvalidAddressError,
InvalidContractAddressError,
InvalidAmountError,
InvalidFinalizeUnstakeAmountError,
InvalidStakingAddressError,
} from '@taquito/core';
import { OperationBatch } from '../batch/rpc-batch-provider';
import { Context } from '../context';
Expand Down Expand Up @@ -407,10 +409,13 @@ export class RpcContractProvider extends Provider implements ContractProvider, S
* @param Stake pseudo-operation parameter
*/
async stake(params: StakeParams) {
const toValidation = validateAddress(params.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.to, invalidDetail(toValidation));
if (params.to === undefined) {
params.to = params.source;
}
if (params.to !== undefined && params.to !== params.source) {
throw new InvalidStakingAddressError(params.to);
}

const sourceValidation = validateAddress(params.source ?? '');
if (params.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.source, invalidDetail(sourceValidation));
Expand Down Expand Up @@ -442,10 +447,13 @@ export class RpcContractProvider extends Provider implements ContractProvider, S
* @param Unstake pseudo-operation parameter
*/
async unstake(params: UnstakeParams) {
const toValidation = validateAddress(params.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.to, invalidDetail(toValidation));
if (params.to === undefined) {
params.to = params.source;
}
if (params.to !== undefined && params.to !== params.source) {
throw new InvalidStakingAddressError(params.to);
}

const sourceValidation = validateAddress(params.source ?? '');
if (params.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.source, invalidDetail(sourceValidation));
Expand Down Expand Up @@ -477,18 +485,25 @@ export class RpcContractProvider extends Provider implements ContractProvider, S
* @param Finalize_unstake pseudo-operation parameter
*/
async finalizeUnstake(params: FinalizeUnstakeParams) {
const toValidation = validateAddress(params.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.to, invalidDetail(toValidation));
if (params.to === undefined) {
params.to = params.source;
}
if (params.to !== undefined && params.to !== params.source) {
throw new InvalidStakingAddressError(params.to);
}

const sourceValidation = validateAddress(params.source ?? '');
if (params.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(params.source, invalidDetail(sourceValidation));
}

if (params.amount < 0) {
throw new InvalidAmountError(params.amount.toString());
if (params.amount === undefined) {
params.amount = 0;
}
if (params.amount !== undefined && params.amount > 0) {
throw new InvalidFinalizeUnstakeAmountError('Amount must be 0 to finalize unstake.');
}

const publicKeyHash = await this.signer.publicKeyHash();
const estimate = await this.estimate(
params,
Expand Down
36 changes: 24 additions & 12 deletions packages/taquito/src/estimate/rpc-estimate-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { ContractMethod, ContractMethodObject, ContractProvider } from '../contr
import { Provider } from '../provider';
import { PrepareProvider } from '../prepare/prepare-provider';
import { PreparedOperation } from '../prepare';
import { InvalidAddressError, InvalidAmountError } from '@taquito/core';
import { InvalidAddressError, InvalidAmountError, InvalidStakingAddressError } from '@taquito/core';

// stub signature that won't be verified by tezos rpc simulate_operation
const STUB_SIGNATURE =
Expand Down Expand Up @@ -215,10 +215,13 @@ export class RPCEstimateProvider extends Provider implements EstimationProvider
* @param Stake pseudo-operation parameter
*/
async stake({ fee, storageLimit, gasLimit, ...rest }: StakeParams) {
const toValidation = validateAddress(rest.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.to, invalidDetail(toValidation));
if (rest.to === undefined) {
rest.to = rest.source;
}
if (rest.to !== undefined && rest.to !== rest.source) {
throw new InvalidStakingAddressError(rest.to);
}

const sourceValidation = validateAddress(rest.source ?? '');
if (rest.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.source, invalidDetail(sourceValidation));
Expand Down Expand Up @@ -251,10 +254,13 @@ export class RPCEstimateProvider extends Provider implements EstimationProvider
* @param Unstake pseudo-operation parameter
*/
async unstake({ fee, storageLimit, gasLimit, ...rest }: UnstakeParams) {
const toValidation = validateAddress(rest.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.to, invalidDetail(toValidation));
if (rest.to === undefined) {
rest.to = rest.source;
}
if (rest.to !== undefined && rest.to !== rest.source) {
throw new InvalidStakingAddressError(rest.to);
}

const sourceValidation = validateAddress(rest.source ?? '');
if (rest.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.source, invalidDetail(sourceValidation));
Expand Down Expand Up @@ -287,17 +293,23 @@ export class RPCEstimateProvider extends Provider implements EstimationProvider
* @param finalize_unstake pseudo-operation parameter
*/
async finalizeUnstake({ fee, storageLimit, gasLimit, ...rest }: FinalizeUnstakeParams) {
const toValidation = validateAddress(rest.to);
if (toValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.to, invalidDetail(toValidation));
if (rest.to === undefined) {
rest.to = rest.source;
}
if (rest.to !== undefined && rest.to !== rest.source) {
throw new InvalidStakingAddressError(rest.to);
}
const sourceValidation = validateAddress(rest.source ?? '');
if (rest.source && sourceValidation !== ValidationResult.VALID) {
throw new InvalidAddressError(rest.source, invalidDetail(sourceValidation));
}
if (rest.amount < 0) {
throw new InvalidAmountError(rest.amount.toString());
if (rest.amount === undefined) {
rest.amount = 0;
}
if (rest.amount !== undefined && rest.amount !== 0) {
throw new Error('Amount must be 0 for finalize_unstake operation');
}

const preparedOperation = await this.prepare.finalizeUnstake({
fee,
storageLimit,
Expand Down
33 changes: 30 additions & 3 deletions packages/taquito/src/operations/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,17 +313,44 @@ export interface TransferParams {
/**
* @description RPC Stake pseudo operation params
*/
export interface StakeParams extends TransferParams {}
export interface StakeParams {
to?: string;
source?: string;
amount: number;
fee?: number;
parameter?: TransactionOperationParameter;
gasLimit?: number;
storageLimit?: number;
mutez?: boolean;
}

/**
* @description RPC unstake pseudo operation params
*/
export interface UnstakeParams extends TransferParams {}
export interface UnstakeParams {
to?: string;
source?: string;
amount: number;
fee?: number;
parameter?: TransactionOperationParameter;
gasLimit?: number;
storageLimit?: number;
mutez?: boolean;
}

/**
* @description RPC finalize_unstake pseudo operation params
*/
export interface FinalizeUnstakeParams extends TransferParams {}
export interface FinalizeUnstakeParams {
to?: string;
source?: string;
amount?: number;
fee?: number;
parameter?: TransactionOperationParameter;
gasLimit?: number;
storageLimit?: number;
mutez?: boolean;
}

/**
* @description RPC register global constant operation
Expand Down
4 changes: 4 additions & 0 deletions packages/taquito/src/prepare/prepare-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ export class PrepareProvider extends Provider implements PreparationProvider {
const DEFAULT_PARAMS = await this.getOperationLimits(protocolConstants);
const op = await createTransferOperation({
...rest,
to: pkh,
...mergeLimits({ fee, storageLimit, gasLimit }, DEFAULT_PARAMS),
parameter: {
entrypoint: 'stake',
Expand Down Expand Up @@ -518,6 +519,7 @@ export class PrepareProvider extends Provider implements PreparationProvider {
const DEFAULT_PARAMS = await this.getOperationLimits(protocolConstants);
const op = await createTransferOperation({
...rest,
to: pkh,
...mergeLimits({ fee, storageLimit, gasLimit }, DEFAULT_PARAMS),
parameter: {
entrypoint: 'unstake',
Expand Down Expand Up @@ -564,6 +566,8 @@ export class PrepareProvider extends Provider implements PreparationProvider {
const DEFAULT_PARAMS = await this.getOperationLimits(protocolConstants);
const op = await createTransferOperation({
...rest,
to: pkh,
amount: 0,
...mergeLimits({ fee, storageLimit, gasLimit }, DEFAULT_PARAMS),
parameter: {
entrypoint: 'finalize_unstake',
Expand Down
Loading

0 comments on commit 3655961

Please sign in to comment.