-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Orch/Unbond Walkthrough #1221
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,163 +1,118 @@ | ||
# 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/> | ||
|
||
## Imports | ||
|
||
```js | ||
import { M } from '@endo/patterns'; | ||
import { withOrchestration } from '../utils/start-helper.js'; | ||
``` | ||
<br/> --> | ||
|
||
- `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. | ||
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). | ||
|
||
## JSDoc Annotations for Type Information | ||
## Overview | ||
|
||
```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'; | ||
*/ | ||
``` | ||
The Unbond Contract leverages the Agoric Orchestration API to interact with external chains, like Osmosis and Stride, to facilitate unbonding and transferring assets from one chain to another. | ||
|
||
This includes type information annotations to help with TypeScript or JSDoc, making it easier to understand the types used throughout the contract. | ||
The contract consists of two main parts: | ||
|
||
## `unbondAndLiquidStakeFn` Function | ||
- **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. | ||
|
||
```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. | ||
### `contract` Function | ||
|
||
### Make Account | ||
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: | ||
|
||
Creates an account on the omniflixhub chain. | ||
|
||
## 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() | ||
}) | ||
Comment on lines
+60
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add a line or two about why this contract doesn't have or expect any give/want terms? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't feel the need for it - this would raise more questions that rather not be answer here. |
||
); | ||
} | ||
}); | ||
|
||
return harden({ publicFacet }); | ||
}; | ||
``` | ||
|
||
### Get Chain | ||
|
||
Retrieves the stride chain object using the orchestrator. | ||
|
||
### Make Account | ||
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. | ||
|
||
Creates an account on the stride chain. | ||
### `start` function | ||
|
||
## `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: | ||
## Flows: `unbond.flows.js` | ||
|
||
- `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. | ||
This file contains the Orchestration flow that performs the unbonding and transferring of assets across chains. | ||
|
||
### Flow Function: `unbondAndTransfer` | ||
|
||
## Offer Handler for Unbond and Liquid Stake | ||
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There needs to be a separate h3 for the start function below for the link to work. It doesn't, right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Will add back.