Skip to content

Commit

Permalink
feat: continuing inv as flows (wip)
Browse files Browse the repository at this point in the history
- rewrites some logic in restake.kit.js as flows
- uses mocked PersistentState to represent a non-existent exo for sharing state across flows
  - this exo will also need to accept flows as instantiation and return them as part of a ContinuingOfferResult
  • Loading branch information
0xpatrickdev committed Aug 1, 2024
1 parent d6f9b7a commit 12d8122
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 3 deletions.
122 changes: 120 additions & 2 deletions packages/orchestration/src/examples/restake.flows.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
* @file Example contract that allows users to do different things with rewards
*/
import { M, mustMatch } from '@endo/patterns';
import { Fail } from '@endo/errors';
import { ChainAddressShape } from '../typeGuards.js';
import { RepeaterOptsShape } from './restake.kit.js';

/**
* @import {OrchestrationAccount, OrchestrationFlow, Orchestrator, StakingAccountActions} from '@agoric/orchestration';
* @import {MakeRestakeHolderKit} from './restake.kit.js';
* @import {CosmosValidatorAddress, OrchestrationAccount, OrchestrationFlow, Orchestrator, StakingAccountActions} from '@agoric/orchestration';
* @import {MakeRestakeHolderKit, MakeRestakeWaker, RestakeParams, RepeaterOpts} from './restake.kit.js';
* @import {MakeCombineInvitationMakers} from '../exos/combine-invitation-makers.js';
* @import {TimerRepeater, TimestampRecord, TimerService} from '@agoric/time';
*/

/**
Expand Down Expand Up @@ -51,3 +55,117 @@ export const makeRestakeAccount = async (
publicSubscribers,
});
};

/**
* Placeholder for an (per continuing) Exo that's part of ctx.
*
* Since some values are not available during initialization, we need some sort
* of pattern for setting and getting state.
*
* XXX consider a more simple `getState/setState`
*
* XXX for this exo, need a mechanism to invoke asyncFlows for Restake and
* CancelRestake
*
* @typedef {{
* getAccount: () => Promise<
* OrchestrationAccount<any> & StakingAccountActions
* >;
* setAccount: (
* account: OrchestrationAccount<any> & StakingAccountActions,
* ) => Promise<void>;
* getRepeater: () => Promise<TimerRepeater>;
* setRepeater: (repeater: TimerRepeater) => Promise<void>;
* getValidator: () => Promise<CosmosValidatorAddress>;
* setValidator: (validator: CosmosValidatorAddress) => Promise<void>;
* }} PersistentState
*/

/**
* NOT CURRENTLY USED
*
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} _orch
* @param {{
* makeRestakeWaker: MakeRestakeWaker;
* timerService: TimerService;
* opts: RestakeParams;
* state: PersistentState;
* }} ctx
* @param {ZCFSeat} seat
* @param {{ validator: CosmosValidatorAddress; opts: RepeaterOpts }} offerArgs
*/
export const makeRestakeHandler = async (
_orch,
{
state,
makeRestakeWaker,
timerService,
opts: { minimumDelay, minimumInterval },
},
seat,
{ validator, opts },
) => {
seat.exit(); // no funds exchanged
mustMatch(validator, ChainAddressShape, 'invalid validator address');
mustMatch(opts, RepeaterOptsShape, 'invalid repeater options');

const { delay, interval } = opts;
delay >= minimumDelay || Fail`delay must be at least ${minimumDelay}`;
interval >= minimumInterval ||
Fail`interval must be at least ${minimumInterval}`;

// XXX make stateKit real
const activeRepeater = await state.getRepeater();

// only one repeater at a time
// XXX consider logic to allow one per validator
if (activeRepeater) {
await activeRepeater.disable();
}
// XXX make stateKit real
const orchAccount = await state.getAccount();
// XXX can we put the waker logic in an async-flow? And have something that turns this into TimerWaker exo
const restakeWaker = makeRestakeWaker(orchAccount, validator);
const repeater = await timerService.makeRepeater(delay, interval);
await repeater.schedule(restakeWaker);
return state.setRepeater(repeater);
};

/**
* NOT CURRENTLY USED
*
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} _orch
* @param {{ state: PersistentState }} ctx
* @param {ZCFSeat} seat
*/
export const makeCancelRestakeHandler = async (_orch, { state }, seat) => {
seat.exit(); // no funds exchanged
// XXX make stateKit real
const repeater = await state.getRepeater();
repeater || Fail`No active restake to cancel.`;
return repeater.disable();
};

/**
* NOT CURRENTLY USED
*
* @satisfies {OrchestrationFlow}
* @param {Orchestrator} _orch
* @param {{ state: PersistentState }} ctx
* @param {TimestampRecord} timestampRecord
*/
export const makeWakerHandler = async (_orch, { state }, timestampRecord) => {
console.log('Wake Received', timestampRecord);
const orchAccount = await state.getAccount();
const validator = await state.getValidator();

const amounts = await orchAccount.withdrawReward(validator);
if (amounts.length !== 1) {
throw Fail`Received ${amounts.length} amounts, only expected one.`;
}
if (!amounts[0].value) return;

return orchAccount.delegate(validator, amounts[0]);
};
4 changes: 3 additions & 1 deletion packages/orchestration/src/examples/restake.kit.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export const prepareRestakeWaker = (zone, vowTools) => {
return (...args) => makeKit(...args).waker;
};

/** @typedef {ReturnType<typeof prepareRestakeWaker>} MakeRestakeWaker */

/**
* @typedef {{
* orchAccount: OrchestrationAccount<any> & StakingAccountActions;
Expand All @@ -113,7 +115,7 @@ const RepeaterStateShape = {
* }} RepeaterOpts
*/

const RepeaterOptsShape = {
export const RepeaterOptsShape = {
delay: M.nat(),
interval: M.nat(),
};
Expand Down

0 comments on commit 12d8122

Please sign in to comment.