@agoric/orchestration 0.1.1-calypso-dev-84eb287.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/LICENSE +201 -0
- package/README.md +5 -0
- package/index.d.ts +4 -0
- package/index.js +7 -0
- package/package.json +95 -0
- package/src/chain-info.d.ts +2318 -0
- package/src/chain-info.d.ts.map +1 -0
- package/src/chain-info.js +114 -0
- package/src/cosmos-api.d.ts +174 -0
- package/src/cosmos-api.d.ts.map +1 -0
- package/src/cosmos-api.ts +231 -0
- package/src/ethereum-api.d.ts +8 -0
- package/src/ethereum-api.d.ts.map +1 -0
- package/src/ethereum-api.ts +7 -0
- package/src/examples/sendAnywhere.contract.d.ts +31 -0
- package/src/examples/sendAnywhere.contract.d.ts.map +1 -0
- package/src/examples/sendAnywhere.contract.js +171 -0
- package/src/examples/stakeBld.contract.d.ts +121 -0
- package/src/examples/stakeBld.contract.d.ts.map +1 -0
- package/src/examples/stakeBld.contract.js +133 -0
- package/src/examples/stakeIca.contract.d.ts +93 -0
- package/src/examples/stakeIca.contract.d.ts.map +1 -0
- package/src/examples/stakeIca.contract.js +143 -0
- package/src/examples/swapExample.contract.d.ts +34 -0
- package/src/examples/swapExample.contract.d.ts.map +1 -0
- package/src/examples/swapExample.contract.js +155 -0
- package/src/examples/unbondExample.contract.d.ts +21 -0
- package/src/examples/unbondExample.contract.d.ts.map +1 -0
- package/src/examples/unbondExample.contract.js +105 -0
- package/src/exos/README.md +56 -0
- package/src/exos/agoric-names-tools.d.ts +27 -0
- package/src/exos/agoric-names-tools.d.ts.map +1 -0
- package/src/exos/agoric-names-tools.js +109 -0
- package/src/exos/chain-account-kit.d.ts +88 -0
- package/src/exos/chain-account-kit.d.ts.map +1 -0
- package/src/exos/chain-account-kit.js +210 -0
- package/src/exos/chain-hub.d.ts +77 -0
- package/src/exos/chain-hub.d.ts.map +1 -0
- package/src/exos/chain-hub.js +214 -0
- package/src/exos/cosmos-orchestration-account.d.ts +207 -0
- package/src/exos/cosmos-orchestration-account.d.ts.map +1 -0
- package/src/exos/cosmos-orchestration-account.js +536 -0
- package/src/exos/icq-connection-kit.d.ts +50 -0
- package/src/exos/icq-connection-kit.d.ts.map +1 -0
- package/src/exos/icq-connection-kit.js +135 -0
- package/src/exos/local-chain-facade.d.ts +81 -0
- package/src/exos/local-chain-facade.d.ts.map +1 -0
- package/src/exos/local-chain-facade.js +113 -0
- package/src/exos/local-orchestration-account.d.ts +176 -0
- package/src/exos/local-orchestration-account.d.ts.map +1 -0
- package/src/exos/local-orchestration-account.js +446 -0
- package/src/exos/orchestrator.d.ts +91 -0
- package/src/exos/orchestrator.d.ts.map +1 -0
- package/src/exos/orchestrator.js +141 -0
- package/src/exos/remote-chain-facade.d.ts +144 -0
- package/src/exos/remote-chain-facade.d.ts.map +1 -0
- package/src/exos/remote-chain-facade.js +145 -0
- package/src/facade.d.ts +57 -0
- package/src/facade.d.ts.map +1 -0
- package/src/facade.js +132 -0
- package/src/fetched-chain-info.d.ts +2311 -0
- package/src/fetched-chain-info.d.ts.map +1 -0
- package/src/fetched-chain-info.js +2288 -0
- package/src/internal.d.ts +13 -0
- package/src/internal.d.ts.map +1 -0
- package/src/internal.ts +20 -0
- package/src/orchestration-api.d.ts +158 -0
- package/src/orchestration-api.d.ts.map +1 -0
- package/src/orchestration-api.ts +201 -0
- package/src/proposals/orchestration-proposal.d.ts +53 -0
- package/src/proposals/orchestration-proposal.d.ts.map +1 -0
- package/src/proposals/orchestration-proposal.js +179 -0
- package/src/proposals/revise-chain-info.d.ts +21 -0
- package/src/proposals/revise-chain-info.d.ts.map +1 -0
- package/src/proposals/revise-chain-info.js +44 -0
- package/src/proposals/start-stakeAtom.d.ts +109 -0
- package/src/proposals/start-stakeAtom.d.ts.map +1 -0
- package/src/proposals/start-stakeAtom.js +105 -0
- package/src/proposals/start-stakeBld.d.ts +154 -0
- package/src/proposals/start-stakeBld.d.ts.map +1 -0
- package/src/proposals/start-stakeBld.js +103 -0
- package/src/proposals/start-stakeOsmo.d.ts +108 -0
- package/src/proposals/start-stakeOsmo.d.ts.map +1 -0
- package/src/proposals/start-stakeOsmo.js +106 -0
- package/src/service.d.ts +97 -0
- package/src/service.d.ts.map +1 -0
- package/src/service.js +259 -0
- package/src/typeGuards.d.ts +55 -0
- package/src/typeGuards.d.ts.map +1 -0
- package/src/typeGuards.js +104 -0
- package/src/types.d.ts +11 -0
- package/src/types.d.ts.map +1 -0
- package/src/types.ts +11 -0
- package/src/utils/address.d.ts +14 -0
- package/src/utils/address.d.ts.map +1 -0
- package/src/utils/address.js +79 -0
- package/src/utils/cosmos.d.ts +9 -0
- package/src/utils/cosmos.d.ts.map +1 -0
- package/src/utils/cosmos.js +36 -0
- package/src/utils/orc.d.ts +17 -0
- package/src/utils/orc.d.ts.map +1 -0
- package/src/utils/orc.js +38 -0
- package/src/utils/orchestrationAccount.d.ts +10 -0
- package/src/utils/orchestrationAccount.d.ts.map +1 -0
- package/src/utils/orchestrationAccount.js +22 -0
- package/src/utils/packet.d.ts +57 -0
- package/src/utils/packet.d.ts.map +1 -0
- package/src/utils/packet.js +112 -0
- package/src/utils/registry.d.ts +13 -0
- package/src/utils/registry.d.ts.map +1 -0
- package/src/utils/registry.js +131 -0
- package/src/utils/start-helper.d.ts +51 -0
- package/src/utils/start-helper.d.ts.map +1 -0
- package/src/utils/start-helper.js +109 -0
- package/src/utils/time.d.ts +31 -0
- package/src/utils/time.d.ts.map +1 -0
- package/src/utils/time.js +63 -0
- package/src/vat-orchestration.d.ts +58 -0
- package/src/vat-orchestration.d.ts.map +1 -0
- package/src/vat-orchestration.js +24 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { makeTracer } from '@agoric/internal';
|
|
2
|
+
import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js';
|
|
3
|
+
import { heapVowE as E } from '@agoric/vow/vat.js';
|
|
4
|
+
import { makeChainHub } from '../exos/chain-hub.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @import {IBCConnectionID} from '@agoric/vats';
|
|
8
|
+
* @import {StakeIcaSF} from '../examples/stakeIca.contract';
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const trace = makeTracer('StartStakeOsmo', true);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {BootstrapPowers & {
|
|
15
|
+
* installation: {
|
|
16
|
+
* consume: {
|
|
17
|
+
* stakeIca: Installation<
|
|
18
|
+
* import('../examples/stakeIca.contract.js').start
|
|
19
|
+
* >;
|
|
20
|
+
* };
|
|
21
|
+
* };
|
|
22
|
+
* }} powers
|
|
23
|
+
*/
|
|
24
|
+
export const startStakeOsmo = async ({
|
|
25
|
+
consume: {
|
|
26
|
+
agoricNames,
|
|
27
|
+
board,
|
|
28
|
+
chainStorage,
|
|
29
|
+
chainTimerService,
|
|
30
|
+
orchestration,
|
|
31
|
+
startUpgradable,
|
|
32
|
+
},
|
|
33
|
+
installation: {
|
|
34
|
+
consume: { stakeIca },
|
|
35
|
+
},
|
|
36
|
+
instance: {
|
|
37
|
+
// @ts-expect-error stakeOsmo not typed
|
|
38
|
+
produce: { stakeOsmo: produceInstance },
|
|
39
|
+
},
|
|
40
|
+
}) => {
|
|
41
|
+
const VSTORAGE_PATH = 'stakeOsmo';
|
|
42
|
+
trace('startStakeOsmo');
|
|
43
|
+
await null;
|
|
44
|
+
|
|
45
|
+
const storageNode = await makeStorageNodeChild(chainStorage, VSTORAGE_PATH);
|
|
46
|
+
const marshaller = await E(board).getPublishingMarshaller();
|
|
47
|
+
|
|
48
|
+
const chainHub = makeChainHub(await agoricNames);
|
|
49
|
+
|
|
50
|
+
const [_, osmosis, connectionInfo] = await E.when(
|
|
51
|
+
chainHub.getChainsAndConnection('agoric', 'osmosis'),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
/** @type {StartUpgradableOpts<StakeIcaSF>} */
|
|
55
|
+
const startOpts = {
|
|
56
|
+
label: 'stakeOsmo',
|
|
57
|
+
installation: stakeIca,
|
|
58
|
+
terms: {
|
|
59
|
+
chainId: osmosis.chainId,
|
|
60
|
+
hostConnectionId: connectionInfo.id,
|
|
61
|
+
controllerConnectionId: connectionInfo.counterparty.connection_id,
|
|
62
|
+
bondDenom: osmosis.stakingTokens[0].denom,
|
|
63
|
+
icqEnabled: osmosis.icqEnabled,
|
|
64
|
+
},
|
|
65
|
+
privateArgs: {
|
|
66
|
+
orchestration: await orchestration,
|
|
67
|
+
storageNode,
|
|
68
|
+
marshaller,
|
|
69
|
+
timer: await chainTimerService,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const { instance } = await E(startUpgradable)(startOpts);
|
|
74
|
+
produceInstance.resolve(instance);
|
|
75
|
+
};
|
|
76
|
+
harden(startStakeOsmo);
|
|
77
|
+
|
|
78
|
+
export const getManifestForStakeOsmo = (
|
|
79
|
+
{ restoreRef },
|
|
80
|
+
{ installKeys, ...options },
|
|
81
|
+
) => {
|
|
82
|
+
return {
|
|
83
|
+
manifest: {
|
|
84
|
+
[startStakeOsmo.name]: {
|
|
85
|
+
consume: {
|
|
86
|
+
agoricNames: true,
|
|
87
|
+
board: true,
|
|
88
|
+
chainStorage: true,
|
|
89
|
+
chainTimerService: true,
|
|
90
|
+
orchestration: true,
|
|
91
|
+
startUpgradable: true,
|
|
92
|
+
},
|
|
93
|
+
installation: {
|
|
94
|
+
consume: { stakeIca: true },
|
|
95
|
+
},
|
|
96
|
+
instance: {
|
|
97
|
+
produce: { stakeOsmo: true },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
installations: {
|
|
102
|
+
stakeIca: restoreRef(installKeys.stakeIca),
|
|
103
|
+
},
|
|
104
|
+
options,
|
|
105
|
+
};
|
|
106
|
+
};
|
package/src/service.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export function prepareOrchestrationTools(zone: Zone, vowTools: VowTools): {
|
|
2
|
+
makeOrchestrationKit: (initialPowers?: Partial<OrchestrationPowers> | undefined) => import("@endo/exo").GuardedKit<{
|
|
3
|
+
requestICAChannelWatcher: {
|
|
4
|
+
/**
|
|
5
|
+
* @param {Port} port
|
|
6
|
+
* @param {{
|
|
7
|
+
* chainId: string;
|
|
8
|
+
* remoteConnAddr: RemoteIbcAddress;
|
|
9
|
+
* }} watchContext
|
|
10
|
+
*/
|
|
11
|
+
onFulfilled(port: Port, { chainId, remoteConnAddr }: {
|
|
12
|
+
chainId: string;
|
|
13
|
+
remoteConnAddr: RemoteIbcAddress;
|
|
14
|
+
}): Vow<any>;
|
|
15
|
+
};
|
|
16
|
+
requestICQChannelWatcher: {
|
|
17
|
+
/**
|
|
18
|
+
* @param {Port} port
|
|
19
|
+
* @param {{
|
|
20
|
+
* remoteConnAddr: RemoteIbcAddress;
|
|
21
|
+
* controllerConnectionId: IBCConnectionID;
|
|
22
|
+
* }} watchContext
|
|
23
|
+
*/
|
|
24
|
+
onFulfilled(port: Port, { remoteConnAddr, controllerConnectionId }: {
|
|
25
|
+
remoteConnAddr: RemoteIbcAddress;
|
|
26
|
+
controllerConnectionId: IBCConnectionID;
|
|
27
|
+
}): Vow<any>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Waits for a channel (ICA, ICQ) to open and returns the consumer-facing
|
|
31
|
+
* facet of the ConnectionKit, specified by `returnFacet`. Saves the
|
|
32
|
+
* ConnectionKit if `saveICQConnection` is provided.
|
|
33
|
+
*/
|
|
34
|
+
channelOpenWatcher: {
|
|
35
|
+
/**
|
|
36
|
+
* @param {Connection} _connection
|
|
37
|
+
* @param {{
|
|
38
|
+
* connectionKit: ConnectionKit;
|
|
39
|
+
* returnFacet: string;
|
|
40
|
+
* saveICQConnection?: IBCConnectionID;
|
|
41
|
+
* }} watchContext
|
|
42
|
+
*/
|
|
43
|
+
onFulfilled(_connection: Connection, { connectionKit, returnFacet, saveICQConnection }: {
|
|
44
|
+
connectionKit: ConnectionKit;
|
|
45
|
+
returnFacet: string;
|
|
46
|
+
saveICQConnection?: IBCConnectionID;
|
|
47
|
+
}): any;
|
|
48
|
+
};
|
|
49
|
+
public: {
|
|
50
|
+
/**
|
|
51
|
+
* @param {string} chainId
|
|
52
|
+
* @param {IBCConnectionID} hostConnectionId the counterparty
|
|
53
|
+
* connection_id
|
|
54
|
+
* @param {IBCConnectionID} controllerConnectionId self connection_id
|
|
55
|
+
* @returns {Vow<IcaAccount>}
|
|
56
|
+
*/
|
|
57
|
+
makeAccount(chainId: string, hostConnectionId: IBCConnectionID, controllerConnectionId: IBCConnectionID): Vow<IcaAccount>;
|
|
58
|
+
/**
|
|
59
|
+
* @param {IBCConnectionID} controllerConnectionId
|
|
60
|
+
* @returns {Vow<ICQConnection> | ICQConnection}
|
|
61
|
+
*/
|
|
62
|
+
provideICQConnection(controllerConnectionId: IBCConnectionID): Vow<ICQConnection> | ICQConnection;
|
|
63
|
+
};
|
|
64
|
+
}>;
|
|
65
|
+
};
|
|
66
|
+
export type OrchestrationPowers = {
|
|
67
|
+
portAllocator: Remote<PortAllocator>;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* PowerStore is used so additional powers can be added on upgrade. See
|
|
71
|
+
* [#7337](https://github.com/Agoric/agoric-sdk/issues/7337) for tracking on Exo
|
|
72
|
+
* state migrations.
|
|
73
|
+
*/
|
|
74
|
+
export type PowerStore = MapStore<keyof OrchestrationPowers, OrchestrationPowers[keyof OrchestrationPowers]>;
|
|
75
|
+
export type ICQConnectionStore = MapStore<IBCConnectionID, ICQConnectionKit>;
|
|
76
|
+
export type ConnectionKit = ChainAccountKit | ICQConnectionKit;
|
|
77
|
+
export type OrchestrationState = {
|
|
78
|
+
powers: PowerStore;
|
|
79
|
+
icqConnections: ICQConnectionStore;
|
|
80
|
+
};
|
|
81
|
+
export type OrchestrationTools = ReturnType<typeof prepareOrchestrationTools>;
|
|
82
|
+
export type OrchestrationKit = ReturnType<OrchestrationTools["makeOrchestrationKit"]>;
|
|
83
|
+
export type OrchestrationService = OrchestrationKit["public"];
|
|
84
|
+
import type { Zone } from '@agoric/base-zone';
|
|
85
|
+
import type { VowTools } from '@agoric/vow';
|
|
86
|
+
import type { Port } from '@agoric/network';
|
|
87
|
+
import type { RemoteIbcAddress } from '@agoric/vats/tools/ibc-utils.js';
|
|
88
|
+
import type { Vow } from '@agoric/vow';
|
|
89
|
+
import type { IBCConnectionID } from '@agoric/vats';
|
|
90
|
+
import type { Connection } from '@agoric/network';
|
|
91
|
+
import type { IcaAccount } from './types.js';
|
|
92
|
+
import type { ICQConnection } from './types.js';
|
|
93
|
+
import type { PortAllocator } from '@agoric/network';
|
|
94
|
+
import type { Remote } from '@agoric/internal';
|
|
95
|
+
import type { ICQConnectionKit } from './types.js';
|
|
96
|
+
import type { ChainAccountKit } from './types.js';
|
|
97
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["service.js"],"names":[],"mappings":"AAkPO,gDAHI,IAAI,YACJ,QAAQ;;;YA3HX;;;;;;eAMG;8BALQ,IAAI,+BACJ;gBACV,OAAW,EAAE,MAAM,CAAC;gBACpB,cAAkB,EAAE,gBAAgB,CAAC;aAClC;;;YAgBJ;;;;;;eAMG;8BALQ,IAAI,8CACJ;gBACV,cAAkB,EAAE,gBAAgB,CAAC;gBACrC,sBAA0B,EAAE,eAAe,CAAC;aACzC;;QAgBN;;;;WAIG;;YAED;;;;;;;eAOG;qCANQ,UAAU,qDACV;gBACV,aAAiB,EAAE,aAAa,CAAC;gBACjC,WAAe,EAAE,MAAM,CAAC;gBACxB,iBAAqB,CAAC,EAAE,eAAe,CAAC;aACrC;;;YAkBJ;;;;;;eAMG;iCALQ,MAAM,oBACN,eAAe,0BAEf,eAAe,GACb,IAAI,UAAU,CAAC;YAiB5B;;;eAGG;yDAFQ,eAAe,GACb,IAAI,aAAa,CAAC,GAAG,aAAa;;;EAwCtD;;mBAnOa,OAAO,aAAa,CAAC;;;;;;;yBAQtB,QAAQ,CACpB,MAAU,mBAAmB,EAC7B,mBAAuB,CAAC,MAAM,mBAAmB,CAAC,CAC/C;iCAGU,QAAQ,CAAC,eAAe,EAAE,gBAAgB,CAAC;4BAE3C,eAAe,GAAG,gBAAgB;iCAYlC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,cAAc,EAAE,kBAAkB,CAAA;CAAE;iCA0M1D,UAAU,CAAC,OAAO,yBAAyB,CAAC;+BAC5C,UAAU,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;mCACtD,gBAAgB,CAAC,QAAQ,CAAC;0BArPjB,mBAAmB;8BAKV,aAAa;0BAHK,iBAAiB;sCAEhC,iCAAiC;yBACpC,aAAa;qCAFX,cAAc;gCADE,iBAAiB;gCAIY,YAAY;mCAAZ,YAAY;mCAJzC,iBAAiB;4BAD1C,kBAAkB;sCAKoC,YAAY;qCAAZ,YAAY"}
|
package/src/service.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/** @file Orchestration service */
|
|
2
|
+
|
|
3
|
+
import { E } from '@endo/far';
|
|
4
|
+
import { M } from '@endo/patterns';
|
|
5
|
+
import { Shape as NetworkShape } from '@agoric/network';
|
|
6
|
+
import { prepareChainAccountKit } from './exos/chain-account-kit.js';
|
|
7
|
+
import { prepareICQConnectionKit } from './exos/icq-connection-kit.js';
|
|
8
|
+
import {
|
|
9
|
+
makeICAChannelAddress,
|
|
10
|
+
makeICQChannelAddress,
|
|
11
|
+
} from './utils/address.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @import {Zone} from '@agoric/base-zone';
|
|
15
|
+
* @import {Remote} from '@agoric/internal';
|
|
16
|
+
* @import {Connection, Port, PortAllocator} from '@agoric/network';
|
|
17
|
+
* @import {IBCConnectionID} from '@agoric/vats';
|
|
18
|
+
* @import {RemoteIbcAddress} from '@agoric/vats/tools/ibc-utils.js';
|
|
19
|
+
* @import {Vow, VowTools} from '@agoric/vow';
|
|
20
|
+
* @import {ICQConnection, IcaAccount, ICQConnectionKit, ChainAccountKit} from './types.js';
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const { Fail, bare } = assert;
|
|
24
|
+
const { Vow$ } = NetworkShape; // TODO #9611
|
|
25
|
+
/**
|
|
26
|
+
* @typedef {object} OrchestrationPowers
|
|
27
|
+
* @property {Remote<PortAllocator>} portAllocator
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* PowerStore is used so additional powers can be added on upgrade. See
|
|
32
|
+
* [#7337](https://github.com/Agoric/agoric-sdk/issues/7337) for tracking on Exo
|
|
33
|
+
* state migrations.
|
|
34
|
+
*
|
|
35
|
+
* @typedef {MapStore<
|
|
36
|
+
* keyof OrchestrationPowers,
|
|
37
|
+
* OrchestrationPowers[keyof OrchestrationPowers]
|
|
38
|
+
* >} PowerStore
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** @typedef {MapStore<IBCConnectionID, ICQConnectionKit>} ICQConnectionStore */
|
|
42
|
+
|
|
43
|
+
/** @typedef {ChainAccountKit | ICQConnectionKit} ConnectionKit */
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @template {keyof OrchestrationPowers} K
|
|
47
|
+
* @param {PowerStore} powers
|
|
48
|
+
* @param {K} name
|
|
49
|
+
*/
|
|
50
|
+
const getPower = (powers, name) => {
|
|
51
|
+
powers.has(name) || Fail`need powers.${bare(name)} for this method`;
|
|
52
|
+
return /** @type {OrchestrationPowers[K]} */ (powers.get(name));
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** @typedef {{ powers: PowerStore; icqConnections: ICQConnectionStore }} OrchestrationState */
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {Zone} zone
|
|
59
|
+
* @param {VowTools} vowTools
|
|
60
|
+
* @param {ReturnType<typeof prepareChainAccountKit>} makeChainAccountKit
|
|
61
|
+
* @param {ReturnType<typeof prepareICQConnectionKit>} makeICQConnectionKit
|
|
62
|
+
*/
|
|
63
|
+
const prepareOrchestrationKit = (
|
|
64
|
+
zone,
|
|
65
|
+
{ watch },
|
|
66
|
+
makeChainAccountKit,
|
|
67
|
+
makeICQConnectionKit,
|
|
68
|
+
) =>
|
|
69
|
+
zone.exoClassKit(
|
|
70
|
+
'Orchestration',
|
|
71
|
+
{
|
|
72
|
+
requestICAChannelWatcher: M.interface('RequestICAChannelWatcher', {
|
|
73
|
+
onFulfilled: M.call(M.remotable('Port'))
|
|
74
|
+
.optional({ chainId: M.string(), remoteConnAddr: M.string() })
|
|
75
|
+
.returns(Vow$(NetworkShape.Connection)),
|
|
76
|
+
}),
|
|
77
|
+
requestICQChannelWatcher: M.interface('RequestICQChannelWatcher', {
|
|
78
|
+
onFulfilled: M.call(M.remotable('Port'))
|
|
79
|
+
.optional({
|
|
80
|
+
remoteConnAddr: M.string(),
|
|
81
|
+
controllerConnectionId: M.string(),
|
|
82
|
+
})
|
|
83
|
+
.returns(Vow$(NetworkShape.Connection)),
|
|
84
|
+
}),
|
|
85
|
+
channelOpenWatcher: M.interface('ChannelOpenWatcher', {
|
|
86
|
+
onFulfilled: M.call(M.remotable('Connection'))
|
|
87
|
+
.optional(
|
|
88
|
+
M.splitRecord(
|
|
89
|
+
{ connectionKit: M.record(), returnFacet: M.string() },
|
|
90
|
+
{ saveICQConnection: M.string() },
|
|
91
|
+
),
|
|
92
|
+
)
|
|
93
|
+
.returns(M.remotable('ConnectionKit Holder facet')),
|
|
94
|
+
}),
|
|
95
|
+
public: M.interface('OrchestrationService', {
|
|
96
|
+
makeAccount: M.call(M.string(), M.string(), M.string()).returns(
|
|
97
|
+
Vow$(M.remotable('ChainAccountKit')),
|
|
98
|
+
),
|
|
99
|
+
provideICQConnection: M.call(M.string()).returns(
|
|
100
|
+
Vow$(M.remotable('ICQConnection')),
|
|
101
|
+
),
|
|
102
|
+
}),
|
|
103
|
+
},
|
|
104
|
+
/** @param {Partial<OrchestrationPowers>} [initialPowers] */
|
|
105
|
+
initialPowers => {
|
|
106
|
+
/** @type {PowerStore} */
|
|
107
|
+
const powers = zone.detached().mapStore('PowerStore');
|
|
108
|
+
if (initialPowers) {
|
|
109
|
+
for (const [name, power] of Object.entries(initialPowers)) {
|
|
110
|
+
powers.init(/** @type {keyof OrchestrationPowers} */ (name), power);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const icqConnections = zone.detached().mapStore('ICQConnections');
|
|
114
|
+
return /** @type {OrchestrationState} */ ({ powers, icqConnections });
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
requestICAChannelWatcher: {
|
|
118
|
+
/**
|
|
119
|
+
* @param {Port} port
|
|
120
|
+
* @param {{
|
|
121
|
+
* chainId: string;
|
|
122
|
+
* remoteConnAddr: RemoteIbcAddress;
|
|
123
|
+
* }} watchContext
|
|
124
|
+
*/
|
|
125
|
+
onFulfilled(port, { chainId, remoteConnAddr }) {
|
|
126
|
+
const chainAccountKit = makeChainAccountKit(
|
|
127
|
+
chainId,
|
|
128
|
+
port,
|
|
129
|
+
remoteConnAddr,
|
|
130
|
+
);
|
|
131
|
+
return watch(
|
|
132
|
+
E(port).connect(remoteConnAddr, chainAccountKit.connectionHandler),
|
|
133
|
+
this.facets.channelOpenWatcher,
|
|
134
|
+
{ returnFacet: 'account', connectionKit: chainAccountKit },
|
|
135
|
+
);
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
requestICQChannelWatcher: {
|
|
139
|
+
/**
|
|
140
|
+
* @param {Port} port
|
|
141
|
+
* @param {{
|
|
142
|
+
* remoteConnAddr: RemoteIbcAddress;
|
|
143
|
+
* controllerConnectionId: IBCConnectionID;
|
|
144
|
+
* }} watchContext
|
|
145
|
+
*/
|
|
146
|
+
onFulfilled(port, { remoteConnAddr, controllerConnectionId }) {
|
|
147
|
+
const connectionKit = makeICQConnectionKit(port);
|
|
148
|
+
/** @param {ICQConnectionKit} kit */
|
|
149
|
+
return watch(
|
|
150
|
+
E(port).connect(remoteConnAddr, connectionKit.connectionHandler),
|
|
151
|
+
this.facets.channelOpenWatcher,
|
|
152
|
+
{
|
|
153
|
+
connectionKit,
|
|
154
|
+
returnFacet: 'connection',
|
|
155
|
+
saveICQConnection: controllerConnectionId,
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Waits for a channel (ICA, ICQ) to open and returns the consumer-facing
|
|
162
|
+
* facet of the ConnectionKit, specified by `returnFacet`. Saves the
|
|
163
|
+
* ConnectionKit if `saveICQConnection` is provided.
|
|
164
|
+
*/
|
|
165
|
+
channelOpenWatcher: {
|
|
166
|
+
/**
|
|
167
|
+
* @param {Connection} _connection
|
|
168
|
+
* @param {{
|
|
169
|
+
* connectionKit: ConnectionKit;
|
|
170
|
+
* returnFacet: string;
|
|
171
|
+
* saveICQConnection?: IBCConnectionID;
|
|
172
|
+
* }} watchContext
|
|
173
|
+
*/
|
|
174
|
+
onFulfilled(
|
|
175
|
+
_connection,
|
|
176
|
+
{ connectionKit, returnFacet, saveICQConnection },
|
|
177
|
+
) {
|
|
178
|
+
if (saveICQConnection) {
|
|
179
|
+
this.state.icqConnections.init(
|
|
180
|
+
saveICQConnection,
|
|
181
|
+
/** @type {ICQConnectionKit} */ (connectionKit),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return connectionKit[returnFacet];
|
|
185
|
+
},
|
|
186
|
+
// TODO #9317 if we fail, should we revoke the port (if it was created in this flow)?
|
|
187
|
+
// onRejected() {}
|
|
188
|
+
},
|
|
189
|
+
public: {
|
|
190
|
+
/**
|
|
191
|
+
* @param {string} chainId
|
|
192
|
+
* @param {IBCConnectionID} hostConnectionId the counterparty
|
|
193
|
+
* connection_id
|
|
194
|
+
* @param {IBCConnectionID} controllerConnectionId self connection_id
|
|
195
|
+
* @returns {Vow<IcaAccount>}
|
|
196
|
+
*/
|
|
197
|
+
makeAccount(chainId, hostConnectionId, controllerConnectionId) {
|
|
198
|
+
const remoteConnAddr = makeICAChannelAddress(
|
|
199
|
+
hostConnectionId,
|
|
200
|
+
controllerConnectionId,
|
|
201
|
+
);
|
|
202
|
+
const portAllocator = getPower(this.state.powers, 'portAllocator');
|
|
203
|
+
return watch(
|
|
204
|
+
E(portAllocator).allocateICAControllerPort(),
|
|
205
|
+
this.facets.requestICAChannelWatcher,
|
|
206
|
+
{
|
|
207
|
+
chainId,
|
|
208
|
+
remoteConnAddr,
|
|
209
|
+
},
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
/**
|
|
213
|
+
* @param {IBCConnectionID} controllerConnectionId
|
|
214
|
+
* @returns {Vow<ICQConnection> | ICQConnection}
|
|
215
|
+
*/
|
|
216
|
+
provideICQConnection(controllerConnectionId) {
|
|
217
|
+
if (this.state.icqConnections.has(controllerConnectionId)) {
|
|
218
|
+
// TODO #9281 do not return synchronously. see https://github.com/Agoric/agoric-sdk/pull/9454#discussion_r1626898694
|
|
219
|
+
return this.state.icqConnections.get(controllerConnectionId)
|
|
220
|
+
.connection;
|
|
221
|
+
}
|
|
222
|
+
const remoteConnAddr = makeICQChannelAddress(controllerConnectionId);
|
|
223
|
+
const portAllocator = getPower(this.state.powers, 'portAllocator');
|
|
224
|
+
return watch(
|
|
225
|
+
// allocate a new Port for every Connection
|
|
226
|
+
// TODO #9317 optimize ICQ port allocation
|
|
227
|
+
E(portAllocator).allocateICQControllerPort(),
|
|
228
|
+
this.facets.requestICQChannelWatcher,
|
|
229
|
+
{
|
|
230
|
+
remoteConnAddr,
|
|
231
|
+
controllerConnectionId,
|
|
232
|
+
},
|
|
233
|
+
);
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @param {Zone} zone
|
|
241
|
+
* @param {VowTools} vowTools
|
|
242
|
+
*/
|
|
243
|
+
export const prepareOrchestrationTools = (zone, vowTools) => {
|
|
244
|
+
const makeChainAccountKit = prepareChainAccountKit(zone, vowTools);
|
|
245
|
+
const makeICQConnectionKit = prepareICQConnectionKit(zone, vowTools);
|
|
246
|
+
const makeOrchestrationKit = prepareOrchestrationKit(
|
|
247
|
+
zone,
|
|
248
|
+
vowTools,
|
|
249
|
+
makeChainAccountKit,
|
|
250
|
+
makeICQConnectionKit,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
return harden({ makeOrchestrationKit });
|
|
254
|
+
};
|
|
255
|
+
harden(prepareOrchestrationTools);
|
|
256
|
+
|
|
257
|
+
/** @typedef {ReturnType<typeof prepareOrchestrationTools>} OrchestrationTools */
|
|
258
|
+
/** @typedef {ReturnType<OrchestrationTools['makeOrchestrationKit']>} OrchestrationKit */
|
|
259
|
+
/** @typedef {OrchestrationKit['public']} OrchestrationService */
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Used for IBC Channel Connections that only send outgoing transactions. If
|
|
3
|
+
* your channel expects incoming transactions, please extend this interface to
|
|
4
|
+
* include the `onReceive` handler.
|
|
5
|
+
*/
|
|
6
|
+
export const OutboundConnectionHandlerI: import("@endo/patterns").InterfaceGuard<{
|
|
7
|
+
onOpen: import("@endo/patterns").MethodGuard;
|
|
8
|
+
onClose: import("@endo/patterns").MethodGuard;
|
|
9
|
+
}>;
|
|
10
|
+
export namespace ChainAddressShape {
|
|
11
|
+
let address: import("@endo/patterns").Matcher;
|
|
12
|
+
let chainId: import("@endo/patterns").Matcher;
|
|
13
|
+
let addressEncoding: import("@endo/patterns").Matcher;
|
|
14
|
+
}
|
|
15
|
+
export namespace Proto3Shape {
|
|
16
|
+
let typeUrl: import("@endo/patterns").Matcher;
|
|
17
|
+
let value: import("@endo/patterns").Matcher;
|
|
18
|
+
}
|
|
19
|
+
export namespace CoinShape {
|
|
20
|
+
let value_1: import("@endo/patterns").Matcher;
|
|
21
|
+
export { value_1 as value };
|
|
22
|
+
export let denom: import("@endo/patterns").Matcher;
|
|
23
|
+
}
|
|
24
|
+
export namespace ChainAmountShape {
|
|
25
|
+
let denom_1: import("@endo/patterns").Matcher;
|
|
26
|
+
export { denom_1 as denom };
|
|
27
|
+
let value_2: import("@endo/patterns").Matcher;
|
|
28
|
+
export { value_2 as value };
|
|
29
|
+
}
|
|
30
|
+
export const AmountArgShape: import("@endo/patterns").Matcher;
|
|
31
|
+
export namespace DelegationShape {
|
|
32
|
+
let validatorAddress: import("@endo/patterns").Matcher;
|
|
33
|
+
let shares: import("@endo/patterns").Matcher;
|
|
34
|
+
}
|
|
35
|
+
export const IBCTransferOptionsShape: import("@endo/patterns").Matcher;
|
|
36
|
+
export const IBCChannelIDShape: import("@endo/patterns").Matcher;
|
|
37
|
+
export const IBCChannelInfoShape: import("@endo/patterns").Matcher;
|
|
38
|
+
export const IBCConnectionIDShape: import("@endo/patterns").Matcher;
|
|
39
|
+
export const IBCConnectionInfoShape: import("@endo/patterns").Matcher;
|
|
40
|
+
export const CosmosChainInfoShape: import("@endo/patterns").Matcher;
|
|
41
|
+
export const ChainInfoShape: import("@endo/patterns").Matcher;
|
|
42
|
+
export const LocalChainAccountShape: import("@endo/patterns").Matcher;
|
|
43
|
+
export const DenomShape: import("@endo/patterns").Matcher;
|
|
44
|
+
export const BrandInfoShape: import("@endo/patterns").Matcher;
|
|
45
|
+
export namespace DenomAmountShape {
|
|
46
|
+
export { DenomShape as denom };
|
|
47
|
+
let value_3: import("@endo/patterns").Matcher;
|
|
48
|
+
export { value_3 as value };
|
|
49
|
+
}
|
|
50
|
+
/** @see {Chain} */
|
|
51
|
+
export const ChainFacadeI: import("@endo/patterns").InterfaceGuard<{
|
|
52
|
+
getChainInfo: import("@endo/patterns").MethodGuard;
|
|
53
|
+
makeAccount: import("@endo/patterns").MethodGuard;
|
|
54
|
+
}>;
|
|
55
|
+
//# sourceMappingURL=typeGuards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typeGuards.d.ts","sourceRoot":"","sources":["typeGuards.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;;;GAQE;;;;;;;;;;;;;;;;;;;;;AAiBF,8DAAkE;;;;;AAOlE,uEAUE;AAEF,iEAA4C;AAC5C,mEAQG;AACH,oEAA+C;AAC/C,sEAYG;AAEH,oEAUE;AAGF,8DAAsC;AACtC,sEAAuE;AACvE,0DAAqC;AAErC,8DAAsC;;;;;;AAItC,mBAAmB;AACnB;;;GAGG"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { AmountShape } from '@agoric/ertp';
|
|
2
|
+
import { VowShape } from '@agoric/vow';
|
|
3
|
+
import { M } from '@endo/patterns';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Used for IBC Channel Connections that only send outgoing transactions. If
|
|
7
|
+
* your channel expects incoming transactions, please extend this interface to
|
|
8
|
+
* include the `onReceive` handler.
|
|
9
|
+
*/
|
|
10
|
+
export const OutboundConnectionHandlerI = M.interface(
|
|
11
|
+
'OutboundConnectionHandler',
|
|
12
|
+
{
|
|
13
|
+
onOpen: M.callWhen(M.any(), M.string(), M.string(), M.any()).returns(
|
|
14
|
+
M.any(),
|
|
15
|
+
),
|
|
16
|
+
onClose: M.callWhen(M.any(), M.any(), M.any()).returns(M.any()),
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export const ChainAddressShape = {
|
|
21
|
+
address: M.string(),
|
|
22
|
+
chainId: M.string(),
|
|
23
|
+
addressEncoding: M.string(),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const Proto3Shape = {
|
|
27
|
+
typeUrl: M.string(),
|
|
28
|
+
value: M.string(),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const CoinShape = { value: M.bigint(), denom: M.string() };
|
|
32
|
+
|
|
33
|
+
export const ChainAmountShape = harden({ denom: M.string(), value: M.nat() });
|
|
34
|
+
|
|
35
|
+
export const AmountArgShape = M.or(AmountShape, ChainAmountShape);
|
|
36
|
+
|
|
37
|
+
export const DelegationShape = harden({
|
|
38
|
+
validatorAddress: M.string(),
|
|
39
|
+
shares: M.string(), // TODO: bigint?
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export const IBCTransferOptionsShape = M.splitRecord(
|
|
43
|
+
{},
|
|
44
|
+
{
|
|
45
|
+
timeoutTimestamp: M.bigint(),
|
|
46
|
+
timeoutHeight: {
|
|
47
|
+
revisionHeight: M.bigint(),
|
|
48
|
+
revisionNumber: M.bigint(),
|
|
49
|
+
},
|
|
50
|
+
memo: M.string(),
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export const IBCChannelIDShape = M.string();
|
|
55
|
+
export const IBCChannelInfoShape = M.splitRecord({
|
|
56
|
+
portId: M.string(),
|
|
57
|
+
channelId: IBCChannelIDShape,
|
|
58
|
+
counterPartyPortId: M.string(),
|
|
59
|
+
counterPartyChannelId: IBCChannelIDShape,
|
|
60
|
+
ordering: M.scalar(), // XXX
|
|
61
|
+
state: M.scalar(), // XXX
|
|
62
|
+
version: M.string(),
|
|
63
|
+
});
|
|
64
|
+
export const IBCConnectionIDShape = M.string();
|
|
65
|
+
export const IBCConnectionInfoShape = M.splitRecord({
|
|
66
|
+
id: IBCConnectionIDShape,
|
|
67
|
+
client_id: M.string(),
|
|
68
|
+
state: M.scalar(), // XXX STATE_OPEN or...
|
|
69
|
+
counterparty: {
|
|
70
|
+
client_id: M.string(),
|
|
71
|
+
connection_id: IBCConnectionIDShape,
|
|
72
|
+
prefix: {
|
|
73
|
+
key_prefix: M.string(),
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
transferChannel: IBCChannelInfoShape,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const CosmosChainInfoShape = M.splitRecord(
|
|
80
|
+
{
|
|
81
|
+
chainId: M.string(),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
connections: M.record(),
|
|
85
|
+
stakingTokens: M.arrayOf({ denom: M.string() }),
|
|
86
|
+
// UNTIL https://github.com/Agoric/agoric-sdk/issues/9326
|
|
87
|
+
icqEnabled: M.boolean(),
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// FIXME more validation
|
|
92
|
+
export const ChainInfoShape = M.any();
|
|
93
|
+
export const LocalChainAccountShape = M.remotable('LocalChainAccount');
|
|
94
|
+
export const DenomShape = M.string();
|
|
95
|
+
// FIXME more validation
|
|
96
|
+
export const BrandInfoShape = M.any();
|
|
97
|
+
|
|
98
|
+
export const DenomAmountShape = { denom: DenomShape, value: M.bigint() };
|
|
99
|
+
|
|
100
|
+
/** @see {Chain} */
|
|
101
|
+
export const ChainFacadeI = M.interface('ChainFacade', {
|
|
102
|
+
getChainInfo: M.call().returns(VowShape),
|
|
103
|
+
makeAccount: M.call().returns(VowShape),
|
|
104
|
+
});
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** @file Rollup of all type definitions in the package, for local import and external export */
|
|
2
|
+
export type * from './chain-info.js';
|
|
3
|
+
export type * from './cosmos-api.js';
|
|
4
|
+
export type * from './ethereum-api.js';
|
|
5
|
+
export type * from './exos/chain-account-kit.js';
|
|
6
|
+
export type * from './exos/icq-connection-kit.js';
|
|
7
|
+
export type * from './internal.js';
|
|
8
|
+
export type * from './orchestration-api.js';
|
|
9
|
+
export type * from './service.js';
|
|
10
|
+
export type * from './vat-orchestration.js';
|
|
11
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAEhG,mBAAmB,iBAAiB,CAAC;AACrC,mBAAmB,iBAAiB,CAAC;AACrC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,6BAA6B,CAAC;AACjD,mBAAmB,8BAA8B,CAAC;AAClD,mBAAmB,eAAe,CAAC;AACnC,mBAAmB,wBAAwB,CAAC;AAC5C,mBAAmB,cAAc,CAAC;AAClC,mBAAmB,wBAAwB,CAAC"}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** @file Rollup of all type definitions in the package, for local import and external export */
|
|
2
|
+
|
|
3
|
+
export type * from './chain-info.js';
|
|
4
|
+
export type * from './cosmos-api.js';
|
|
5
|
+
export type * from './ethereum-api.js';
|
|
6
|
+
export type * from './exos/chain-account-kit.js';
|
|
7
|
+
export type * from './exos/icq-connection-kit.js';
|
|
8
|
+
export type * from './internal.js';
|
|
9
|
+
export type * from './orchestration-api.js';
|
|
10
|
+
export type * from './service.js';
|
|
11
|
+
export type * from './vat-orchestration.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function makeICAChannelAddress(hostConnectionId: IBCConnectionID, controllerConnectionId: IBCConnectionID, { version, encoding, ordering, txType, }?: {
|
|
2
|
+
encoding?: string | undefined;
|
|
3
|
+
ordering?: "ordered" | "unordered" | undefined;
|
|
4
|
+
txType?: string | undefined;
|
|
5
|
+
version?: string | undefined;
|
|
6
|
+
} | undefined): RemoteIbcAddress;
|
|
7
|
+
export function makeICQChannelAddress(controllerConnectionId: IBCConnectionID, { version }?: {
|
|
8
|
+
version?: string;
|
|
9
|
+
} | undefined): RemoteIbcAddress;
|
|
10
|
+
export function findAddressField(remoteAddressString: RemoteIbcAddress): ChainAddress["address"] | undefined;
|
|
11
|
+
import type { IBCConnectionID } from '@agoric/vats';
|
|
12
|
+
import type { RemoteIbcAddress } from '@agoric/vats/tools/ibc-utils.js';
|
|
13
|
+
import type { ChainAddress } from '../types.js';
|
|
14
|
+
//# sourceMappingURL=address.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["address.js"],"names":[],"mappings":"AAoBO,wDAXI,eAAe,0BACf,eAAe;;;;;gBAQb,gBAAgB,CAuB5B;AAQM,8DAJI,eAAe;cACH,MAAM;gBAChB,gBAAgB,CAQ5B;AAaM,sDAJI,gBAAgB,GAEd,YAAY,CAAC,SAAS,CAAC,GAAG,SAAS,CAW/C;qCA1EiC,cAAc;sCAEb,iCAAiC;kCADrC,aAAa"}
|