Skip to content

Commit

Permalink
docs: update unbond walkthrough
Browse files Browse the repository at this point in the history
  • Loading branch information
amessbee committed Oct 1, 2024
1 parent 8cbab6c commit aebbc20
Showing 1 changed file with 78 additions and 121 deletions.
Original file line number Diff line number Diff line change
@@ -1,163 +1,120 @@
# Cross-Chain Unbond Contract

## Overview Diagram
<!-- XXX the diagram below is a useful part of the page but it needs to be updated before it is uncommented. -->
<!-- ## Overview Diagram
<br/>
<img src="/reference/assets/sequence-diagrams/orchestration-unbond-example.svg" width="100%" />
<br/>
<br/> -->

## Imports
This walkthrough outlines the functionality of the Unbond Contract that enables unbonding of assets from a
Cosmos-based chain and transferring them to another chain using IBC (Inter-Blockchain Communication).

```js
import { M } from '@endo/patterns';
import { withOrchestration } from '../utils/start-helper.js';
```
## Overview

- `M`: Imported from @endo/patterns, provides pattern-matching utilities.
- `withOrchestration`: Imported from a utility module, used to set up and provide access to orchestration tools.
The Unbond Contract leverages the Agoric orchestration to interact with external chains, like Osmosis and Stride, to facilitate unbonding and transferring assets from one chain to another.

## JSDoc Annotations for Type Information
The contract consists of two main parts:

```js
/**
* @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js'
* @import {TimerService} from '@agoric/time';
* @import {Baggage} from '@agoric/vat-data';
* @import {LocalChain} from '@agoric/vats/src/localchain.js';
* @import {NameHub} from '@agoric/vats';
* @import {Remote} from '@agoric/internal';
* @import {Zone} from '@agoric/zone';
* @import {CosmosInterchainService} from '../exos/cosmos-interchain-service.js';
* @import {OrchestrationTools} from '../utils/start-helper.js';
*/
```
- **Contract File (`unbond.contract.js`)**: Defines the contract structure, and public-facing APIs.
- **Flows File (`unbond.flows.js`)**: Implements the logic for the unbonding and transfer operations.

This includes type information annotations to help with TypeScript or JSDoc, making it easier to understand the types used throughout the contract.
---

## `unbondAndLiquidStakeFn` Function

```js
/**
* @param {Orchestrator} orch
* @param {object} ctx
* @param {ZCF} ctx.zcf
* @param {ZCFSeat} _seat
* @param {undefined} _offerArgs
*/
const unbondAndLiquidStakeFn = async (orch, { zcf }, _seat, _offerArgs) => {
// ...
```
## Contract: `unbond.contract.js`

### Function Parameters
This file contains the main orchestration contract, which is wrapped using the `withOrchestration` helper for Zoe. It exposes a public facet that allows users to initiate the unbonding process and transfer assets to another chain.

- `orch`: The orchestrator object to manage interactions with chains/accounts.
- `ctx`: Context object containing zcf.
- `_seat`: The seat representing the user’s position in the contract (not used in this function, hence `_` prefix).
- `_offerArgs`: Arguments provided with the offer (not used in this function, hence `_` prefix).
### Imports

## Interacting with Chains
The key imports include the `withOrchestration` helper, pattern matching utility `M`, and the flows from `unbond.flows.js` files.

```js
const omni = await orch.getChain('omniflixhub');
const omniAccount = await omni.makeAccount();
import { M } from '@endo/patterns';
import { withOrchestration } from '../utils/start-helper.js';
import * as flows from './unbond.flows.js';
```

### Get Chain
Retrieves the omniflixhub chain object using the orchestrator.
### Make Account
### `contract` Function

Creates an account on the omniflixhub chain.
The `contract` function when wrapped inside `withOrchestration` defines the [`start` function](#start-function) which is the entry point of the contract. The contract exports a `start` function [below](#start-function). It is merely a convention/convenience that we define a more abstract `contract` function here and pass it to `withOrchestration`. The `contract` function parameters include:

## Interaction with Stride Chain
- `zcf`: Zoe Contract Facet.
- `privateArgs`: Object containing remote references to various services.
- `zone`: A `Zone` object with access to storage for persistent data.
- `OrchestrationTools`: A set of orchestration related tools needed by the contract.

```js
const stride = await orch.getChain('stride');
const strideAccount = await stride.makeAccount();
const contract = async (
zcf,
privateArgs,
zone,
{ orchestrateAll, zcfTools }
) => {
const { unbondAndTransfer } = orchestrateAll(flows, { zcfTools });

const publicFacet = zone.exo('publicFacet', undefined, {
makeUnbondAndTransferInvitation() {
return zcf.makeInvitation(
unbondAndTransfer,
'Unbond and transfer',
undefined,
harden({
give: {},
want: {},
exit: M.any()
})
);
}
});

return harden({ publicFacet });
};
```

### Get Chain
The `orchestrateAll` function links the flows from the flows file to the contract logic. In this case, it links the `unbondAndTransfer` flow. The `publicFacet` exposes the `makeUnbondAndTransferInvitation` method, which creates a Zoe invitation to allow users to make an offer for the unbonding and transferring process.

Retrieves the stride chain object using the orchestrator.
### Make Account
Creates an account on the stride chain.
## `contract` Function
The `contract` function when wrapped inside `withOrchestration` defines the [`start` function](#start-function) which is the entry point of the contract. The contract exports a `start` function [below](#start-function). It is merely a convention/convenience that we define a more abstract `contract` function here and pass it to `withOrchestration`. The arguments of this function are `zcf`, `privateAge`, `zone`, and `tools` for orchestration.
The following code defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup.

```js
/**
* Orchestration contract to be wrapped by withOrchestration for Zoe
*
* @param {ZCF} zcf
* @param {{
* agoricNames: Remote<NameHub>;
* localchain: Remote<LocalChain>;
* orchestrationService: Remote<CosmosInterchainService>;
* storageNode: Remote<StorageNode>;
* marshaller: Marshaller;
* timerService: Remote<TimerService>;
* }} privateArgs
* @param {Zone} zone
* @param {OrchestrationTools} tools
*/
const contract = async (zcf, privateArgs, zone, { orchestrate }) => {
export const start = withOrchestration(contract);
```

### `contract` Function Parameters:
---

- `zcf`: Zoe Contract Facet.
- `privateArgs`: Object containing remote references to various services.
- `zone`: A `Zone` object with access to storage for persistent data.
- `OrchestrationTools`: A set of orchestration related tools needed by the contract.
## Flows: `unbond.flows.js`

## Offer Handler for Unbond and Liquid Stake
This file contains the orchestration flow that performs the unbonding and transferring of assets across chains.

### Flow Function: `unbondAndTransfer`

The `unbondAndTransfer` flow orchestrates the process of unbonding assets from a source chain (e.g., Osmosis) and transferring them to a destination chain (e.g., Stride).

```js
/** @type {OfferHandler} */
const unbondAndLiquidStake = orchestrate(
'LSTTia',
{ zcf },
unbondAndLiquidStakeFn
);
```
export const unbondAndTransfer = async (orch, { zcfTools }) => {
const osmosis = await orch.getChain('osmosis');
const osmoDenom = (await osmosis.getChainInfo()).stakingTokens[0].denom;

### Offer Handler
const osmoAccount = await osmosis.makeAccount();
const delegations = await osmoAccount.getDelegations();
const osmoDelegations = delegations.filter(d => d.amount.denom === osmoDenom);

Defines the offer handler for the unbond and liquid stake operation using [`unbondAndLiquidStakeFn`](#unbondandliquidstakefn-function).
await osmoAccount.undelegate(osmoDelegations);

## Make Invitation and Create `publicFacet`
const stride = await orch.getChain('stride');
const strideAccount = await stride.makeAccount();

```js
const publicFacet = zone.exo('publicFacet', undefined, {
makeUnbondAndLiquidStakeInvitation() {
return zcf.makeInvitation(
unbondAndLiquidStake,
'Unbond and liquid stake',
undefined,
harden({
// Nothing to give; the funds come from undelegating
give: {},
want: {}, // XXX ChainAccount Ownable?
exit: M.any()
})
);
}
});

return harden({ publicFacet });
const balance = await osmoAccount.getBalance(osmoDenom);
await osmoAccount.transfer(strideAccount.getAddress(), balance);
};
```

Defines the `publicFacet` for the contract, which includes the method to make an `invitation`, and returns the hardened public facet. Defining `publicFacet` with `zone.exo` makes it [remotely accessible](/glossary/#exo) and persistent through contract upgrades with a [durable `zone`](/glossary/#zone).
The above code achieve several things including:

## `start` Function
```js
export const start = withOrchestration(contract);
```
- Retrieval of `osmosis` chain object, and `osmo` denom from the chain info.
- Create an `osmoAccount` on `osmosis`. _Note that in real-life scenario, this step would not be needed as we would be using an account that has already delegated some `osmo` assets_.
- Perform `undelegate` on `osmo` delegations of the `osmoAccount`.
- Create an account on `stride` chain.
- Transfer all `osmo` balance from `osmoAccount` to `strideAccount`.

Defines the `start` function of the contract that is returned by a call to `withOrchestration` with [`contract` function](#contract-function) as a parameter. In essence `contract` function is the entry point or `start` function of this contract with some orchestration setup.
Upon successful transfer, the assets are moved from the Osmosis chain to the Stride chain, ready for the user to claim.

0 comments on commit aebbc20

Please sign in to comment.