|
1 | 1 | # Cross-Chain Unbond Contract
|
2 | 2 |
|
3 |
| -## Overview Diagram |
| 3 | +<!-- XXX the diagram below is a useful part of the page but it needs to be updated before it is uncommented. --> |
| 4 | +<!-- ## Overview Diagram |
4 | 5 |
|
5 | 6 | <br/>
|
6 | 7 | <img src="/reference/assets/sequence-diagrams/orchestration-unbond-example.svg" width="100%" />
|
7 |
| -<br/> |
| 8 | +<br/> --> |
8 | 9 |
|
9 |
| -## Imports |
| 10 | +This walkthrough outlines the functionality of the Unbond Contract that enables unbonding of assets from a |
| 11 | +Cosmos-based chain and transferring them to another chain using IBC (Inter-Blockchain Communication). |
10 | 12 |
|
11 |
| -```js |
12 |
| -import { M } from '@endo/patterns'; |
13 |
| -import { withOrchestration } from '../utils/start-helper.js'; |
14 |
| -``` |
| 13 | +## Overview |
15 | 14 |
|
16 |
| -- `M`: Imported from @endo/patterns, provides pattern-matching utilities. |
17 |
| -- `withOrchestration`: Imported from a utility module, used to set up and provide access to orchestration tools. |
| 15 | +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. |
18 | 16 |
|
19 |
| -## JSDoc Annotations for Type Information |
| 17 | +The contract consists of two main parts: |
20 | 18 |
|
21 |
| -```js |
22 |
| -/** |
23 |
| - * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' |
24 |
| - * @import {TimerService} from '@agoric/time'; |
25 |
| - * @import {Baggage} from '@agoric/vat-data'; |
26 |
| - * @import {LocalChain} from '@agoric/vats/src/localchain.js'; |
27 |
| - * @import {NameHub} from '@agoric/vats'; |
28 |
| - * @import {Remote} from '@agoric/internal'; |
29 |
| - * @import {Zone} from '@agoric/zone'; |
30 |
| - * @import {CosmosInterchainService} from '../exos/cosmos-interchain-service.js'; |
31 |
| - * @import {OrchestrationTools} from '../utils/start-helper.js'; |
32 |
| - */ |
33 |
| -``` |
| 19 | +- **Contract File (`unbond.contract.js`)**: Defines the contract structure, and public-facing APIs. |
| 20 | +- **Flows File (`unbond.flows.js`)**: Implements the logic for the unbonding and transfer operations. |
34 | 21 |
|
35 |
| -This includes type information annotations to help with TypeScript or JSDoc, making it easier to understand the types used throughout the contract. |
| 22 | +--- |
36 | 23 |
|
37 |
| -## `unbondAndLiquidStakeFn` Function |
38 |
| - |
39 |
| -```js |
40 |
| -/** |
41 |
| - * @param {Orchestrator} orch |
42 |
| - * @param {object} ctx |
43 |
| - * @param {ZCF} ctx.zcf |
44 |
| - * @param {ZCFSeat} _seat |
45 |
| - * @param {undefined} _offerArgs |
46 |
| - */ |
47 |
| -const unbondAndLiquidStakeFn = async (orch, { zcf }, _seat, _offerArgs) => { |
48 |
| -// ... |
49 |
| -``` |
| 24 | +## Contract: `unbond.contract.js` |
50 | 25 |
|
51 |
| -### Function Parameters |
| 26 | +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. |
52 | 27 |
|
53 |
| -- `orch`: The orchestrator object to manage interactions with chains/accounts. |
54 |
| -- `ctx`: Context object containing zcf. |
55 |
| -- `_seat`: The seat representing the user’s position in the contract (not used in this function, hence `_` prefix). |
56 |
| -- `_offerArgs`: Arguments provided with the offer (not used in this function, hence `_` prefix). |
| 28 | +### Imports |
57 | 29 |
|
58 |
| -## Interacting with Chains |
| 30 | +The key imports include the `withOrchestration` helper, pattern matching utility `M`, and the flows from `unbond.flows.js` files. |
59 | 31 |
|
60 | 32 | ```js
|
61 |
| -const omni = await orch.getChain('omniflixhub'); |
62 |
| -const omniAccount = await omni.makeAccount(); |
| 33 | +import { M } from '@endo/patterns'; |
| 34 | +import { withOrchestration } from '../utils/start-helper.js'; |
| 35 | +import * as flows from './unbond.flows.js'; |
63 | 36 | ```
|
64 | 37 |
|
65 |
| -### Get Chain |
66 |
| -
|
67 |
| -Retrieves the omniflixhub chain object using the orchestrator. |
68 |
| -
|
69 |
| -### Make Account |
| 38 | +### `contract` Function |
70 | 39 |
|
71 |
| -Creates an account on the omniflixhub chain. |
| 40 | +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: |
72 | 41 |
|
73 |
| -## Interaction with Stride Chain |
| 42 | +- `zcf`: Zoe Contract Facet. |
| 43 | +- `privateArgs`: Object containing remote references to various services. |
| 44 | +- `zone`: A `Zone` object with access to storage for persistent data. |
| 45 | +- `OrchestrationTools`: A set of orchestration related tools needed by the contract. |
74 | 46 |
|
75 | 47 | ```js
|
76 |
| -const stride = await orch.getChain('stride'); |
77 |
| -const strideAccount = await stride.makeAccount(); |
| 48 | +const contract = async ( |
| 49 | + zcf, |
| 50 | + privateArgs, |
| 51 | + zone, |
| 52 | + { orchestrateAll, zcfTools } |
| 53 | +) => { |
| 54 | + const { unbondAndTransfer } = orchestrateAll(flows, { zcfTools }); |
| 55 | + |
| 56 | + const publicFacet = zone.exo('publicFacet', undefined, { |
| 57 | + makeUnbondAndTransferInvitation() { |
| 58 | + return zcf.makeInvitation( |
| 59 | + unbondAndTransfer, |
| 60 | + 'Unbond and transfer', |
| 61 | + undefined, |
| 62 | + harden({ |
| 63 | + give: {}, |
| 64 | + want: {}, |
| 65 | + exit: M.any() |
| 66 | + }) |
| 67 | + ); |
| 68 | + } |
| 69 | + }); |
| 70 | + |
| 71 | + return harden({ publicFacet }); |
| 72 | +}; |
78 | 73 | ```
|
79 | 74 |
|
80 |
| -### Get Chain |
| 75 | +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. |
81 | 76 |
|
82 |
| -Retrieves the stride chain object using the orchestrator. |
83 |
| -
|
84 |
| -### Make Account |
85 |
| -
|
86 |
| -Creates an account on the stride chain. |
87 |
| -
|
88 |
| -## `contract` Function |
89 |
| -
|
90 |
| -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. |
| 77 | +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. |
91 | 78 |
|
92 | 79 | ```js
|
93 |
| -/** |
94 |
| - * Orchestration contract to be wrapped by withOrchestration for Zoe |
95 |
| - * |
96 |
| - * @param {ZCF} zcf |
97 |
| - * @param {{ |
98 |
| - * agoricNames: Remote<NameHub>; |
99 |
| - * localchain: Remote<LocalChain>; |
100 |
| - * orchestrationService: Remote<CosmosInterchainService>; |
101 |
| - * storageNode: Remote<StorageNode>; |
102 |
| - * marshaller: Marshaller; |
103 |
| - * timerService: Remote<TimerService>; |
104 |
| - * }} privateArgs |
105 |
| - * @param {Zone} zone |
106 |
| - * @param {OrchestrationTools} tools |
107 |
| - */ |
108 |
| -const contract = async (zcf, privateArgs, zone, { orchestrate }) => { |
| 80 | +export const start = withOrchestration(contract); |
109 | 81 | ```
|
110 | 82 |
|
111 |
| -### `contract` Function Parameters: |
| 83 | +--- |
112 | 84 |
|
113 |
| -- `zcf`: Zoe Contract Facet. |
114 |
| -- `privateArgs`: Object containing remote references to various services. |
115 |
| -- `zone`: A `Zone` object with access to storage for persistent data. |
116 |
| -- `OrchestrationTools`: A set of orchestration related tools needed by the contract. |
| 85 | +## Flows: `unbond.flows.js` |
117 | 86 |
|
118 |
| -## Offer Handler for Unbond and Liquid Stake |
| 87 | +This file contains the orchestration flow that performs the unbonding and transferring of assets across chains. |
| 88 | + |
| 89 | +### Flow Function: `unbondAndTransfer` |
| 90 | + |
| 91 | +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). |
119 | 92 |
|
120 | 93 | ```js
|
121 |
| -/** @type {OfferHandler} */ |
122 |
| -const unbondAndLiquidStake = orchestrate( |
123 |
| - 'LSTTia', |
124 |
| - { zcf }, |
125 |
| - unbondAndLiquidStakeFn |
126 |
| -); |
127 |
| -``` |
| 94 | +export const unbondAndTransfer = async (orch, { zcfTools }) => { |
| 95 | + const osmosis = await orch.getChain('osmosis'); |
| 96 | + const osmoDenom = (await osmosis.getChainInfo()).stakingTokens[0].denom; |
128 | 97 |
|
129 |
| -### Offer Handler |
| 98 | + const osmoAccount = await osmosis.makeAccount(); |
| 99 | + const delegations = await osmoAccount.getDelegations(); |
| 100 | + const osmoDelegations = delegations.filter(d => d.amount.denom === osmoDenom); |
130 | 101 |
|
131 |
| -Defines the offer handler for the unbond and liquid stake operation using [`unbondAndLiquidStakeFn`](#unbondandliquidstakefn-function). |
| 102 | + await osmoAccount.undelegate(osmoDelegations); |
132 | 103 |
|
133 |
| -## Make Invitation and Create `publicFacet` |
| 104 | + const stride = await orch.getChain('stride'); |
| 105 | + const strideAccount = await stride.makeAccount(); |
134 | 106 |
|
135 |
| -```js |
136 |
| -const publicFacet = zone.exo('publicFacet', undefined, { |
137 |
| - makeUnbondAndLiquidStakeInvitation() { |
138 |
| - return zcf.makeInvitation( |
139 |
| - unbondAndLiquidStake, |
140 |
| - 'Unbond and liquid stake', |
141 |
| - undefined, |
142 |
| - harden({ |
143 |
| - // Nothing to give; the funds come from undelegating |
144 |
| - give: {}, |
145 |
| - want: {}, // XXX ChainAccount Ownable? |
146 |
| - exit: M.any() |
147 |
| - }) |
148 |
| - ); |
149 |
| - } |
150 |
| -}); |
151 |
| - |
152 |
| -return harden({ publicFacet }); |
| 107 | + const balance = await osmoAccount.getBalance(osmoDenom); |
| 108 | + await osmoAccount.transfer(strideAccount.getAddress(), balance); |
| 109 | +}; |
153 | 110 | ```
|
154 | 111 |
|
155 |
| -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). |
| 112 | +The above code achieve several things including: |
156 | 113 |
|
157 |
| -## `start` Function |
158 |
| -
|
159 |
| -```js |
160 |
| -export const start = withOrchestration(contract); |
161 |
| -``` |
| 114 | +- Retrieval of `osmosis` chain object, and `osmo` denom from the chain info. |
| 115 | +- 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_. |
| 116 | +- Perform `undelegate` on `osmo` delegations of the `osmoAccount`. |
| 117 | +- Create an account on `stride` chain. |
| 118 | +- Transfer all `osmo` balance from `osmoAccount` to `strideAccount`. |
162 | 119 |
|
163 |
| -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. |
| 120 | +Upon successful transfer, the assets are moved from the Osmosis chain to the Stride chain, ready for the user to claim. |
0 commit comments