Overview of orca.contract.js
Here, we will walkthrough the orchestration basics demo contract.
Table of Contents
The orca.contract.js
file defines the smart contract that orchestrates interactions with various blockchains using the Ochestration API, facilitating the creation and management of accounts on these chains. The primary components of this contract are the createAccountsFn
function and the start
function.
Directory Structure
tree contract -I 'node_modules'
contract
├── Makefile
├── jsconfig.json
├── package.json
├── patch-bn.js
├── rollup.config.mjs
├── scripts
│ ├── deploy-contract.js
│ └── run-chain.sh
├── src
│ ├── @types
│ │ └── zoe-contract-facet.d.ts
│ ├── collectFees.js
│ ├── debug.js
│ ├── facade.js
│ ├── fixHub.js
│ ├── objectTools.js
│ ├── orc.js
│ ├── orca.contract.js
│ ├── orca.proposal.js
│ ├── platform-goals
│ │ ├── README.md
│ │ ├── board-aux.core.js
│ │ ├── endo1.core.js
│ │ ├── start-contract.js
│ │ ├── start-governed-contract.js
│ │ └── types.js
│ ├── tools
│ │ └── debug.js
│ └── types.js
├── test
│ ├── boot-tools.js
│ ├── build-proposal.test.js
│ ├── bundle-source.test.js
│ ├── lib-gov-test
│ │ └── puppet-gov.js
│ ├── market-actors.js
│ ├── mintStable.js
│ ├── orca-contract.test.js
│ ├── prepare-test-env-ava.js
│ ├── snapshots
│ │ ├── test-postalSvc.js.md
│ │ ├── test-postalSvc.js.snap
│ │ ├── test-swap-wallet.js.md
│ │ ├── test-swap-wallet.js.snap
│ │ ├── test-vote-by-committee.js.md
│ │ └── test-vote-by-committee.js.snap
│ ├── test-build-proposal.js
│ ├── test-bundle-source.js
│ ├── test-deploy-tools.js
│ └── wallet-tools.js
├── tools
│ ├── README.md
│ ├── agd-lib.js
│ ├── bundle-tools.js
│ ├── e2e-tools.js
│ ├── rollup-plugin-core-eval.js
│ ├── startOrch.js
│ └── ui-kit-goals
│ ├── README.md
│ ├── batchQuery.js
│ ├── makeHttpClient.js
│ ├── marshalTables.js
│ ├── name-service-client.js
│ ├── queryKit.js
│ └── test-nameProxy.js
└── tsconfig.json
12 directories, 61 files
createAccountsFn
Orhestration Handler function
The createAccountsFn
function is an asynchronous operation designed to create an account on a specified Cosmos chain. This function not only creates the account but also returns a continuing offer that allows the user to perform further actions like Delegation, WithdrawRewards, and Transfers. Let's break down the key components of this function:
Parameters
orch
:- Type:
Orchestrator
- Purpose: The
orch
parameter represents an instance of the Orchestrator, a powerful abstraction that manages interactions with the blockchain. It provides methods to interact with different chains, create accounts, and fetch chain information.
- Type:
_ctx
:- Type:
undefined
- Purpose: This context parameter is not used in this particular function but is often included in functions to pass additional information or tools that might be needed for processing. (unused for now in the first release)
- Type:
seat
:- Type:
ZCFSeat
- Purpose: The
seat
parameter represents the user's position from within the contract. It holds the proposal made by the user, which includes the assets they are willing to give or receive.
- Type:
offerArgs
:- Type:
{ chainName: string }
- Purpose: The
offerArgs
object contains arguments related to the user's offer, specifically thechainName
that identifies which chain the orchestration account should be created on.
- Type:
Workflow
const createAccountsFn = async (orch, _ctx, seat, { chainName }) => {
const { give } = seat.getProposal();
trace('version 0.1.36');
trace('give');
trace(give);
- Extracting Proposal: The function begins by extracting the user's proposal from the
seat
. Thegive
object represents what the user is willing to offer in the transaction. - Tracing Information: Several
trace
calls are made to log the current state of the function. This is useful for debugging and ensuring that the function's inputs and intermediate states are correct.
trace('inside createAccounts');
trace('orch');
trace(orch);
trace('seat');
trace(seat);
trace(chainName);
seat.exit();
When we run the contract, we will see these log results, as a sanity check of our contract having the dependencies it needs to perform the work we want.
Next, we simply exit the seat with seat.exit()
because we are not intending to perform any asset reallocation in this example contract.
try {
const chain = await orch.getChain(chainName);
trace('chain object');
trace(chain);
Fetching Chain Object: The function then retrieves the chain object using orch.getChain(chainName)
. This object contains all the necessary information and methods to interact with the specified chain. We pass the chainName
provided by the offerArgs
.
const info = await chain.getChainInfo();
trace('chain info', info);
Fetching Chain Information: The chain information is fetched using chain.getChainInfo()
. This step is crucial as it provides details about the chain, such as its denomination, address prefixes, and other chain-specific data that might be required for account creation.
const chainAccount = await chain.makeAccount();
console.log("chainAccount")
console.log(chainAccount)
Creating Account: The core operation of this function is to create an account on the specified chain. This is done by calling chain.makeAccount()
. The returned chainAccount
object represents the newly created account and includes methods to interact with the account, such as sending tokens or delegating stake.
return await chainAccount.asContinuingOffer();
} catch (error) {
console.error('Error in createAccounts:', error);
}
Returning Continuing Offer: Once the account is created, the function returns a continuing offer by calling chainAccount.asContinuingOffer()
. This allows the user to perform further actions on the account, such as delegating tokens or withdrawing rewards, through subsequent offers.
Error Handling: We wrap the function in a try...catch
block to handle any errors that might occur during the process. If an error is encountered, it is logged to the console for us to diagnose issues during development and testing.
The start
Function
The start
function is the entry point of the contract, responsible for initializing the contract and setting up the public interface that external users can interact with. Let's break down the function line by line.
Parameters
zcf
: Zoe Contract Facet - Provides essential utilities for contract execution, including making invitations, accessing state, and managing offers. See zcf for more.privateArgs
: A collection of services and utilities that are provided privately to the contract. These include:orchestrationService
: Manages orchestration operations across multiple chains.marshaller
: Handles serialization and deserialization of data.storageNode
: The storage node in vstorade that our contract can write to, and write children to.timer
: Provides access to timing-related functionalities. This is not used yet in this example.localchain
: Manages local chain interactions.agoricNames
: A service that manages name lookups for Agoric chains and connections.
baggage
: Used for persisting contract-related data across reboots/upgrades, ensuring that the contract's state is preserved.
export const start = async (zcf, privateArgs, baggage) => {
trace('inside start function');
trace('privateArgs', privateArgs);
The start
function begins by tracing the function entry and the provided privateArgs
to make sure that all necessary services are available in our logs.
const {
orchestrationService: orchestration,
marshaller,
storageNode,
timer,
localchain,
agoricNames,
} = privateArgs;
Destructuring privateArgs
: The relevant services from privateArgs
are unpacked and assigned to local variables for easier access within the function.
trace('orchestration: ', orchestration);
trace('marshaller: ', marshaller);
trace('storageNode: ', storageNode);
trace('timer: ', timer);
trace('localchain: ', localchain);
trace('agoricNames: ', agoricNames);
Tracing Services: Each service is logged for debugging purposes, ensuring that all services are correctly initialized.
const { orchestrate, zone } = provideOrchestration(
zcf,
baggage,
privateArgs,
privateArgs.marshaller,
);
Orchestration Setup: The provideOrchestration
function is invoked, which sets up the orchestration tooling for us, as a convenience. This function returns two key elements:
orchestrate
: the orchestration offer handler forcreateAccountsFn
.zone
: The zone we use to allocate exposed remotable objects, or Exos.
Creating Offer Handler
/** @type {OfferHandler} */
const makeAccount = orchestrate(
'makeAccount',
undefined,
createAccountsFn,
);
OfferHandler Definition: An OfferHandler
we name makeAccount
is created using the orchestrate
method. This links the handler to the createAccountsFn
function, which is responsible for creating accounts on a chain.
Public Facet
The publicFacet
is the part of the contract that is exposed to external users, allowing them to interact with it. See facet
const publicFacet = zone.exo(
'Orca Public Facet',
M.interface('Orca PF', {
makeAccountInvitation: M.callWhen().returns(InvitationShape),
}),
{
makeAccountInvitation() {
return zcf.makeInvitation(
makeAccount,
'Make an Orchestration Account',
);
},
},
);
Creating Public Facet: The zone.exo
method is used to create an isolated object (exo) that defines the public interface of the contract.
Interface Guard Definition: The public facet exposes a single method, makeAccountInvitation
, which returns an invitation for creating an orchestration account. The invitation is created using zcf.makeInvitation
and is tied to the makeAccount
offer handler.
Here, our interface guard enforces that when makeAccountInvitation
is invoked, it expects no input parameters, and expects to return an InvitationShape
. Otherwise, the interface guard will reject the offer before it reaches the contract.
Return Value
return { publicFacet };
};
Returning Public Facet: The function returns an object containing the publicFacet
. This makes the public interface accessible to users and other contracts, enabling them to interact with the contract's, all while adhering to the object-capabilities model.