Skip to content

Commit

Permalink
refactor: refine StakingAccountHolder facets
Browse files Browse the repository at this point in the history
 - implement delegate() etc. directly on holder;
   - avoids unguarded helper methods
   - since these methods don't have multiple callers,
     it makes little sense to put them on the helper facet anyway
 - call zcf.makeInvitation() directly from invitationMaker facet
   methods; prune makeXInvitation methods on holder
  • Loading branch information
dckc committed May 3, 2024
1 parent 17c2932 commit aa79cd5
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 86 deletions.
136 changes: 53 additions & 83 deletions packages/orchestration/src/exos/stakingAccountKit.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ const { Fail } = assert;

const HolderI = M.interface('holder', {
getPublicTopics: M.call().returns(TopicsRecordShape),
makeDelegateInvitation: M.call(M.string(), AmountShape).returns(M.promise()),
makeWithdrawRewardInvitation: M.call(M.string()).returns(M.promise()),
makeCloseAccountInvitation: M.call().returns(M.promise()),
makeTransferAccountInvitation: M.call().returns(M.promise()),
delegate: M.callWhen(M.string(), AmountShape).returns(M.record()),
withdrawReward: M.callWhen(M.string()).returns(M.array()),
});

/** @type {{ [name: string]: [description: string, valueShape: Pattern] }} */
Expand Down Expand Up @@ -94,12 +91,10 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
helper: UnguardedHelperI,
holder: HolderI,
invitationMakers: M.interface('invitationMakers', {
Delegate: HolderI.payload.methodGuards.makeDelegateInvitation,
WithdrawReward:
HolderI.payload.methodGuards.makeWithdrawRewardInvitation,
CloseAccount: HolderI.payload.methodGuards.makeCloseAccountInvitation,
TransferAccount:
HolderI.payload.methodGuards.makeTransferAccountInvitation,
Delegate: M.call(M.string(), AmountShape).returns(M.promise()),
WithdrawReward: M.call(M.string()).returns(M.promise()),
CloseAccount: M.call().returns(M.promise()),
TransferAccount: M.call().returns(M.promise()),
}),
},
/**
Expand Down Expand Up @@ -127,6 +122,52 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
getUpdater() {
return this.state.topicKit.recorder;
},
},
invitationMakers: {
/**
*
* @param {string} validatorAddress
* @param {Amount<'nat'>} amount
*/
Delegate(validatorAddress, amount) {
trace('Delegate', validatorAddress, amount);

return zcf.makeInvitation(async seat => {
seat.exit();
return this.facets.holder.delegate(validatorAddress, amount);
}, 'Delegate');
},
/** @param {string} validatorAddress */
WithdrawReward(validatorAddress) {
trace('WithdrawReward', validatorAddress);

return zcf.makeInvitation(async seat => {
seat.exit();
return this.facets.holder.withdrawReward(validatorAddress);
}, 'WithdrawReward');
},
CloseAccount() {
throw Error('not yet implemented');
},
/**
* Starting a transfer revokes the account holder. The associated updater
* will get a special notification that the account is being transferred.
*/
TransferAccount() {
throw Error('not yet implemented');
},
},
holder: {
getPublicTopics() {
const { topicKit } = this.state;
return harden({
account: {
description: PUBLIC_TOPICS.account[0],
subscriber: topicKit.subscriber,
storagePath: topicKit.recorder.getStoragePath(),
},
});
},
// TODO move this beneath the Orchestration abstraction,
// to the OrchestrationAccount provided by makeAccount()
/**
Expand All @@ -135,6 +176,8 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
* @param {Amount<'nat'>} ertpAmount
*/
async delegate(validatorAddress, ertpAmount) {
trace('delegate', validatorAddress, ertpAmount);

// FIXME get values from proposal or args
// FIXME brand handling and amount scaling
trace('TODO: handle brand', ertpAmount);
Expand Down Expand Up @@ -180,79 +223,6 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
return harden(coins.map(toChainAmount));
},
},
invitationMakers: {
Delegate(validatorAddress, amount) {
return this.facets.holder.makeDelegateInvitation(
validatorAddress,
amount,
);
},
/** @param {string} validatorAddress */
WithdrawReward(validatorAddress) {
return this.facets.holder.makeWithdrawRewardInvitation(
validatorAddress,
);
},
CloseAccount() {
return this.facets.holder.makeCloseAccountInvitation();
},
TransferAccount() {
return this.facets.holder.makeTransferAccountInvitation();
},
},
holder: {
getPublicTopics() {
const { topicKit } = this.state;
return harden({
account: {
description: PUBLIC_TOPICS.account[0],
subscriber: topicKit.subscriber,
storagePath: topicKit.recorder.getStoragePath(),
},
});
},
/**
*
* @param {string} validatorAddress
* @param {Amount<'nat'>} ertpAmount
*/
async delegate(validatorAddress, ertpAmount) {
trace('delegate', validatorAddress, ertpAmount);
return this.facets.helper.delegate(validatorAddress, ertpAmount);
},
/**
*
* @param {string} validatorAddress
* @param {Amount<'nat'>} ertpAmount
*/
makeDelegateInvitation(validatorAddress, ertpAmount) {
trace('makeDelegateInvitation', validatorAddress, ertpAmount);

return zcf.makeInvitation(async seat => {
seat.exit();
return this.facets.helper.delegate(validatorAddress, ertpAmount);
}, 'Delegate');
},
/** @param {string} validatorAddress */
makeWithdrawRewardInvitation(validatorAddress) {
trace('makeWithdrawRewardInvitation', validatorAddress);

return zcf.makeInvitation(async seat => {
seat.exit();
return this.facets.helper.withdrawReward(validatorAddress);
}, 'WithdrawReward');
},
makeCloseAccountInvitation() {
throw Error('not yet implemented');
},
/**
* Starting a transfer revokes the account holder. The associated updater
* will get a special notification that the account is being transferred.
*/
makeTransferAccountInvitation() {
throw Error('not yet implemented');
},
},
},
);
return makeStakingAccountKit;
Expand Down
6 changes: 3 additions & 3 deletions packages/orchestration/test/test-withdraw-reward.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,10 @@ test('withdraw rewards from staking account holder', async t => {
const { baggage, makeRecorderKit, storageNode, zcf } = s;
const make = prepareStakingAccountKit(baggage, makeRecorderKit, zcf);

// `helper` is a somewhat internal API;
// Higher fidelity tests below use invitationMakers.
const { helper } = make(account, storageNode, account.getAddress());
const { holder } = make(account, storageNode, account.getAddress());
const { validator } = scenario1;
const actual = await E(helper).withdrawReward(validator.address);
const actual = await E(holder).withdrawReward(validator.address);
t.deepEqual(actual, [{ denom: 'uatom', value: 2n }]);
const msg = {
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward',
Expand All @@ -181,6 +180,7 @@ test(`delegate; withdraw rewards`, async t => {
const { validator, delegations } = scenario1;
{
const value = BigInt(Object.values(delegations)[0].amount);
/** @type {Amount<'nat'>} */
const anAmount = { brand: Far('Token'), value };
const toDelegate = await E(invitationMakers).Delegate(
validator.address,
Expand Down

0 comments on commit aa79cd5

Please sign in to comment.