@agoric/orchestration 0.1.1-dev-9b5b61a.0 → 0.1.1-dev-9553675.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/orchestration",
3
- "version": "0.1.1-dev-9b5b61a.0+9b5b61a",
3
+ "version": "0.1.1-dev-9553675.0+9553675",
4
4
  "description": "Chain abstraction for Agoric's orchestration clients",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -29,19 +29,19 @@
29
29
  },
30
30
  "homepage": "https://github.com/Agoric/agoric-sdk#readme",
31
31
  "dependencies": {
32
- "@agoric/assert": "0.6.1-dev-9b5b61a.0+9b5b61a",
33
- "@agoric/cosmic-proto": "0.4.1-dev-9b5b61a.0+9b5b61a",
34
- "@agoric/ertp": "0.16.3-dev-9b5b61a.0+9b5b61a",
35
- "@agoric/internal": "0.3.3-dev-9b5b61a.0+9b5b61a",
36
- "@agoric/network": "0.1.1-dev-9b5b61a.0+9b5b61a",
37
- "@agoric/notifier": "0.6.3-dev-9b5b61a.0+9b5b61a",
38
- "@agoric/store": "0.9.3-dev-9b5b61a.0+9b5b61a",
39
- "@agoric/time": "0.3.3-dev-9b5b61a.0+9b5b61a",
40
- "@agoric/vat-data": "0.5.3-dev-9b5b61a.0+9b5b61a",
41
- "@agoric/vats": "0.15.2-dev-9b5b61a.0+9b5b61a",
42
- "@agoric/vow": "0.1.1-dev-9b5b61a.0+9b5b61a",
43
- "@agoric/zoe": "0.26.3-dev-9b5b61a.0+9b5b61a",
44
- "@agoric/zone": "0.2.3-dev-9b5b61a.0+9b5b61a",
32
+ "@agoric/assert": "0.6.1-dev-9553675.0+9553675",
33
+ "@agoric/cosmic-proto": "0.4.1-dev-9553675.0+9553675",
34
+ "@agoric/ertp": "0.16.3-dev-9553675.0+9553675",
35
+ "@agoric/internal": "0.3.3-dev-9553675.0+9553675",
36
+ "@agoric/network": "0.1.1-dev-9553675.0+9553675",
37
+ "@agoric/notifier": "0.6.3-dev-9553675.0+9553675",
38
+ "@agoric/store": "0.9.3-dev-9553675.0+9553675",
39
+ "@agoric/time": "0.3.3-dev-9553675.0+9553675",
40
+ "@agoric/vat-data": "0.5.3-dev-9553675.0+9553675",
41
+ "@agoric/vats": "0.15.2-dev-9553675.0+9553675",
42
+ "@agoric/vow": "0.1.1-dev-9553675.0+9553675",
43
+ "@agoric/zoe": "0.26.3-dev-9553675.0+9553675",
44
+ "@agoric/zone": "0.2.3-dev-9553675.0+9553675",
45
45
  "@endo/base64": "^1.0.5",
46
46
  "@endo/far": "^1.1.2",
47
47
  "@endo/marshal": "^1.5.0",
@@ -83,5 +83,5 @@
83
83
  "typeCoverage": {
84
84
  "atLeast": 96.18
85
85
  },
86
- "gitHead": "9b5b61af3496abdd21313e5373913920b9cf2e3f"
86
+ "gitHead": "9553675cd136d389c427e024fc4da78558344779"
87
87
  }
@@ -2,7 +2,7 @@
2
2
  /**
3
3
  * @file Example contract that uses orchestration
4
4
  */
5
- import { makeTracer } from '@agoric/internal';
5
+ import { makeTracer, StorageNodeShape } from '@agoric/internal';
6
6
  import { makeDurableZone } from '@agoric/zone/durable.js';
7
7
  import { V as E } from '@agoric/vow/vat.js';
8
8
  import { M } from '@endo/patterns';
@@ -13,9 +13,20 @@ const trace = makeTracer('StakeAtom');
13
13
  /**
14
14
  * @import { Baggage } from '@agoric/vat-data';
15
15
  * @import { IBCConnectionID } from '@agoric/vats';
16
+ * @import { TimerService } from '@agoric/time';
16
17
  * @import { ICQConnection, OrchestrationService } from '../types.js';
17
18
  */
18
19
 
20
+ export const meta = harden({
21
+ privateArgsShape: {
22
+ orchestration: M.remotable('orchestration'),
23
+ storageNode: StorageNodeShape,
24
+ marshaller: M.remotable('Marshaller'),
25
+ timer: M.remotable('TimerService'),
26
+ },
27
+ });
28
+ export const privateArgsShape = meta.privateArgsShape;
29
+
19
30
  /**
20
31
  * @typedef {{
21
32
  * hostConnectionId: IBCConnectionID;
@@ -31,6 +42,7 @@ const trace = makeTracer('StakeAtom');
31
42
  * orchestration: OrchestrationService;
32
43
  * storageNode: StorageNode;
33
44
  * marshaller: Marshaller;
45
+ * timer: TimerService;
34
46
  * }} privateArgs
35
47
  * @param {Baggage} baggage
36
48
  */
@@ -38,7 +50,7 @@ export const start = async (zcf, privateArgs, baggage) => {
38
50
  // TODO #9063 this roughly matches what we'll get from Chain<C>.getChainInfo()
39
51
  const { hostConnectionId, controllerConnectionId, bondDenom } =
40
52
  zcf.getTerms();
41
- const { orchestration, marshaller, storageNode } = privateArgs;
53
+ const { orchestration, marshaller, storageNode, timer } = privateArgs;
42
54
 
43
55
  const zone = makeDurableZone(baggage);
44
56
 
@@ -63,11 +75,14 @@ export const start = async (zcf, privateArgs, baggage) => {
63
75
  const accountAddress = await E(account).getAddress();
64
76
  trace('account address', accountAddress);
65
77
  const { holder, invitationMakers } = makeStakingAccountKit(
66
- account,
67
- storageNode,
68
78
  accountAddress,
69
- icqConnection,
70
79
  bondDenom,
80
+ {
81
+ account,
82
+ storageNode,
83
+ icqConnection,
84
+ timer,
85
+ },
71
86
  );
72
87
  return {
73
88
  publicSubscribers: holder.getPublicTopics(),
@@ -5,8 +5,11 @@ import {
5
5
  MsgWithdrawDelegatorRewardResponse,
6
6
  } from '@agoric/cosmic-proto/cosmos/distribution/v1beta1/tx.js';
7
7
  import {
8
+ MsgBeginRedelegate,
8
9
  MsgDelegate,
9
10
  MsgDelegateResponse,
11
+ MsgUndelegate,
12
+ MsgUndelegateResponse,
10
13
  } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js';
11
14
  import {
12
15
  QueryBalanceRequest,
@@ -15,19 +18,31 @@ import {
15
18
  import { Any } from '@agoric/cosmic-proto/google/protobuf/any.js';
16
19
  import { AmountShape } from '@agoric/ertp';
17
20
  import { makeTracer } from '@agoric/internal';
18
- import { UnguardedHelperI } from '@agoric/internal/src/typeGuards.js';
19
21
  import { M, prepareExoClassKit } from '@agoric/vat-data';
20
22
  import { TopicsRecordShape } from '@agoric/zoe/src/contractSupport/index.js';
21
- import { decodeBase64 } from '@endo/base64';
23
+ import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
24
+ import { decodeBase64, encodeBase64 } from '@endo/base64';
22
25
  import { E } from '@endo/far';
23
26
  import { toRequestQueryJson } from '@agoric/cosmic-proto';
24
- import { ChainAddressShape, CoinShape } from '../typeGuards.js';
27
+ import {
28
+ AmountArgShape,
29
+ ChainAddressShape,
30
+ ChainAmountShape,
31
+ CoinShape,
32
+ DelegationShape,
33
+ } from '../typeGuards.js';
34
+
35
+ /** maximum clock skew, in seconds, for unbonding time reported from other chain */
36
+ export const maxClockSkew = 10n * 60n;
25
37
 
26
38
  /**
27
- * @import {ChainAccount, ChainAddress, ChainAmount, CosmosValidatorAddress, ICQConnection} from '../types.js';
39
+ * @import {AmountArg, ChainAccount, ChainAddress, ChainAmount, CosmosValidatorAddress, ICQConnection, StakingAccountActions} from '../types.js';
28
40
  * @import {RecorderKit, MakeRecorderKit} from '@agoric/zoe/src/contractSupport/recorder.js';
29
41
  * @import {Baggage} from '@agoric/swingset-liveslots';
30
42
  * @import {AnyJson} from '@agoric/cosmic-proto';
43
+ * @import { Coin } from '@agoric/cosmic-proto/cosmos/base/v1beta1/coin.js';
44
+ * @import { Delegation } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/staking.js';
45
+ * @import {TimerService} from '@agoric/time';
31
46
  */
32
47
 
33
48
  const trace = makeTracer('StakingAccountHolder');
@@ -45,6 +60,7 @@ const { Fail } = assert;
45
60
  * chainAddress: ChainAddress;
46
61
  * icqConnection: ICQConnection;
47
62
  * bondDenom: string;
63
+ * timer: TimerService;
48
64
  * }} State
49
65
  */
50
66
 
@@ -52,8 +68,17 @@ export const ChainAccountHolderI = M.interface('ChainAccountHolder', {
52
68
  getPublicTopics: M.call().returns(TopicsRecordShape),
53
69
  getAddress: M.call().returns(ChainAddressShape),
54
70
  getBalance: M.callWhen().optional(M.string()).returns(CoinShape),
55
- delegate: M.callWhen(ChainAddressShape, AmountShape).returns(M.record()),
56
- withdrawReward: M.callWhen(ChainAddressShape).returns(M.arrayOf(CoinShape)),
71
+ delegate: M.callWhen(ChainAddressShape, AmountShape).returns(M.undefined()),
72
+ redelegate: M.callWhen(
73
+ ChainAddressShape,
74
+ ChainAddressShape,
75
+ AmountShape,
76
+ ).returns(M.undefined()),
77
+ withdrawReward: M.callWhen(ChainAddressShape).returns(
78
+ M.arrayOf(ChainAmountShape),
79
+ ),
80
+ withdrawRewards: M.callWhen().returns(M.arrayOf(ChainAmountShape)),
81
+ undelegate: M.callWhen(M.arrayOf(DelegationShape)).returns(M.undefined()),
57
82
  });
58
83
 
59
84
  /** @type {{ [name: string]: [description: string, valueShape: Pattern] }} */
@@ -68,6 +93,25 @@ const PUBLIC_TOPICS = {
68
93
  */
69
94
  const toAnyJSON = x => /** @type {AnyJson} */ (Any.toJSON(x));
70
95
 
96
+ export const encodeTxResponse = (response, toProtoMsg) => {
97
+ const protoMsg = toProtoMsg(response);
98
+ const any1 = Any.fromPartial(protoMsg);
99
+ const any2 = Any.fromPartial({ value: Any.encode(any1).finish() });
100
+ const ackStr = encodeBase64(Any.encode(any2).finish());
101
+ return ackStr;
102
+ };
103
+
104
+ export const trivialDelegateResponse = encodeTxResponse(
105
+ {},
106
+ MsgDelegateResponse.toProtoMsg,
107
+ );
108
+
109
+ const expect = (actual, expected, message) => {
110
+ if (actual !== expected) {
111
+ console.log(message, { actual, expected });
112
+ }
113
+ };
114
+
71
115
  /**
72
116
  * @template T
73
117
  * @param {string} ackStr
@@ -98,29 +142,46 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
98
142
  baggage,
99
143
  'Staking Account Holder',
100
144
  {
101
- helper: UnguardedHelperI,
145
+ helper: M.interface('helper', {
146
+ owned: M.call().returns(M.remotable()),
147
+ getUpdater: M.call().returns(M.remotable()),
148
+ amountToCoin: M.call(AmountShape).returns(M.record()),
149
+ }),
102
150
  holder: ChainAccountHolderI,
103
151
  invitationMakers: M.interface('invitationMakers', {
104
- Delegate: M.call(ChainAddressShape, AmountShape).returns(M.promise()),
105
- WithdrawReward: M.call(ChainAddressShape).returns(M.promise()),
106
- CloseAccount: M.call().returns(M.promise()),
107
- TransferAccount: M.call().returns(M.promise()),
152
+ Delegate: M.callWhen(ChainAddressShape, AmountShape).returns(
153
+ InvitationShape,
154
+ ),
155
+ Redelegate: M.callWhen(
156
+ ChainAddressShape,
157
+ ChainAddressShape,
158
+ AmountArgShape,
159
+ ).returns(InvitationShape),
160
+ WithdrawReward: M.callWhen(ChainAddressShape).returns(InvitationShape),
161
+ Undelegate: M.callWhen(M.arrayOf(DelegationShape)).returns(
162
+ InvitationShape,
163
+ ),
164
+ CloseAccount: M.callWhen().returns(InvitationShape),
165
+ TransferAccount: M.callWhen().returns(InvitationShape),
108
166
  }),
109
167
  },
110
168
  /**
111
- * @param {ChainAccount} account
112
- * @param {StorageNode} storageNode
113
169
  * @param {ChainAddress} chainAddress
114
- * @param {ICQConnection} icqConnection
115
170
  * @param {string} bondDenom e.g. 'uatom'
171
+ * @param {object} io
172
+ * @param {ChainAccount} io.account
173
+ * @param {StorageNode} io.storageNode
174
+ * @param {ICQConnection} io.icqConnection
175
+ * @param {TimerService} io.timer
116
176
  * @returns {State}
117
177
  */
118
- (account, storageNode, chainAddress, icqConnection, bondDenom) => {
178
+ (chainAddress, bondDenom, io) => {
179
+ const { storageNode, ...rest } = io;
119
180
  // must be the fully synchronous maker because the kit is held in durable state
120
181
  // @ts-expect-error XXX Patterns
121
182
  const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]);
122
183
 
123
- return { account, chainAddress, topicKit, icqConnection, bondDenom };
184
+ return { chainAddress, bondDenom, topicKit, ...rest };
124
185
  },
125
186
  {
126
187
  helper: {
@@ -135,6 +196,23 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
135
196
  getUpdater() {
136
197
  return this.state.topicKit.recorder;
137
198
  },
199
+ /**
200
+ * @param {AmountArg} amount
201
+ * @returns {Coin}
202
+ */
203
+ amountToCoin(amount) {
204
+ const { bondDenom } = this.state;
205
+ if ('denom' in amount) {
206
+ assert.equal(amount.denom, bondDenom);
207
+ } else {
208
+ trace('TODO: handle brand', amount);
209
+ // FIXME(#9211) brand handling
210
+ }
211
+ return harden({
212
+ denom: bondDenom,
213
+ amount: String(amount.value),
214
+ });
215
+ },
138
216
  },
139
217
  invitationMakers: {
140
218
  /**
@@ -150,6 +228,23 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
150
228
  return this.facets.holder.delegate(validator, amount);
151
229
  }, 'Delegate');
152
230
  },
231
+ /**
232
+ * @param {CosmosValidatorAddress} srcValidator
233
+ * @param {CosmosValidatorAddress} dstValidator
234
+ * @param {AmountArg} amount
235
+ */
236
+ Redelegate(srcValidator, dstValidator, amount) {
237
+ trace('Redelegate', srcValidator, dstValidator, amount);
238
+
239
+ return zcf.makeInvitation(async seat => {
240
+ seat.exit();
241
+ return this.facets.holder.redelegate(
242
+ srcValidator,
243
+ dstValidator,
244
+ amount,
245
+ );
246
+ }, 'Redelegate');
247
+ },
153
248
  /** @param {CosmosValidatorAddress} validator */
154
249
  WithdrawReward(validator) {
155
250
  trace('WithdrawReward', validator);
@@ -159,6 +254,17 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
159
254
  return this.facets.holder.withdrawReward(validator);
160
255
  }, 'WithdrawReward');
161
256
  },
257
+ /**
258
+ * @param {Delegation[]} delegations
259
+ */
260
+ Undelegate(delegations) {
261
+ trace('Undelegate', delegations);
262
+
263
+ return zcf.makeInvitation(async seat => {
264
+ seat.exit();
265
+ return this.facets.holder.undelegate(delegations);
266
+ }, 'Undelegate');
267
+ },
162
268
  CloseAccount() {
163
269
  throw Error('not yet implemented');
164
270
  },
@@ -181,6 +287,7 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
181
287
  },
182
288
  });
183
289
  },
290
+
184
291
  // TODO move this beneath the Orchestration abstraction,
185
292
  // to the OrchestrationAccount provided by makeAccount()
186
293
  /** @returns {ChainAddress} */
@@ -190,33 +297,47 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
190
297
  /**
191
298
  * _Assumes users has already sent funds to their ICA, until #9193
192
299
  * @param {CosmosValidatorAddress} validator
193
- * @param {Amount<'nat'>} ertpAmount
300
+ * @param {AmountArg} amount
194
301
  */
195
- async delegate(validator, ertpAmount) {
196
- trace('delegate', validator, ertpAmount);
197
-
198
- // FIXME brand handling and amount scaling #9211
199
- trace('TODO: handle brand', ertpAmount);
200
- const amount = {
201
- amount: String(ertpAmount.value),
202
- denom: this.state.bondDenom,
203
- };
204
-
205
- const account = this.facets.helper.owned();
206
- const delegatorAddress = this.state.chainAddress.address;
302
+ async delegate(validator, amount) {
303
+ trace('delegate', validator, amount);
304
+ const { helper } = this.facets;
305
+ const { chainAddress } = this.state;
207
306
 
208
- const result = await E(account).executeEncodedTx([
307
+ const result = await E(helper.owned()).executeEncodedTx([
209
308
  toAnyJSON(
210
309
  MsgDelegate.toProtoMsg({
211
- delegatorAddress,
310
+ delegatorAddress: chainAddress.address,
212
311
  validatorAddress: validator.address,
213
- amount,
312
+ amount: helper.amountToCoin(amount),
214
313
  }),
215
314
  ),
216
315
  ]);
217
316
 
218
- if (!result) throw Fail`Failed to delegate.`;
219
- return tryDecodeResponse(result, MsgDelegateResponse.fromProtoMsg);
317
+ expect(result, trivialDelegateResponse, 'MsgDelegateResponse');
318
+ },
319
+ /**
320
+ * _Assumes users has already sent funds to their ICA, until #9193
321
+ * @param {CosmosValidatorAddress} srcValidator
322
+ * @param {CosmosValidatorAddress} dstValidator
323
+ * @param {AmountArg} amount
324
+ */
325
+ async redelegate(srcValidator, dstValidator, amount) {
326
+ trace('redelegate', srcValidator, dstValidator, amount);
327
+ const { helper } = this.facets;
328
+ const { chainAddress } = this.state;
329
+
330
+ // NOTE: response, including completionTime, is currently discarded.
331
+ await E(helper.owned()).executeEncodedTx([
332
+ toAnyJSON(
333
+ MsgBeginRedelegate.toProtoMsg({
334
+ delegatorAddress: chainAddress.address,
335
+ validatorSrcAddress: srcValidator.address,
336
+ validatorDstAddress: dstValidator.address,
337
+ amount: helper.amountToCoin(amount),
338
+ }),
339
+ ),
340
+ ]);
220
341
  },
221
342
 
222
343
  /**
@@ -224,18 +345,21 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
224
345
  * @returns {Promise<ChainAmount[]>}
225
346
  */
226
347
  async withdrawReward(validator) {
348
+ trace('withdrawReward', validator);
349
+ const { helper } = this.facets;
227
350
  const { chainAddress } = this.state;
228
- assert.typeof(validator.address, 'string');
229
351
  const msg = MsgWithdrawDelegatorReward.toProtoMsg({
230
352
  delegatorAddress: chainAddress.address,
231
353
  validatorAddress: validator.address,
232
354
  });
233
- const account = this.facets.helper.owned();
355
+ const account = helper.owned();
234
356
  const result = await E(account).executeEncodedTx([toAnyJSON(msg)]);
235
- const { amount: coins } = tryDecodeResponse(
357
+ const response = tryDecodeResponse(
236
358
  result,
237
359
  MsgWithdrawDelegatorRewardResponse.fromProtoMsg,
238
360
  );
361
+ trace('withdrawReward response', response);
362
+ const { amount: coins } = response;
239
363
  return harden(coins.map(toChainAmount));
240
364
  },
241
365
  /**
@@ -262,9 +386,55 @@ export const prepareStakingAccountKit = (baggage, makeRecorderKit, zcf) => {
262
386
  if (!balance) throw Fail`Result lacked balance key: ${result}`;
263
387
  return harden(toChainAmount(balance));
264
388
  },
389
+
390
+ withdrawRewards() {
391
+ throw assert.error('Not implemented');
392
+ },
393
+
394
+ /**
395
+ * @param {Delegation[]} delegations
396
+ */
397
+ async undelegate(delegations) {
398
+ trace('undelegate', delegations);
399
+ const { helper } = this.facets;
400
+ const { chainAddress, bondDenom, timer } = this.state;
401
+
402
+ const result = await E(helper.owned()).executeEncodedTx(
403
+ delegations.map(d =>
404
+ toAnyJSON(
405
+ MsgUndelegate.toProtoMsg({
406
+ delegatorAddress: chainAddress.address,
407
+ validatorAddress: d.validatorAddress,
408
+ amount: { denom: bondDenom, amount: d.shares },
409
+ }),
410
+ ),
411
+ ),
412
+ );
413
+
414
+ const response = tryDecodeResponse(
415
+ result,
416
+ MsgUndelegateResponse.fromProtoMsg,
417
+ );
418
+ trace('undelegate response', response);
419
+ const { completionTime } = response;
420
+ const endTime = BigInt(completionTime.getTime() / 1000);
421
+
422
+ await E(timer).wakeAt(endTime + maxClockSkew);
423
+ },
265
424
  },
266
425
  },
267
426
  );
427
+
428
+ /** check holder facet against StakingAccountActions interface. */
429
+ // eslint-disable-next-line no-unused-vars
430
+ const typeCheck = () => {
431
+ /** @type {any} */
432
+ const arg = null;
433
+ /** @satisfies { StakingAccountActions } */
434
+ // eslint-disable-next-line no-unused-vars
435
+ const kit = makeStakingAccountKit(arg, arg, arg).holder;
436
+ };
437
+
268
438
  return makeStakingAccountKit;
269
439
  };
270
440
 
@@ -17,6 +17,7 @@ export const startStakeAtom = async (
17
17
  agoricNames,
18
18
  board,
19
19
  chainStorage,
20
+ chainTimerService,
20
21
  orchestration,
21
22
  startUpgradable,
22
23
  },
@@ -56,6 +57,7 @@ export const startStakeAtom = async (
56
57
  orchestration: await orchestration,
57
58
  storageNode,
58
59
  marshaller,
60
+ timer: await chainTimerService,
59
61
  },
60
62
  };
61
63
 
@@ -75,6 +77,7 @@ export const getManifestForStakeAtom = (
75
77
  agoricNames: true,
76
78
  board: true,
77
79
  chainStorage: true,
80
+ chainTimerService: true,
78
81
  orchestration: true,
79
82
  startUpgradable: true,
80
83
  },
package/src/typeGuards.js CHANGED
@@ -1,3 +1,5 @@
1
+ // @ts-check
2
+ import { AmountShape } from '@agoric/ertp';
1
3
  import { M } from '@endo/patterns';
2
4
 
3
5
  export const ConnectionHandlerI = M.interface('ConnectionHandler', {
@@ -18,3 +20,9 @@ export const Proto3Shape = {
18
20
  };
19
21
 
20
22
  export const CoinShape = { value: M.bigint(), denom: M.string() };
23
+
24
+ export const ChainAmountShape = harden({ denom: M.string(), value: M.nat() });
25
+
26
+ export const AmountArgShape = M.or(AmountShape, ChainAmountShape);
27
+
28
+ export const DelegationShape = M.record(); // TODO: DelegationShape fields
package/src/types.d.ts CHANGED
@@ -3,10 +3,6 @@ import type { Timestamp } from '@agoric/time';
3
3
  import type { Invitation } from '@agoric/zoe/exported.js';
4
4
  import type { Any } from '@agoric/cosmic-proto/google/protobuf/any';
5
5
  import type { AnyJson } from '@agoric/cosmic-proto';
6
- import type {
7
- MsgBeginRedelegateResponse,
8
- MsgUndelegateResponse,
9
- } from '@agoric/cosmic-proto/cosmos/staking/v1beta1/tx.js';
10
6
  import type {
11
7
  Delegation,
12
8
  Redelegation,
@@ -283,28 +279,7 @@ export interface ChainAccount {
283
279
  getPort: () => Port;
284
280
  }
285
281
 
286
- /**
287
- * An object that supports high-level operations for an account on a remote chain.
288
- */
289
- export interface BaseOrchestrationAccount {
290
- /** @returns the underlying low-level operation object. */
291
- getChainAcccount: () => Promise<ChainAccount>;
292
-
293
- /**
294
- * @returns the address of the account on the remote chain
295
- */
296
- getAddress: () => ChainAddress;
297
-
298
- /** @returns an array of amounts for every balance in the account. */
299
- getBalances: () => Promise<ChainAmount[]>;
300
-
301
- /** @returns the balance of a specific denom for the account. */
302
- getBalance: (denom: DenomArg) => Promise<ChainAmount>;
303
-
304
- getDenomTrace: (
305
- denom: string,
306
- ) => Promise<{ path: string; base_denom: string }>;
307
-
282
+ export interface StakingAccountQueries {
308
283
  /**
309
284
  * @returns all active delegations from the account to any validator (or [] if none)
310
285
  */
@@ -347,15 +322,8 @@ export interface BaseOrchestrationAccount {
347
322
  * @returns the amount of the account's rewards pending from a specific validator
348
323
  */
349
324
  getReward: (validator: CosmosValidatorAddress) => Promise<ChainAmount[]>;
350
-
351
- /**
352
- * Transfer amount to another account on the same chain. The promise settles when the transfer is complete.
353
- * @param toAccount - the account to send the amount to. MUST be on the same chain
354
- * @param amount - the amount to send
355
- * @returns void
356
- */
357
- send: (toAccount: ChainAddress, amount: AmountArg) => Promise<void>;
358
-
325
+ }
326
+ export interface StakingAccountActions {
359
327
  /**
360
328
  * Delegate an amount to a validator. The promise settles when the delegation is complete.
361
329
  * @param validator - the validator to delegate to
@@ -369,7 +337,7 @@ export interface BaseOrchestrationAccount {
369
337
 
370
338
  /**
371
339
  * Redelegate from one delegator to another.
372
- * Settles when teh redelegation is established, not 21 days later.
340
+ * Settles when the redelegation is established, not 21 days later.
373
341
  * @param srcValidator - the current validator for the delegation.
374
342
  * @param dstValidator - the validator that will receive the delegation.
375
343
  * @param amount - how much to redelegate.
@@ -379,14 +347,15 @@ export interface BaseOrchestrationAccount {
379
347
  srcValidator: CosmosValidatorAddress,
380
348
  dstValidator: CosmosValidatorAddress,
381
349
  amount: AmountArg,
382
- ) => Promise<MsgBeginRedelegateResponse>;
350
+ ) => Promise<void>;
383
351
 
384
352
  /**
385
353
  * Undelegate multiple delegations (concurrently). To delegate independently, pass an array with one item.
386
354
  * Resolves when the undelegation is complete and the tokens are no longer bonded. Note it may take weeks.
355
+ * The unbonding time is padded by 10 minutes to account for clock skew.
387
356
  * @param {Delegation[]} delegations - the delegation to undelegate
388
357
  */
389
- undelegate: (delegations: Delegation[]) => Promise<MsgUndelegateResponse>;
358
+ undelegate: (delegations: Delegation[]) => Promise<void>;
390
359
 
391
360
  /**
392
361
  * Withdraw rewards from all validators. The promise settles when the rewards are withdrawn.
@@ -400,6 +369,39 @@ export interface BaseOrchestrationAccount {
400
369
  * @returns
401
370
  */
402
371
  withdrawReward: (validator: CosmosValidatorAddress) => Promise<ChainAmount[]>;
372
+ }
373
+
374
+ /**
375
+ * An object that supports high-level operations for an account on a remote chain.
376
+ */
377
+ export interface BaseOrchestrationAccount
378
+ extends StakingAccountQueries,
379
+ StakingAccountActions {
380
+ /** @returns the underlying low-level operation object. */
381
+ getChainAcccount: () => Promise<ChainAccount>;
382
+
383
+ /**
384
+ * @returns the address of the account on the remote chain
385
+ */
386
+ getAddress: () => ChainAddress;
387
+
388
+ /** @returns an array of amounts for every balance in the account. */
389
+ getBalances: () => Promise<ChainAmount[]>;
390
+
391
+ /** @returns the balance of a specific denom for the account. */
392
+ getBalance: (denom: DenomArg) => Promise<ChainAmount>;
393
+
394
+ getDenomTrace: (
395
+ denom: string,
396
+ ) => Promise<{ path: string; base_denom: string }>;
397
+
398
+ /**
399
+ * Transfer amount to another account on the same chain. The promise settles when the transfer is complete.
400
+ * @param toAccount - the account to send the amount to. MUST be on the same chain
401
+ * @param amount - the amount to send
402
+ * @returns void
403
+ */
404
+ send: (toAccount: ChainAddress, amount: AmountArg) => Promise<void>;
403
405
 
404
406
  /**
405
407
  * Transfer an amount to another account, typically on another chain.