@agoric/orchestration 0.1.1-dev-df81dca.0 → 0.1.1-dev-be74a2b.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/examples/swap-anything.contract.d.ts +48 -0
- package/src/examples/swap-anything.contract.d.ts.map +1 -0
- package/src/examples/swap-anything.contract.js +187 -0
- package/src/examples/swap-anything.flows.d.ts +32 -0
- package/src/examples/swap-anything.flows.d.ts.map +1 -0
- package/src/examples/swap-anything.flows.js +222 -0
- package/src/exos/ibc-packet.d.ts.map +1 -1
- package/src/exos/ibc-packet.js +19 -2
- package/src/proposals/start-swap-anything.js +133 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/orchestration",
|
|
3
|
-
"version": "0.1.1-dev-
|
|
3
|
+
"version": "0.1.1-dev-be74a2b.0+be74a2b",
|
|
4
4
|
"description": "Chain abstraction for Agoric's orchestration clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"typeCoverage": {
|
|
101
101
|
"atLeast": 97.7
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "be74a2bc3be6c03203f4fe76e9e287f49271ef76"
|
|
104
104
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {Remote, Vow} from '@agoric/vow';
|
|
3
|
+
* @import {Zone} from '@agoric/zone';
|
|
4
|
+
* @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js';
|
|
5
|
+
* @import {CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration';
|
|
6
|
+
*/
|
|
7
|
+
export const SingleNatAmountRecord: import("@endo/patterns").Matcher;
|
|
8
|
+
export function contract(zcf: ZCF, privateArgs: OrchestrationPowers & {
|
|
9
|
+
assetInfo?: [Denom, DenomDetail & {
|
|
10
|
+
brandKey?: string;
|
|
11
|
+
}][];
|
|
12
|
+
chainInfo?: Record<string, CosmosChainInfo>;
|
|
13
|
+
marshaller: Marshaller;
|
|
14
|
+
storageNode: Remote<StorageNode>;
|
|
15
|
+
}, zone: Zone, { chainHub, orchestrate, vowTools, zoeTools }: OrchestrationTools): Promise<{
|
|
16
|
+
publicFacet: import("@endo/exo").Guarded<{
|
|
17
|
+
makeSwapInvitation(): Promise<globalThis.Invitation<Vow<string>, import("./swap-anything.flows.js").SwapInfo>>;
|
|
18
|
+
}>;
|
|
19
|
+
creatorFacet: import("@endo/exo").Guarded<{
|
|
20
|
+
registerChain(chainName: string, chainInfo: import("@agoric/orchestration").ChainInfo, ibcConnectionInfo?: import("@agoric/orchestration").IBCConnectionInfo): Promise<void>;
|
|
21
|
+
registerAsset(denom: Denom, detail: DenomDetail): Promise<void>;
|
|
22
|
+
}>;
|
|
23
|
+
}>;
|
|
24
|
+
export const start: (zcf: globalThis.ZCF<Record<string, unknown>>, privateArgs: OrchestrationPowers & {
|
|
25
|
+
assetInfo?: [Denom, DenomDetail & {
|
|
26
|
+
brandKey?: string;
|
|
27
|
+
}][];
|
|
28
|
+
chainInfo?: Record<string, CosmosChainInfo>;
|
|
29
|
+
marshaller: Marshaller;
|
|
30
|
+
storageNode: Remote<StorageNode>;
|
|
31
|
+
}, baggage: Baggage) => Promise<{
|
|
32
|
+
publicFacet: import("@endo/exo").Guarded<{
|
|
33
|
+
makeSwapInvitation(): Promise<globalThis.Invitation<Vow<string>, import("./swap-anything.flows.js").SwapInfo>>;
|
|
34
|
+
}>;
|
|
35
|
+
creatorFacet: import("@endo/exo").Guarded<{
|
|
36
|
+
registerChain(chainName: string, chainInfo: import("@agoric/orchestration").ChainInfo, ibcConnectionInfo?: import("@agoric/orchestration").IBCConnectionInfo): Promise<void>;
|
|
37
|
+
registerAsset(denom: Denom, detail: DenomDetail): Promise<void>;
|
|
38
|
+
}>;
|
|
39
|
+
}>;
|
|
40
|
+
import type { OrchestrationPowers } from '../utils/start-helper.js';
|
|
41
|
+
import type { Denom } from '@agoric/orchestration';
|
|
42
|
+
import type { DenomDetail } from '@agoric/orchestration';
|
|
43
|
+
import type { CosmosChainInfo } from '@agoric/orchestration';
|
|
44
|
+
import type { Remote } from '@agoric/vow';
|
|
45
|
+
import type { Zone } from '@agoric/zone';
|
|
46
|
+
import type { OrchestrationTools } from '../utils/start-helper.js';
|
|
47
|
+
import type { Vow } from '@agoric/vow';
|
|
48
|
+
//# sourceMappingURL=swap-anything.contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swap-anything.contract.d.ts","sourceRoot":"","sources":["swap-anything.contract.js"],"names":[],"mappings":"AAcA;;;;;GAKG;AAEH,qEAGE;AAmBK,8BAVI,GAAG,eACH,mBAAmB,GAAG;IAC5B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5C,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,OAAO,WAAW,CAAC,CAAC;CAClC,QACO,IAAI,iDACJ,kBAAkB;;;;;;;;GA6I5B;AAGD;gBAtJiB,CAAC,KAAK,EAAE,WAAW,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE;gBAC9C,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC;gBAC/B,UAAU;iBACT,OAAO,WAAW,CAAC;;;;;;;;;GAmJ0C;yCAxKrB,0BAA0B;2BACR,uBAAuB;iCAAvB,uBAAuB;qCAAvB,uBAAuB;4BAHrE,aAAa;0BACpB,cAAc;wCACqB,0BAA0B;yBAFtD,aAAa"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { InvitationShape } from '@agoric/zoe/src/typeGuards.js';
|
|
2
|
+
import { makeTracer } from '@agoric/internal';
|
|
3
|
+
import { E } from '@endo/far';
|
|
4
|
+
import { M } from '@endo/patterns';
|
|
5
|
+
import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
|
|
6
|
+
import { prepareChainHubAdmin } from '../exos/chain-hub-admin.js';
|
|
7
|
+
import { withOrchestration } from '../utils/start-helper.js';
|
|
8
|
+
import * as sharedFlows from './shared.flows.js';
|
|
9
|
+
import { swapAnythingViaHook, swapIt } from './swap-anything.flows.js';
|
|
10
|
+
import { AnyNatAmountShape } from '../typeGuards.js';
|
|
11
|
+
import { registerChainsAndAssets } from '../utils/chain-hub-helper.js';
|
|
12
|
+
|
|
13
|
+
const trace = makeTracer('SwapAnything.Contract');
|
|
14
|
+
const interfaceTODO = undefined;
|
|
15
|
+
/**
|
|
16
|
+
* @import {Remote, Vow} from '@agoric/vow';
|
|
17
|
+
* @import {Zone} from '@agoric/zone';
|
|
18
|
+
* @import {OrchestrationPowers, OrchestrationTools} from '../utils/start-helper.js';
|
|
19
|
+
* @import {CosmosChainInfo, Denom, DenomDetail, OrchestrationAccount} from '@agoric/orchestration';
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export const SingleNatAmountRecord = M.and(
|
|
23
|
+
M.recordOf(M.string(), AnyNatAmountShape, { numPropertiesLimit: 1 }),
|
|
24
|
+
M.not(harden({})),
|
|
25
|
+
);
|
|
26
|
+
harden(SingleNatAmountRecord);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Swap assets that are currently in an ERTP purse against another cosmos asset
|
|
30
|
+
* by using an Osmosis pool then have the swap output routed to any address
|
|
31
|
+
*
|
|
32
|
+
* Orchestration contract to be wrapped by withOrchestration for Zoe
|
|
33
|
+
*
|
|
34
|
+
* @param {ZCF} zcf
|
|
35
|
+
* @param {OrchestrationPowers & {
|
|
36
|
+
* assetInfo?: [Denom, DenomDetail & { brandKey?: string }][];
|
|
37
|
+
* chainInfo?: Record<string, CosmosChainInfo>;
|
|
38
|
+
* marshaller: Marshaller;
|
|
39
|
+
* storageNode: Remote<StorageNode>;
|
|
40
|
+
* }} privateArgs
|
|
41
|
+
* @param {Zone} zone
|
|
42
|
+
* @param {OrchestrationTools} tools
|
|
43
|
+
*/
|
|
44
|
+
export const contract = async (
|
|
45
|
+
zcf,
|
|
46
|
+
privateArgs,
|
|
47
|
+
zone,
|
|
48
|
+
{ chainHub, orchestrate, vowTools, zoeTools },
|
|
49
|
+
) => {
|
|
50
|
+
const creatorFacet = prepareChainHubAdmin(zone, chainHub);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @type {OrchestrationAccount<{ chainId: 'agoric' }>} ;
|
|
54
|
+
*/
|
|
55
|
+
let sharedLocalAccount;
|
|
56
|
+
|
|
57
|
+
// UNTIL https://github.com/Agoric/agoric-sdk/issues/9066
|
|
58
|
+
const logNode = E(privateArgs.storageNode).makeChildNode('log');
|
|
59
|
+
/** @type {(msg: string) => Vow<void>} */
|
|
60
|
+
const log = (msg, level = 'info') =>
|
|
61
|
+
vowTools.watch(E(logNode).setValue(JSON.stringify({ msg, level })));
|
|
62
|
+
|
|
63
|
+
const makeLocalAccount = orchestrate(
|
|
64
|
+
'makeLocalAccount',
|
|
65
|
+
{},
|
|
66
|
+
sharedFlows.makeLocalAccount,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
registerChainsAndAssets(
|
|
70
|
+
chainHub,
|
|
71
|
+
zcf.getTerms().brands,
|
|
72
|
+
privateArgs.chainInfo,
|
|
73
|
+
privateArgs.assetInfo,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @type {any} sharedLocalAccountP expects a Promise but this is a vow UNTIL
|
|
78
|
+
* https://github.com/Agoric/agoric-sdk/issues/9822
|
|
79
|
+
*/
|
|
80
|
+
const sharedLocalAccountP = zone.makeOnce('localAccount', () =>
|
|
81
|
+
makeLocalAccount(),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const swapAnythingOffer = orchestrate(
|
|
85
|
+
'swapAnything',
|
|
86
|
+
{ chainHub, sharedLocalAccountP, log, zoeTools },
|
|
87
|
+
swapIt,
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const swapAnythingAddressHook = orchestrate(
|
|
91
|
+
'swapAnythingViaHook',
|
|
92
|
+
{
|
|
93
|
+
chainHub,
|
|
94
|
+
sharedLocalAccountP,
|
|
95
|
+
log,
|
|
96
|
+
},
|
|
97
|
+
swapAnythingViaHook,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const tap = zone.makeOnce('tapPosition', _key => {
|
|
101
|
+
console.log('making tap');
|
|
102
|
+
return zone.exo('tap', interfaceTODO, {
|
|
103
|
+
/**
|
|
104
|
+
* @param {import('@agoric/vats').VTransferIBCEvent} event
|
|
105
|
+
*/
|
|
106
|
+
async receiveUpcall(event) {
|
|
107
|
+
await null;
|
|
108
|
+
trace('receiveUpcall', event);
|
|
109
|
+
|
|
110
|
+
if (event.event !== 'writeAcknowledgement') return;
|
|
111
|
+
trace('Moving on...');
|
|
112
|
+
|
|
113
|
+
const {
|
|
114
|
+
amount,
|
|
115
|
+
extra: { receiver: origReceiver },
|
|
116
|
+
} = await vowTools.when(
|
|
117
|
+
E(sharedLocalAccount).parseInboundTransfer(event.packet),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const { baseAddress, query } = decodeAddressHook(origReceiver);
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @type {{
|
|
124
|
+
* destAddr: string;
|
|
125
|
+
* receiverAddr: string;
|
|
126
|
+
* outDenom: string;
|
|
127
|
+
* }}
|
|
128
|
+
*/
|
|
129
|
+
// @ts-expect-error
|
|
130
|
+
const { destAddr, receiverAddr, outDenom } = query;
|
|
131
|
+
|
|
132
|
+
trace({
|
|
133
|
+
baseAddress,
|
|
134
|
+
destAddr,
|
|
135
|
+
receiverAddr,
|
|
136
|
+
outDenom,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!receiverAddr || !destAddr || !outDenom) return;
|
|
140
|
+
// Invoke the flow to perform swap and end up at the final destination.
|
|
141
|
+
return swapAnythingAddressHook(amount, {
|
|
142
|
+
destAddr,
|
|
143
|
+
receiverAddr,
|
|
144
|
+
outDenom, // swapOutDenom
|
|
145
|
+
onFailedDelivery: 'do_nothing',
|
|
146
|
+
slippage: {
|
|
147
|
+
slippagePercentage: '20',
|
|
148
|
+
windowSeconds: 10,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
void vowTools.when(sharedLocalAccountP, async lca => {
|
|
156
|
+
sharedLocalAccount = lca;
|
|
157
|
+
await sharedLocalAccount.monitorTransfers(tap);
|
|
158
|
+
const encoded = await E(privateArgs.marshaller).toCapData({
|
|
159
|
+
sharedLocalAccount: sharedLocalAccount.getAddress(),
|
|
160
|
+
});
|
|
161
|
+
void E(privateArgs.storageNode).setValue(JSON.stringify(encoded));
|
|
162
|
+
trace('Localchain account information published', encoded);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const publicFacet = zone.exo(
|
|
166
|
+
'Swap Anything PF',
|
|
167
|
+
M.interface('Swap Anything PF', {
|
|
168
|
+
makeSwapInvitation: M.callWhen().returns(InvitationShape),
|
|
169
|
+
}),
|
|
170
|
+
{
|
|
171
|
+
makeSwapInvitation() {
|
|
172
|
+
return zcf.makeInvitation(
|
|
173
|
+
swapAnythingOffer,
|
|
174
|
+
'swap',
|
|
175
|
+
undefined,
|
|
176
|
+
M.splitRecord({ give: SingleNatAmountRecord }),
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return { publicFacet, creatorFacet };
|
|
183
|
+
};
|
|
184
|
+
harden(contract);
|
|
185
|
+
|
|
186
|
+
export const start = withOrchestration(contract, { publishAccountInfo: true });
|
|
187
|
+
harden(start);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function swapIt(orch: Orchestrator, { chainHub, sharedLocalAccountP, log, zoeTools: { localTransfer, withdrawToSeat }, }: {
|
|
2
|
+
chainHub: GuestInterface<ChainHub>;
|
|
3
|
+
sharedLocalAccountP: Promise<GuestInterface<LocalOrchestrationAccountKit["holder"]>>;
|
|
4
|
+
zoeTools: GuestInterface<ZoeTools>;
|
|
5
|
+
log: GuestOf<(msg: string, level?: string) => Vow<void>>;
|
|
6
|
+
}, seat: ZCFSeat, offerArgs: SwapInfo): Promise<string>;
|
|
7
|
+
export function swapAnythingViaHook(_orch: Orchestrator, { chainHub, sharedLocalAccountP }: {
|
|
8
|
+
chainHub: GuestInterface<ChainHub>;
|
|
9
|
+
sharedLocalAccountP: Promise<GuestInterface<LocalOrchestrationAccountKit["holder"]>>;
|
|
10
|
+
}, { denom, value }: DenomAmount, memoArgs: SwapInfo): Promise<void>;
|
|
11
|
+
export type SwapInfo = {
|
|
12
|
+
destAddr: string;
|
|
13
|
+
receiverAddr: string;
|
|
14
|
+
outDenom: Denom;
|
|
15
|
+
slippage: {
|
|
16
|
+
slippagePercentage: string;
|
|
17
|
+
windowSeconds: number;
|
|
18
|
+
};
|
|
19
|
+
onFailedDelivery: string;
|
|
20
|
+
nextMemo?: string;
|
|
21
|
+
};
|
|
22
|
+
import type { Orchestrator } from '../types.js';
|
|
23
|
+
import type { ChainHub } from '../types.js';
|
|
24
|
+
import type { GuestInterface } from '@agoric/async-flow';
|
|
25
|
+
import type { LocalOrchestrationAccountKit } from '../exos/local-orchestration-account.js';
|
|
26
|
+
import type { ZoeTools } from '../utils/zoe-tools.js';
|
|
27
|
+
import type { Vow } from '@agoric/vow';
|
|
28
|
+
import type { GuestOf } from '@agoric/async-flow';
|
|
29
|
+
import type { ZCFSeat } from '@agoric/zoe';
|
|
30
|
+
import type { DenomAmount } from '../types.js';
|
|
31
|
+
import type { Denom } from '@agoric/orchestration';
|
|
32
|
+
//# sourceMappingURL=swap-anything.flows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swap-anything.flows.d.ts","sourceRoot":"","sources":["swap-anything.flows.js"],"names":[],"mappings":"AA8EO,6BAXI,YAAY,wFAEpB;IAAsC,QAAQ,EAAtC,eAAe,QAAQ,CAAC;IAC6C,mBAAmB,EAAxF,OAAO,CAAC,eAAe,4BAA4B,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjC,QAAQ,EAAtC,eAAe,QAAQ,CAAC;IACiC,GAAG,EAA5D,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC;CAC3D,QAAQ,OAAO,aACP,QAAQ,mBAwFlB;AAYM,2CAPI,YAAY,qCAEpB;IAAsC,QAAQ,EAAtC,eAAe,QAAQ,CAAC;IAC6C,mBAAmB,EAAxF,OAAO,CAAC,eAAe,4BAA4B,CAAC,QAAQ,CAAC,CAAC,CAAC;CACvE,oBAAQ,WAAW,YACX,QAAQ,iBAgDlB;uBAnNY;IACR,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC;IAChB,QAAQ,EAAE;QAAE,kBAAkB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;kCAQsF,aAAa;8BAAb,aAAa;oCAN7D,oBAAoB;kDAIf,wCAAwC;8BAC5D,uBAAuB;yBAF5B,aAAa;6BAHO,oBAAoB;6BAEpC,aAAa;iCAImD,aAAa;2BAL/E,uBAAuB"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { NonNullish, makeTracer } from '@agoric/internal';
|
|
2
|
+
import { makeError, q } from '@endo/errors';
|
|
3
|
+
import { M, mustMatch } from '@endo/patterns';
|
|
4
|
+
|
|
5
|
+
const trace = makeTracer('SwapAnything.Flow');
|
|
6
|
+
|
|
7
|
+
const { entries } = Object;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{
|
|
11
|
+
* destAddr: string;
|
|
12
|
+
* receiverAddr: string;
|
|
13
|
+
* outDenom: Denom;
|
|
14
|
+
* slippage: { slippagePercentage: string; windowSeconds: number };
|
|
15
|
+
* onFailedDelivery: string;
|
|
16
|
+
* nextMemo?: string;
|
|
17
|
+
* }} SwapInfo
|
|
18
|
+
*
|
|
19
|
+
* @import {GuestInterface, GuestOf} from '@agoric/async-flow';
|
|
20
|
+
* @import {Denom} from '@agoric/orchestration';
|
|
21
|
+
* @import {ZCFSeat} from '@agoric/zoe';
|
|
22
|
+
* @import {Vow} from '@agoric/vow';
|
|
23
|
+
* @import {LocalOrchestrationAccountKit} from '../exos/local-orchestration-account.js';
|
|
24
|
+
* @import {ZoeTools} from '../utils/zoe-tools.js';
|
|
25
|
+
* @import {Orchestrator, OrchestrationFlow, ChainHub, CosmosChainInfo, DenomAmount} from '../types.js';
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const denomForBrand = async (orch, brand) => {
|
|
29
|
+
const agoric = await orch.getChain('agoric');
|
|
30
|
+
const assets = await agoric.getVBankAssetInfo();
|
|
31
|
+
const { denom } = NonNullish(
|
|
32
|
+
assets.find(a => a.brand === brand),
|
|
33
|
+
`${brand} not registered in ChainHub`,
|
|
34
|
+
);
|
|
35
|
+
return denom;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {SwapInfo} swapInfo
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
const buildXCSMemo = swapInfo => {
|
|
43
|
+
const memo = {
|
|
44
|
+
wasm: {
|
|
45
|
+
contract: swapInfo.destAddr,
|
|
46
|
+
msg: {
|
|
47
|
+
osmosis_swap: {
|
|
48
|
+
output_denom: swapInfo.outDenom,
|
|
49
|
+
slippage: {
|
|
50
|
+
twap: {
|
|
51
|
+
window_seconds: swapInfo.slippage.windowSeconds,
|
|
52
|
+
slippage_percentage: swapInfo.slippage.slippagePercentage,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
receiver: swapInfo.receiverAddr,
|
|
56
|
+
on_failed_delivery: swapInfo.onFailedDelivery,
|
|
57
|
+
nextMemo: swapInfo.nextMemo,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return JSON.stringify(memo);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @satisfies {OrchestrationFlow}
|
|
68
|
+
* @param {Orchestrator} orch
|
|
69
|
+
* @param {object} ctx
|
|
70
|
+
* @param {GuestInterface<ChainHub>} ctx.chainHub
|
|
71
|
+
* @param {Promise<GuestInterface<LocalOrchestrationAccountKit['holder']>>} ctx.sharedLocalAccountP
|
|
72
|
+
* @param {GuestInterface<ZoeTools>} ctx.zoeTools
|
|
73
|
+
* @param {GuestOf<(msg: string, level?: string) => Vow<void>>} ctx.log
|
|
74
|
+
* @param {ZCFSeat} seat
|
|
75
|
+
* @param {SwapInfo} offerArgs
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
// Ref: https://github.com/osmosis-labs/osmosis/tree/main/cosmwasm/contracts/crosschain-swaps#via-ibc
|
|
79
|
+
export const swapIt = async (
|
|
80
|
+
orch,
|
|
81
|
+
{
|
|
82
|
+
chainHub,
|
|
83
|
+
sharedLocalAccountP,
|
|
84
|
+
log,
|
|
85
|
+
zoeTools: { localTransfer, withdrawToSeat },
|
|
86
|
+
},
|
|
87
|
+
seat,
|
|
88
|
+
offerArgs,
|
|
89
|
+
) => {
|
|
90
|
+
mustMatch(
|
|
91
|
+
offerArgs,
|
|
92
|
+
M.splitRecord(
|
|
93
|
+
{
|
|
94
|
+
destAddr: M.string(),
|
|
95
|
+
receiverAddr: M.string(),
|
|
96
|
+
outDenom: M.string(),
|
|
97
|
+
onFailedDelivery: M.string(),
|
|
98
|
+
slippage: { slippagePercentage: M.string(), windowSeconds: M.number() },
|
|
99
|
+
},
|
|
100
|
+
{ nextMemo: M.string() },
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
void log('Begin swapIt');
|
|
104
|
+
|
|
105
|
+
const { receiverAddr, destAddr } = offerArgs;
|
|
106
|
+
// NOTE the proposal shape ensures that the `give` is a single asset
|
|
107
|
+
const { give } = seat.getProposal();
|
|
108
|
+
const [[_kw, amt]] = entries(give);
|
|
109
|
+
trace(`sending {${amt.value}} from osmosis to ${receiverAddr}`);
|
|
110
|
+
const denom = await denomForBrand(orch, amt.brand);
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @type {any} XXX methods returning vows
|
|
114
|
+
* https://github.com/Agoric/agoric-sdk/issues/9822
|
|
115
|
+
*/
|
|
116
|
+
const sharedLocalAccount = await sharedLocalAccountP;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Helper function to recover if IBC Transfer fails
|
|
120
|
+
*
|
|
121
|
+
* @param {Error} e
|
|
122
|
+
*/
|
|
123
|
+
const recoverFailedTransfer = async e => {
|
|
124
|
+
await withdrawToSeat(sharedLocalAccount, seat, give);
|
|
125
|
+
const errorMsg = `IBC Transfer failed ${q(e)}`;
|
|
126
|
+
trace(`ERROR: ${errorMsg}`);
|
|
127
|
+
void log(errorMsg, 'error');
|
|
128
|
+
seat.fail(errorMsg);
|
|
129
|
+
throw makeError(errorMsg);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const [_a, osmosisChainInfo, _connection] =
|
|
133
|
+
await chainHub.getChainsAndConnection('agoric', 'osmosis');
|
|
134
|
+
|
|
135
|
+
trace(`got info for chain: osmosis ${osmosisChainInfo}`);
|
|
136
|
+
trace(osmosisChainInfo);
|
|
137
|
+
|
|
138
|
+
await localTransfer(seat, sharedLocalAccount, give);
|
|
139
|
+
trace(`completed transfer to localAccount`);
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const memo = buildXCSMemo(offerArgs);
|
|
143
|
+
trace(memo);
|
|
144
|
+
void log(`sending transfer with ${q(memo)}`);
|
|
145
|
+
|
|
146
|
+
await sharedLocalAccount.transfer(
|
|
147
|
+
{
|
|
148
|
+
value: destAddr,
|
|
149
|
+
encoding: 'bech32',
|
|
150
|
+
chainId: /** @type {CosmosChainInfo} */ (osmosisChainInfo).chainId,
|
|
151
|
+
},
|
|
152
|
+
{ denom, value: amt.value },
|
|
153
|
+
{ memo },
|
|
154
|
+
);
|
|
155
|
+
trace(`completed transfer to ${destAddr}`);
|
|
156
|
+
} catch (e) {
|
|
157
|
+
void log(`transfer error ${q(e)}`, 'error');
|
|
158
|
+
return recoverFailedTransfer(e);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
seat.exit();
|
|
162
|
+
return 'transfer complete, seat exited';
|
|
163
|
+
};
|
|
164
|
+
harden(swapIt);
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @satisfies {OrchestrationFlow}
|
|
168
|
+
* @param {Orchestrator} _orch
|
|
169
|
+
* @param {object} ctx
|
|
170
|
+
* @param {GuestInterface<ChainHub>} ctx.chainHub
|
|
171
|
+
* @param {Promise<GuestInterface<LocalOrchestrationAccountKit['holder']>>} ctx.sharedLocalAccountP
|
|
172
|
+
* @param {DenomAmount} transferInfo
|
|
173
|
+
* @param {SwapInfo} memoArgs
|
|
174
|
+
*/
|
|
175
|
+
export const swapAnythingViaHook = async (
|
|
176
|
+
_orch,
|
|
177
|
+
{ chainHub, sharedLocalAccountP },
|
|
178
|
+
{ denom, value },
|
|
179
|
+
memoArgs,
|
|
180
|
+
) => {
|
|
181
|
+
mustMatch(
|
|
182
|
+
memoArgs,
|
|
183
|
+
M.splitRecord(
|
|
184
|
+
{
|
|
185
|
+
destAddr: M.string(),
|
|
186
|
+
receiverAddr: M.string(),
|
|
187
|
+
outDenom: M.string(),
|
|
188
|
+
onFailedDelivery: M.string(),
|
|
189
|
+
slippage: { slippagePercentage: M.string(), windowSeconds: M.number() },
|
|
190
|
+
},
|
|
191
|
+
{ nextMemo: M.string() },
|
|
192
|
+
),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const { receiverAddr, destAddr } = memoArgs;
|
|
196
|
+
trace(`sending {${value}} from osmosis to ${receiverAddr}`);
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @type {any} XXX methods returning vows
|
|
200
|
+
* https://github.com/Agoric/agoric-sdk/issues/9822
|
|
201
|
+
*/
|
|
202
|
+
const sharedLocalAccount = await sharedLocalAccountP;
|
|
203
|
+
|
|
204
|
+
const [_a, osmosisChainInfo, _connection] =
|
|
205
|
+
await chainHub.getChainsAndConnection('agoric', 'osmosis');
|
|
206
|
+
|
|
207
|
+
trace(`got info for chain: osmosis ${osmosisChainInfo}`);
|
|
208
|
+
trace(osmosisChainInfo);
|
|
209
|
+
|
|
210
|
+
const memo = buildXCSMemo(memoArgs);
|
|
211
|
+
|
|
212
|
+
await sharedLocalAccount.transfer(
|
|
213
|
+
{
|
|
214
|
+
value: destAddr,
|
|
215
|
+
encoding: 'bech32',
|
|
216
|
+
chainId: /** @type {CosmosChainInfo} */ (osmosisChainInfo).chainId,
|
|
217
|
+
},
|
|
218
|
+
{ denom, value },
|
|
219
|
+
{ memo },
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
harden(swapAnythingViaHook);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ibc-packet.d.ts","sourceRoot":"","sources":["ibc-packet.js"],"names":[],"mappings":"AAMA,4CAA6C,MAAM,CAAC;AAsB7C,gDAHI,GAAG,GACD,OAAO,CAgCnB;AAOM,+CAHI,OAAO,mBAAmB,EAAE,IAAI,8BAChC,QAAQ,GAAG;IAAE,eAAe,EAAE,eAAe,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"ibc-packet.d.ts","sourceRoot":"","sources":["ibc-packet.js"],"names":[],"mappings":"AAMA,4CAA6C,MAAM,CAAC;AAsB7C,gDAHI,GAAG,GACD,OAAO,CAgCnB;AAOM,+CAHI,OAAO,mBAAmB,EAAE,IAAI,8BAChC,QAAQ,GAAG;IAAE,eAAe,EAAE,eAAe,CAAA;CAAE,IA2HhD,GAAG,MAFA,UAAU;eAvGH,iBAAiB,CAAC,WAAW,CAAC;;;;;QAU1C;;;;;WAKG;0BAJQ,IACV,SAAa,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAC,CAC9D,QACO,aAAa;;;;;;QAYxB;;;;;;;;;;;;;;;;WAgBG;oCAbQ,CACV,SACA,WACA,UAAkB,2CAA2C,CAAC,CACvD,CACF,CACF,OACO;YACN,IAAI,EAAE,aAAa,CAAC;YACpB,KAAK,EAAE,IACX,SAAe,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAC,CAC9D,CAAC;SACH;;;;;;;;GAgEK;IA/FT;;;;;OAKG;sBAJQ,IACV,SAAa,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAC,CAC9D,QACO,aAAa;;;;GA4F/B;AAaM,yCAHI,OAAO,mBAAmB,EAAE,IAAI,YAChC,QAAQ,IAqC6D,CAAC,SAAjE,SAAS,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAE,sFACjE,OAAO,UACP,IAAI,CAAC,CAAC,QACN,aAAa;;;EAmBzB;AAQM,sCAHI,OAAO,mBAAmB,EAAE,IAAI,YAChC,QAAQ;;mBAtLC,iBAAiB,CAAC,WAAW,CAAC;;;;QAU1C;;;;;WAKG;0BAJQ,IACV,SAAa,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAC,CAC9D,QACO,aAAa;;;;;sBA4IgD,CAAC,SAAjE,SAAS,uBAAuB,CAAC,GAAG,SAAS,eAAe,CAAE,sFACjE,OAAO,UACP,IAAI,CAAC,CAAC,QACN,aAAa;;;;EAkCzB;8BAba,UAAU,CAAC,OAAO,kBAAkB,CAAC;6BAxPpB,gBAAgB;8BAEf,aAAa;8BACP,cAAc;yBADpB,aAAa;mCAGb,mBAAmB;uCADf,gCAAgC;+BAHlB,sBAAsB;gCAAtB,sBAAsB;8BAAtB,sBAAsB"}
|
package/src/exos/ibc-packet.js
CHANGED
|
@@ -157,8 +157,25 @@ export const prepareIBCTransferSender = (zone, { watch, makeIBCReplyKit }) => {
|
|
|
157
157
|
const { result, error } = obj;
|
|
158
158
|
error === undefined || Fail`ICS20-1 transfer error ${error}`;
|
|
159
159
|
result ?? Fail`Missing result in ICS20-1 transfer ack ${obj}`;
|
|
160
|
-
result === ICS20_TRANSFER_SUCCESS_RESULT
|
|
161
|
-
|
|
160
|
+
if (result === ICS20_TRANSFER_SUCCESS_RESULT) {
|
|
161
|
+
return; // OK, transfer was successful, nothing to do
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Function to safely base64-decode and parse JSON
|
|
165
|
+
const decodeAndParse = b64 => {
|
|
166
|
+
try {
|
|
167
|
+
return JSON.parse(atob(b64));
|
|
168
|
+
} catch {
|
|
169
|
+
Fail`Decoding of base64-encoded ack obj object failed: ${JSON.stringify(b64)}`;
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const outerDecoded = decodeAndParse(result);
|
|
174
|
+
const ibcAck =
|
|
175
|
+
outerDecoded?.ibc_ack && decodeAndParse(outerDecoded.ibc_ack);
|
|
176
|
+
|
|
177
|
+
ibcAck?.result === ICS20_TRANSFER_SUCCESS_RESULT ||
|
|
178
|
+
Fail`ICS20-1 transfer unsuccessful with ack result: ${outerDecoded}`;
|
|
162
179
|
},
|
|
163
180
|
},
|
|
164
181
|
},
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deeplyFulfilledObject,
|
|
3
|
+
makeTracer,
|
|
4
|
+
NonNullish,
|
|
5
|
+
} from '@agoric/internal';
|
|
6
|
+
import { E } from '@endo/far';
|
|
7
|
+
|
|
8
|
+
/// <reference types="@agoric/vats/src/core/types-ambient"/>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @import {Installation} from '@agoric/zoe/src/zoeService/utils.js';
|
|
12
|
+
* @import {CosmosChainInfo, Denom, DenomDetail} from '@agoric/orchestration';
|
|
13
|
+
* @import {start as StartFn} from '@agoric/orchestration/src/examples/swap-anything.contract.js';
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const trace = makeTracer('StartSA', true);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {BootstrapPowers & {
|
|
20
|
+
* installation: {
|
|
21
|
+
* consume: {
|
|
22
|
+
* swapAnything: Installation<StartFn>;
|
|
23
|
+
* };
|
|
24
|
+
* };
|
|
25
|
+
* instance: {
|
|
26
|
+
* produce: {
|
|
27
|
+
* swapAnything: Producer<Instance>;
|
|
28
|
+
* };
|
|
29
|
+
* };
|
|
30
|
+
* issuer: {
|
|
31
|
+
* consume: {
|
|
32
|
+
* BLD: Issuer<'nat'>;
|
|
33
|
+
* IST: Issuer<'nat'>;
|
|
34
|
+
* };
|
|
35
|
+
* };
|
|
36
|
+
* }} powers
|
|
37
|
+
* @param {{
|
|
38
|
+
* options: {
|
|
39
|
+
* chainInfo: Record<string, CosmosChainInfo>;
|
|
40
|
+
* assetInfo: [Denom, DenomDetail & { brandKey?: string }][];
|
|
41
|
+
* };
|
|
42
|
+
* }} config
|
|
43
|
+
*/
|
|
44
|
+
export const startSwapAnything = async (
|
|
45
|
+
{
|
|
46
|
+
consume: {
|
|
47
|
+
agoricNames,
|
|
48
|
+
board,
|
|
49
|
+
chainStorage,
|
|
50
|
+
chainTimerService,
|
|
51
|
+
cosmosInterchainService,
|
|
52
|
+
localchain,
|
|
53
|
+
startUpgradable,
|
|
54
|
+
},
|
|
55
|
+
installation: {
|
|
56
|
+
consume: { swapAnything },
|
|
57
|
+
},
|
|
58
|
+
instance: {
|
|
59
|
+
produce: { swapAnything: produceInstance },
|
|
60
|
+
},
|
|
61
|
+
issuer: {
|
|
62
|
+
consume: { BLD, IST },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{ options: { chainInfo, assetInfo } },
|
|
66
|
+
) => {
|
|
67
|
+
trace(startSwapAnything.name);
|
|
68
|
+
|
|
69
|
+
const marshaller = await E(board).getReadonlyMarshaller();
|
|
70
|
+
|
|
71
|
+
const privateArgs = await deeplyFulfilledObject(
|
|
72
|
+
harden({
|
|
73
|
+
agoricNames,
|
|
74
|
+
localchain,
|
|
75
|
+
marshaller,
|
|
76
|
+
orchestrationService: cosmosInterchainService,
|
|
77
|
+
storageNode: E(NonNullish(await chainStorage)).makeChildNode(
|
|
78
|
+
'swap-anything',
|
|
79
|
+
),
|
|
80
|
+
timerService: chainTimerService,
|
|
81
|
+
chainInfo,
|
|
82
|
+
assetInfo,
|
|
83
|
+
}),
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const issuerKeywordRecord = harden({
|
|
87
|
+
BLD: await BLD,
|
|
88
|
+
IST: await IST,
|
|
89
|
+
});
|
|
90
|
+
trace('issuerKeywordRecord', issuerKeywordRecord);
|
|
91
|
+
|
|
92
|
+
const { instance } = await E(startUpgradable)({
|
|
93
|
+
label: 'swap-anything',
|
|
94
|
+
installation: swapAnything,
|
|
95
|
+
issuerKeywordRecord,
|
|
96
|
+
privateArgs,
|
|
97
|
+
});
|
|
98
|
+
produceInstance.resolve(instance);
|
|
99
|
+
trace('done');
|
|
100
|
+
};
|
|
101
|
+
harden(startSwapAnything);
|
|
102
|
+
|
|
103
|
+
export const getManifest = ({ restoreRef }, { installationRef, options }) => {
|
|
104
|
+
return {
|
|
105
|
+
manifest: {
|
|
106
|
+
[startSwapAnything.name]: {
|
|
107
|
+
consume: {
|
|
108
|
+
agoricNames: true,
|
|
109
|
+
board: true,
|
|
110
|
+
chainStorage: true,
|
|
111
|
+
chainTimerService: true,
|
|
112
|
+
cosmosInterchainService: true,
|
|
113
|
+
localchain: true,
|
|
114
|
+
|
|
115
|
+
startUpgradable: true,
|
|
116
|
+
},
|
|
117
|
+
installation: {
|
|
118
|
+
consume: { swapAnything: true },
|
|
119
|
+
},
|
|
120
|
+
instance: {
|
|
121
|
+
produce: { swapAnything: true },
|
|
122
|
+
},
|
|
123
|
+
issuer: {
|
|
124
|
+
consume: { BLD: true, IST: true },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
installations: {
|
|
129
|
+
swapAnything: restoreRef(installationRef),
|
|
130
|
+
},
|
|
131
|
+
options,
|
|
132
|
+
};
|
|
133
|
+
};
|