@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 +15 -15
- package/src/examples/stakeAtom.contract.js +20 -5
- package/src/exos/stakingAccountKit.js +207 -37
- package/src/proposals/start-stakeAtom.js +3 -0
- package/src/typeGuards.js +8 -0
- package/src/types.d.ts +40 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/orchestration",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
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-
|
|
33
|
-
"@agoric/cosmic-proto": "0.4.1-dev-
|
|
34
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
35
|
-
"@agoric/internal": "0.3.3-dev-
|
|
36
|
-
"@agoric/network": "0.1.1-dev-
|
|
37
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
38
|
-
"@agoric/store": "0.9.3-dev-
|
|
39
|
-
"@agoric/time": "0.3.3-dev-
|
|
40
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
41
|
-
"@agoric/vats": "0.15.2-dev-
|
|
42
|
-
"@agoric/vow": "0.1.1-dev-
|
|
43
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
44
|
-
"@agoric/zone": "0.2.3-dev-
|
|
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": "
|
|
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 {
|
|
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 {
|
|
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.
|
|
56
|
-
|
|
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:
|
|
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.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
(
|
|
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 {
|
|
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 {
|
|
300
|
+
* @param {AmountArg} amount
|
|
194
301
|
*/
|
|
195
|
-
async delegate(validator,
|
|
196
|
-
trace('delegate', validator,
|
|
197
|
-
|
|
198
|
-
|
|
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(
|
|
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
|
-
|
|
219
|
-
|
|
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 =
|
|
355
|
+
const account = helper.owned();
|
|
234
356
|
const result = await E(account).executeEncodedTx([toAnyJSON(msg)]);
|
|
235
|
-
const
|
|
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
|
|
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<
|
|
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<
|
|
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.
|