Skip to content

Commit f5e14f3

Browse files
committed
docs: publishing to vstorage
1 parent 2e1afad commit f5e14f3

File tree

2 files changed

+160
-1
lines changed

2 files changed

+160
-1
lines changed

main/guides/governance/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Adding parameter governance to a contract consists mainly of using `handleParamG
4646
We pass it `zcf` so that it can `getTerms()` for initial parameter values, and we
4747
pass `paramTypes` to specify governed parameters and their types. `initialPoserInvitation`
4848
is necessary to set up replacing the electorate. `storageNode` and `marshaller` are used
49-
to publish values of the parameters to vstorage.
49+
to [publish values of the parameters to vstorage](../zoe/pub-to-storage).
5050

5151
```js
5252
import { handleParamGovernance } from '@agoric/governance/src/contractHelper.js';

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

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
## Deployment Capabilities for Publishing to chainStorage
8+
9+
In [Adding Parameter Governance to a Contract](../governance/#adding-parameter-governance-to-a-contract),
10+
`storageNode` and `marshaller` are passed to the contract in its `privateArgs` so it can publish to chainStorage.
11+
12+
In [dapp-agoric-basics](https://github.com/Agoric/dapp-agoric-basics), the `startSwapContract` uses 2 [permitted deployment capabilities](../coreeval/permissions), `chainStorage` and `board` and uses them to make the `privateArgs`:
13+
14+
```js
15+
const marshaller = await E(board).getPublishingMarshaller();
16+
const storageNode = await E(chainStorage).makeChildNode(contractName);
17+
```
18+
19+
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.
20+
As discussed in [Marshalling Amounts and Instances](../getting-started/contract-rpc#marshalling-amounts-and-instances), this lets
21+
off-chain clients use the same `@endo/marshal` API.
22+
23+
The `chainStorage` node corresponds to the `published` key in the
24+
[vstorage hierarchy](/reference/vstorage-ref).
25+
Using `E(chainStorage).makeChildNode(contractName)` gives the contract
26+
access to write to the `published.swaparoo` key and all keys under it.
27+
28+
The `swaparoo` contract delegates the rest of publishing governance parameters to the `@agoric/governance` package.
29+
30+
## Publishing structured data to chainStorage
31+
32+
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 to get more of the details. 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
33+
34+
```js
35+
/**
36+
* @typedef {object} MetricsNotification
37+
* @property {AmountKeywordRecord} allocations
38+
* @property {Amount<'nat'>} shortfallBalance shortfall from liquidation that
39+
* has not yet been compensated.
40+
* @property {Amount<'nat'>} totalFeeMinted total Fee tokens minted to date
41+
* @property {Amount<'nat'>} totalFeeBurned total Fee tokens burned to date
42+
*/
43+
```
44+
45+
For example:
46+
47+
```js
48+
{
49+
allocations: {
50+
Fee: {
51+
brand: Object @Alleged: IST brand {},
52+
value: 64561373455n,
53+
},
54+
ATOM: {
55+
brand: Object @Alleged: ATOM brand {},
56+
value: 6587020n
57+
},
58+
},
59+
shortfallBalance: {
60+
brand: Object @Alleged: IST brand {},
61+
value: 5747205025n,
62+
},
63+
totalFeeBurned: {
64+
brand: Object @Alleged: IST brand {},
65+
value: n,
66+
},
67+
totalFeeMinted: {
68+
brand: Object @Alleged: IST brand {},
69+
value: 0n,
70+
},
71+
},
72+
```
73+
74+
The method that writes this data is:
75+
76+
```js
77+
writeMetrics() {
78+
const { state } = this;
79+
const metrics = harden({
80+
allocations: state.collateralSeat.getCurrentAllocation(),
81+
shortfallBalance: state.shortfallBalance,
82+
totalFeeMinted: state.totalFeeMinted,
83+
totalFeeBurned: state.totalFeeBurned,
84+
});
85+
void state.metricsKit.recorder.write(metrics);
86+
},
87+
```
88+
89+
The `metricsKit` is made with a `makeRecorderKit` function:
90+
91+
```js
92+
metricsKit: makeRecorderKit(
93+
metricsNode,
94+
/** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<MetricsNotification>} */ (
95+
M.any()
96+
),
97+
),
98+
```
99+
100+
We "prepare" (in the [exo](https://endojs.github.io/endo/modules/_endo_exo.html) sense) that function for making
101+
a `RecorderKit` using [prepareRecorderKitMakers](/reference/zoe-api/zoe-helpers#preparerecorderkitmakers-baggage-marshaller).
102+
103+
```js
104+
const { makeRecorderKit } = prepareRecorderKitMakers(
105+
baggage,
106+
privateArgs.marshaller,
107+
);
108+
```
109+
110+
The contract gets `baggage`, along with `privateArgs` when it starts in
111+
[the usual way for upgradable contracts](./contract-upgrade.html#upgradable-declaration):
112+
113+
```js
114+
/**
115+
* Asset Reserve holds onto assets for the Inter Protocol, and ...
116+
*
117+
* @param {{
118+
* ...
119+
* marshaller: ERef<Marshaller>,
120+
* storageNode: ERef<StorageNode>,
121+
* }} privateArgs
122+
* @param {Baggage} baggage
123+
*/
124+
export const prepare = async (zcf, privateArgs, baggage) => {
125+
...
126+
};
127+
```
128+
129+
The reserve uses its `StorageNode` and makes a child to get `metricsNode`:
130+
131+
```js
132+
const metricsNode = await E(storageNode).makeChildNode('metrics');
133+
```
134+
135+
The `marshaller` is used to serialize data structures such as `MetricsNotification` above.
136+
137+
### Deployment Capabilities for the reserve
138+
139+
To start `assetReserve`, the [setupReserve](https://github.com/Agoric/agoric-sdk/blob/agoric-upgrade-13/packages/inter-protocol/src/proposals/econ-behaviors.js#L76) function again supplies
140+
the two relevant `privateArgs`, `marshaller` and `storageNode`:
141+
142+
```js
143+
const STORAGE_PATH = 'reserve';
144+
const storageNode = await E(storageNode).makeChildNode(STORAGE_PATH);
145+
const marshaller = await E(board).getReadonlyMarshaller();
146+
```
147+
148+
The `setupReserve` function gets `chainStorage` and `board` deployment capabilities passed in:
149+
150+
```js
151+
export const setupReserve = async ({
152+
consume: {
153+
board,
154+
chainStorage,
155+
...
156+
},
157+
...
158+
}) => { ... };
159+
```

0 commit comments

Comments
 (0)