Skip to content

Commit 3312def

Browse files
committed
docs: publishing to vstorage
1 parent b3bcf7f commit 3312def

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed

main/guides/zoe/pub-to-storage.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Publishing to chainStorage
2+
3+
Contracts can use [notifiers and subscriptions](../js-programming/notifiers)
4+
to publish to clients. To publish data visible to [vstorage queries](../getting-started/contract-rpc#querying-vstorage), contracts should connect
5+
a subscriber to a `chainStorage` node.
6+
7+
Let's look at the Inter Protocol [assetReserve.js](https://github.com/Agoric/agoric-sdk/blob/agoric-upgrade-13/packages/inter-protocol/src/reserve/assetReserve.js) contract. It publishes to [published.reserve.metrics](https://github.com/Agoric/agoric-sdk/blob/agoric-upgrade-13/packages/inter-protocol/test/reserve/snapshots/test-reserve.js.md) data of the form
8+
9+
```js
10+
/**
11+
* @typedef {object} MetricsNotification
12+
* @property {AmountKeywordRecord} allocations
13+
* @property {Amount<'nat'>} shortfallBalance shortfall from liquidation that
14+
* has not yet been compensated.
15+
* @property {Amount<'nat'>} totalFeeMinted total Fee tokens minted to date
16+
* @property {Amount<'nat'>} totalFeeBurned total Fee tokens burned to date
17+
*/
18+
```
19+
20+
For example:
21+
22+
```js
23+
{
24+
allocations: {
25+
Fee: {
26+
brand: Object @Alleged: IST brand {},
27+
value: 64561373455n,
28+
},
29+
ATOM: {
30+
brand: Object @Alleged: ATOM brand {},
31+
value: 6587020n
32+
},
33+
},
34+
shortfallBalance: {
35+
brand: Object @Alleged: IST brand {},
36+
value: 5747205025n,
37+
},
38+
totalFeeBurned: {
39+
brand: Object @Alleged: IST brand {},
40+
value: n,
41+
},
42+
totalFeeMinted: {
43+
brand: Object @Alleged: IST brand {},
44+
value: 0n,
45+
},
46+
},
47+
```
48+
49+
The method that writes this data is:
50+
51+
```js
52+
writeMetrics() {
53+
const { state } = this;
54+
const metrics = harden({
55+
allocations: state.collateralSeat.getCurrentAllocation(),
56+
shortfallBalance: state.shortfallBalance,
57+
totalFeeMinted: state.totalFeeMinted,
58+
totalFeeBurned: state.totalFeeBurned,
59+
});
60+
void state.metricsKit.recorder.write(metrics);
61+
},
62+
```
63+
64+
The `metricsKit` is made with a `makeRecorderKit` function:
65+
66+
```js
67+
metricsKit: makeRecorderKit(
68+
metricsNode,
69+
/** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<MetricsNotification>} */ (
70+
M.any()
71+
),
72+
),
73+
```
74+
75+
We "prepare" (in the [exo](https://endojs.github.io/endo/modules/_endo_exo.html) sense) that function for making
76+
a `RecorderKit` using [prepareRecorderKitMakers](/reference/zoe-api/zoe-helpers#preparerecorderkitmakers-baggage-marshaller).
77+
78+
```js
79+
const { makeRecorderKit } = prepareRecorderKitMakers(
80+
baggage,
81+
privateArgs.marshaller,
82+
);
83+
```
84+
85+
The contract gets `baggage`, along with `privateArgs` when it starts in
86+
[the usual way for upgradable contracts](./contract-upgrade.html#upgradable-declaration):
87+
88+
```js
89+
/**
90+
* Asset Reserve holds onto assets for the Inter Protocol, and ...
91+
*
92+
* @param {{
93+
* ...
94+
* marshaller: ERef<Marshaller>,
95+
* storageNode: ERef<StorageNode>,
96+
* }} privateArgs
97+
* @param {Baggage} baggage
98+
*/
99+
export const prepare = async (zcf, privateArgs, baggage) => {
100+
...
101+
};
102+
```
103+
104+
The reserve takes its `StorageNode` makes a child to get `metricsNode`:
105+
106+
```js
107+
const metricsNode = await E(storageNode).makeChildNode('metrics');
108+
```
109+
110+
The `marshaller` is used to serialize data structures such as `MetricsNotification` above.
111+
112+
## Deployment Capabilities for Publishing to chainStorage
113+
114+
To start a contract such as `assetReserve` above, the [setupReserve](https://github.com/Agoric/agoric-sdk/blob/agoric-upgrade-13/packages/inter-protocol/src/proposals/econ-behaviors.js#L76) function needs to supply
115+
the two `privateArgs`: `marshaller` and `storageNode`:
116+
117+
```js
118+
const STORAGE_PATH = 'reserve';
119+
const storageNode = await E(storageNode).makeChildNode(STORAGE_PATH);
120+
const marshaller = await E(board).getReadonlyMarshaller();
121+
```
122+
123+
As usual for a [permissioned deployment script function](../coreeval/proposal), `setupReserve` function is passed `BootstrapPowers`
124+
including `chainStorage` and `board`:
125+
126+
```js
127+
export const setupReserve = async ({
128+
consume: {
129+
board,
130+
chainStorage,
131+
...
132+
},
133+
...
134+
}) => { ... };
135+
```
136+
137+
A `Marshaller` is parameterized by functions for mapping unforgeable object identities to plain data slot references and back. Using the [board](../integration/name-services#the-board-publishing-under-arbitrary-names) name service gives consistent slot references across contracts.
138+
As discussed in [Marshalling Amounts and Instances](../getting-started/contract-rpc#marshalling-amounts-and-instances), this lets
139+
off-chain clients use the same `@endo/marshal` API.

0 commit comments

Comments
 (0)