Instructions for deploying a contract to a local agoric testnet and granting storage node powers. Most of the content here derives from Agoric Office hours, Dec. 14
Why
In order for an Agoric contract to publish data without having the user pay tx fees, the use of a chain storage node is required. Chain storage node is an object that can be passed to a contract by submitting a proposal using cosmos-sdk level txs [swingset.CoreEval]. If passed, the proposal runs a script that gets access to the storage node. The pattern described in the following steps uses this script to start an instance of a contract, passing the storage node as a privateArg to the contract
Let’s split the steps in 4 parts:
agd
to request access using the codeBefore we can use the storage node, we have to create a core-eval
proposal that will request access to the storage node. While instantiating the smart contract in the proposal isn’t the only way to pass the storageNode to a contract, we recommend doing it this way in order to take advantage of the privateArgs
functionality
StorageNode
as a private argument [psm.js]/**
* @type {ContractStartFn}
* @param {ZCF} zcf
* @param {{storageNode: StorageNode, marshaller: Marshaller}} privateArgs
*/
const start = async (zcf, privateArgs) => {
const state = {
privateArgs,
}
[...]
}
{
"consume": {
"board": true,
"chainStorage": true,
"zoe": true
},
"produce": {
"bakeSaleKit": true
},
"instance": {
"produce": {
"bakeSale": true
}
}
}
(note that at this point the bundleID from contractInfo
is not yet known)
/**
* @file
*
* This is a script for use with swingset.CoreEval.
*
* It's a script, not a module, so we can't use `import`.
* But E, Far, etc. are in scope, provided by the
* `new Compartment(globals)` call in
* `bridgeCoreEval()` in packages/vats/src/core/chain-behaviors.js
*/
// @ts-check
// uncomment the following line to typecheck, for example, in vs-code.
// import { E } from '@endo/far';
const contractInfo = {
storagePath: 'bakeSales',
instanceName: 'bakeSaleAgent',
// see discussion of publish-bundle and bundleID
// from Dec 14 office hours
// <https://github.com/Agoric/agoric-sdk/issues/6454#issuecomment-1351949397>
bundleID:
'b1-392ae6656ae68bcfd8bd77a2a100ad4076e8b888808274796cce4c148fcb99d1f8b6c2f946bd6bc3e3c26c54c671c788890f3e9780464354fb2d30916e7be896',
};
const fail = reason => {
throw reason;
};
/**
* Execute a proposal to start a contract that publishes bake sales.
*
* See also:
* BLDer DAO governance using arbitrary code injection: swingset.CoreEval
* <https://community.agoric.com/t/blder-dao-governance-using-arbitrary-code-injection-swingset-coreeval/99>
*
* @param {BootstrapPowers} powers see the `behavior(powers)` call
* in `bridgeCoreEval()`
*/
const executeProposal = async powers => {
// Destructure the powers that we use.
// See also bakeSale-permit.json
const {
consume: { board, chainStorage, zoe },
// @ts-expect-error bakeSaleKit isn't declared in vats/src/core/types.js
produce: { bakeSaleKit },
instance: {
// @ts-expect-error bakeSaleKit isn't declared in vats/src/core/types.js
produce: { [contractInfo.instanceName]: produceInstance },
},
} = powers;
const chainStorageSettled =
(await chainStorage) || fail(Error('no chainStorage - sim chain?'));
const storageNode = E(chainStorageSettled).makeChildNode(
contractInfo.storagePath,
);
const marshaller = await E(board).getReadonlyMarshaller();
const privateArgs = harden({ storageNode, marshaller });
const installation = await E(zoe).installBundleID(contractInfo.bundleID);
const noIssuers = harden({});
const noTerms = harden({});
const facets = await E(zoe).startInstance(
installation,
noIssuers,
noTerms,
privateArgs,
);
// Share instance widely via E(agoricNames).lookup('instance', 'bakeSaleAgent')
produceInstance.resolve(facets.instance);
// Share the publicFacet, creatorFacet, and adminFacet in the bootstrap space
// for use by other CoreEval behaviors.
bakeSaleKit.resolve(facets);
};
harden(executeProposal);
// "export" the function as the script completion value
executeProposal;