Skip to content

Commit

Permalink
delegate/undelegate (#9421)
Browse files Browse the repository at this point in the history
## Description

Filling out some use case and test coverage. This adds undelegate to
LCA.

Also a bunch of cleanup.

### Security Considerations

<!-- Does this change introduce new assumptions or dependencies that, if
violated, could introduce security vulnerabilities? How does this PR
change the boundaries between mutually-suspicious components? What new
authorities are introduced by this change, perhaps by new API calls?
-->

### Scaling Considerations

<!-- Does this change require or encourage significant increase in
consumption of CPU cycles, RAM, on-chain storage, message exchanges, or
other scarce resources? If so, can that be prevented or mitigated? -->

### Documentation Considerations

<!-- Give our docs folks some hints about what needs to be described to
downstream users.

Backwards compatibility: what happens to existing data or deployments
when this code is shipped? Do we need to instruct users to do something
to upgrade their saved data? If there is no upgrade path possible, how
bad will that be for users?

-->

### Testing Considerations

<!-- Every PR should of course come with tests of its own functionality.
What additional tests are still needed beyond those unit tests? How does
this affect CI, other test automation, or the testnet?
-->

### Upgrade Considerations

<!-- What aspects of this PR are relevant to upgrading live production
systems, and how should they be addressed? -->
  • Loading branch information
mergify[bot] committed May 30, 2024
2 parents b395841 + a18d21c commit df4954e
Show file tree
Hide file tree
Showing 20 changed files with 442 additions and 261 deletions.
89 changes: 89 additions & 0 deletions packages/boot/test/bootstrapTests/lca.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import type { TestFn } from 'ava';

import { Fail } from '@agoric/assert';
import { AmountMath } from '@agoric/ertp';
import type { start as stakeBldStart } from '@agoric/orchestration/src/examples/stakeBld.contract.js';
import type { Instance } from '@agoric/zoe/src/zoeService/utils.js';
import { M, matches } from '@endo/patterns';
import { makeWalletFactoryContext } from './walletFactory.ts';

type DefaultTestContext = Awaited<ReturnType<typeof makeWalletFactoryContext>>;

const test: TestFn<DefaultTestContext> = anyTest;

test.before(async t => (t.context = await makeWalletFactoryContext(t)));
test.after.always(t => t.context.shutdown?.());

test.serial('stakeBld', async t => {
const {
agoricNamesRemotes,
buildProposal,
evalProposal,
refreshAgoricNamesRemotes,
} = t.context;
// TODO move into a vm-config for u15
await evalProposal(
buildProposal('@agoric/builders/scripts/vats/init-localchain.js'),
);
// start-stakeBld depends on this. Sanity check in case the context changes.
const { BLD } = agoricNamesRemotes.brand;
BLD || Fail`BLD missing from agoricNames`;
await evalProposal(
buildProposal('@agoric/builders/scripts/orchestration/init-stakeBld.js'),
);
// update now that stakeBld is instantiated
refreshAgoricNamesRemotes();
const stakeBld = agoricNamesRemotes.instance.stakeBld as Instance<
typeof stakeBldStart
>;
t.truthy(stakeBld);

const wd = await t.context.walletFactoryDriver.provideSmartWallet(
'agoric1testStakeBld',
);

await wd.executeOffer({
id: 'request-stake',
invitationSpec: {
source: 'agoricContract',
instancePath: ['stakeBld'],
callPipe: [['makeStakeBldInvitation']],
},
proposal: {
give: {
// @ts-expect-error XXX BoardRemote
In: { brand: BLD, value: 10n },
},
},
});

const current = await wd.getCurrentWalletRecord();
const latest = await wd.getLatestUpdateRecord();
t.like(current, {
offerToPublicSubscriberPaths: [
// TODO publish something useful
['request-stake', { account: 'published.stakeBld' }],
],
});
t.like(latest, {
status: { id: 'request-stake', numWantsSatisfied: 1 },
});

await wd.executeOffer({
id: 'request-delegate',
invitationSpec: {
source: 'continuing',
previousOffer: 'request-stake',
invitationMakerName: 'Delegate',
invitationArgs: ['agoric1validator1', { brand: BLD, value: 10n }],
},
proposal: {
give: {
// @ts-expect-error XXX BoardRemote
In: { brand: BLD, value: 10n },
},
},
});
});
84 changes: 7 additions & 77 deletions packages/boot/test/bootstrapTests/orchestration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import type { TestFn } from 'ava';

import { Fail } from '@agoric/assert';
import { AmountMath } from '@agoric/ertp';
import type { start as stakeBldStart } from '@agoric/orchestration/src/examples/stakeBld.contract.js';
import type { Instance } from '@agoric/zoe/src/zoeService/utils.js';
import { M, matches } from '@endo/patterns';
import type { CosmosValidatorAddress } from '@agoric/orchestration';
import type { start as startStakeAtom } from '@agoric/orchestration/src/examples/stakeAtom.contract.js';
import { makeWalletFactoryContext } from './walletFactory.ts';

type DefaultTestContext = Awaited<ReturnType<typeof makeWalletFactoryContext>>;
Expand All @@ -17,85 +17,13 @@ const test: TestFn<DefaultTestContext> = anyTest;
test.before(async t => (t.context = await makeWalletFactoryContext(t)));
test.after.always(t => t.context.shutdown?.());

test.serial('stakeBld', async t => {
const {
agoricNamesRemotes,
buildProposal,
evalProposal,
refreshAgoricNamesRemotes,
} = t.context;
// TODO move into a vm-config for u15
await evalProposal(
buildProposal('@agoric/builders/scripts/vats/init-localchain.js'),
);
// start-stakeBld depends on this. Sanity check in case the context changes.
const { BLD } = agoricNamesRemotes.brand;
BLD || Fail`BLD missing from agoricNames`;
await evalProposal(
buildProposal('@agoric/builders/scripts/orchestration/init-stakeBld.js'),
);
// update now that stakeBld is instantiated
refreshAgoricNamesRemotes();
const stakeBld = agoricNamesRemotes.instance.stakeBld as Instance<
typeof stakeBldStart
>;
t.truthy(stakeBld);

const wd = await t.context.walletFactoryDriver.provideSmartWallet(
'agoric1testStakeBld',
);

await wd.executeOffer({
id: 'request-stake',
invitationSpec: {
source: 'agoricContract',
instancePath: ['stakeBld'],
callPipe: [['makeStakeBldInvitation']],
},
proposal: {
give: {
// @ts-expect-error XXX BoardRemote
In: { brand: BLD, value: 10n },
},
},
});

const current = await wd.getCurrentWalletRecord();
const latest = await wd.getLatestUpdateRecord();
t.like(current, {
offerToPublicSubscriberPaths: [
// TODO publish something useful
['request-stake', { account: 'published.stakeBld' }],
],
});
t.like(latest, {
status: { id: 'request-stake', numWantsSatisfied: 1 },
});

await wd.executeOffer({
id: 'request-delegate',
invitationSpec: {
source: 'continuing',
previousOffer: 'request-stake',
invitationMakerName: 'Delegate',
invitationArgs: ['agoric1validator1', { brand: BLD, value: 10n }],
},
proposal: {
give: {
// @ts-expect-error XXX BoardRemote
In: { brand: BLD, value: 10n },
},
},
});
});

test.serial('stakeAtom - repl-style', async t => {
const {
buildProposal,
evalProposal,
runUtils: { EV },
} = t.context;
// TODO move into a vm-config for u15
// TODO move into a vm-config
await evalProposal(
buildProposal('@agoric/builders/scripts/vats/init-network.js'),
);
Expand All @@ -107,10 +35,12 @@ test.serial('stakeAtom - repl-style', async t => {
);

const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames');
const instance = await EV(agoricNames).lookup('instance', 'stakeAtom');
const instance: Instance<typeof startStakeAtom> = await EV(
agoricNames,
).lookup('instance', 'stakeAtom');
t.truthy(instance, 'stakeAtom instance is available');

const zoe = await EV.vat('bootstrap').consumeItem('zoe');
const zoe: ZoeService = await EV.vat('bootstrap').consumeItem('zoe');
const publicFacet = await EV(zoe).getPublicFacet(instance);
t.truthy(publicFacet, 'stakeAtom publicFacet is available');

Expand All @@ -122,7 +52,7 @@ test.serial('stakeAtom - repl-style', async t => {
'account is a remotable',
);

const atomBrand = await EV(agoricNames).lookup('brand', 'ATOM');
const atomBrand: Brand = await EV(agoricNames).lookup('brand', 'ATOM');
const atomAmount = AmountMath.make(atomBrand, 10n);

const validatorAddress: CosmosValidatorAddress = {
Expand Down
5 changes: 5 additions & 0 deletions packages/cosmic-proto/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import type {
import type {
MsgDelegate,
MsgDelegateResponse,
MsgUndelegate,
MsgUndelegateResponse,
} from './codegen/cosmos/staking/v1beta1/tx.js';
import type { Any } from './codegen/google/protobuf/any.js';
import {
Expand All @@ -33,6 +35,8 @@ export type Proto3Shape = {
'/cosmos.bank.v1beta1.QueryAllBalancesResponse': QueryAllBalancesResponse;
'/cosmos.staking.v1beta1.MsgDelegate': MsgDelegate;
'/cosmos.staking.v1beta1.MsgDelegateResponse': MsgDelegateResponse;
'/cosmos.staking.v1beta1.MsgUndelegate': MsgUndelegate;
'/cosmos.staking.v1beta1.MsgUndelegateResponse': MsgUndelegateResponse;
'/ibc.applications.transfer.v1.MsgTransfer': MsgTransfer;
'/ibc.applications.transfer.v1.MsgTransferResponse': MsgTransferResponse;
};
Expand All @@ -43,6 +47,7 @@ type ResponseMap = {
'/cosmos.bank.v1beta1.QueryAllBalancesRequest': '/cosmos.bank.v1beta1.QueryAllBalancesResponse';
'/cosmos.staking.v1beta1.MsgDelegate': '/cosmos.staking.v1beta1.MsgDelegateResponse';
'/ibc.applications.transfer.v1.MsgTransfer': '/ibc.applications.transfer.v1.MsgTransferResponse';
'/cosmos.staking.v1beta1.MsgUndelegate': '/cosmos.staking.v1beta1.MsgUndelegateResponse';
};

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/orchestration/src/examples/stakeAtom.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const start = async (zcf, privateArgs, baggage) => {
const { makeRecorderKit } = prepareRecorderKitMakers(baggage, marshaller);

const makeStakingAccountKit = prepareStakingAccountKit(
baggage,
zone,
makeRecorderKit,
zcf,
);
Expand Down
8 changes: 7 additions & 1 deletion packages/orchestration/src/examples/stakeBld.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const start = async (zcf, privateArgs, baggage) => {
const agoricChainInfo = prepareMockChainInfo(zone);

const makeLocalChainAccountKit = prepareLocalChainAccountKit(
baggage,
zone,
makeRecorderKit,
zcf,
privateArgs.timerService,
Expand All @@ -75,6 +75,9 @@ export const start = async (zcf, privateArgs, baggage) => {
makeStakeBldInvitation: M.callWhen().returns(InvitationShape),
}),
{
/**
* Invitation to make an account, initialized with the give's BLD
*/
makeStakeBldInvitation() {
return zcf.makeInvitation(
async seat => {
Expand Down Expand Up @@ -104,6 +107,9 @@ export const start = async (zcf, privateArgs, baggage) => {
const { holder } = await makeLocalAccountKit();
return holder;
},
/**
* Invitation to make an account, without any funds
*/
makeAccountInvitationMaker() {
trace('makeCreateAccountInvitation');
return zcf.makeInvitation(async seat => {
Expand Down
10 changes: 6 additions & 4 deletions packages/orchestration/src/examples/unbondExample.contract.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Far } from '@endo/far';
import { M } from '@endo/patterns';
import { makeDurableZone } from '@agoric/zone/durable.js';
import { makeOrchestrationFacade } from '../facade.js';

/**
* @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js'
* @import {TimerService} from '@agoric/time';
* @import {Baggage} from '@agoric/vat-data';
* @import {LocalChain} from '@agoric/vats/src/localchain.js';
* @import {Remote} from '@agoric/internal';
* @import {OrchestrationService} from '../service.js';
* @import {Zone} from '@agoric/zone';
*/

/**
Expand All @@ -18,12 +19,13 @@ import { makeOrchestrationFacade } from '../facade.js';
* orchestrationService: Remote<OrchestrationService>;
* storageNode: Remote<StorageNode>;
* timerService: Remote<TimerService>;
* zone: Zone;
* }} privateArgs
* @param {Baggage} baggage
*/
export const start = async (zcf, privateArgs) => {
const { localchain, orchestrationService, storageNode, timerService, zone } =
export const start = async (zcf, privateArgs, baggage) => {
const { localchain, orchestrationService, storageNode, timerService } =
privateArgs;
const zone = makeDurableZone(baggage);

const { orchestrate } = makeOrchestrationFacade({
localchain,
Expand Down
Loading

0 comments on commit df4954e

Please sign in to comment.