Skip to content

Commit ffa30d9

Browse files
committed
feat: ICA Probe contract (WIP)
1 parent b9e6d53 commit ffa30d9

File tree

5 files changed

+253
-2
lines changed

5 files changed

+253
-2
lines changed

packages/orch-skel/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
"@agoric/cosmic-proto": "^0.4.0",
2323
"@agoric/ertp": "^0.16.2",
2424
"@agoric/fast-usdc": "^0.1.0",
25-
"@agoric/internal": "^0.3.2",
2625
"@agoric/swingset-liveslots": "^0.10.2",
2726
"@agoric/vow": "^0.1.0",
2827
"@agoric/zoe": "^0.26.2",
@@ -36,6 +35,7 @@
3635
"ts-blank-space": "^0.6.1"
3736
},
3837
"dependencies": {
38+
"@agoric/internal": "^0.3.2",
3939
"@agoric/orchestration": "^0.1.0",
4040
"@agoric/vats": "^0.15.1",
4141
"@endo/errors": "^1.2.10",
@@ -60,4 +60,4 @@
6060
],
6161
"timeout": "20m"
6262
}
63-
}
63+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// @ts-check
2+
import { makeTracer, mustMatch } from '@agoric/internal';
3+
import { withOrchestration, ChainInfoShape } from '@agoric/orchestration';
4+
import { M } from '@endo/patterns';
5+
import * as flows from './ica-probe.flows.js';
6+
7+
/**
8+
* @import {TypedPattern} from '@agoric/internal';
9+
* @import { ZCF } from '@agoric/zoe/src/zoeService/zoe.js';
10+
* @import {Zone} from '@agoric/zone';
11+
* @import {ChainInfo} from '@agoric/orchestration';
12+
* @import {OrchestrationPowers, OrchestrationTools} from '@agoric/orchestration/src/utils/start-helper.js';
13+
*/
14+
15+
const trace = makeTracer('ICApr');
16+
17+
/** @type {TypedPattern<{ name: string, chainInfo: ChainInfo }>} */
18+
const registerArgsShape = harden({
19+
name: M.string(),
20+
chainInfo: ChainInfoShape,
21+
});
22+
23+
/**
24+
* @param {ZCF} zcf
25+
* @param {OrchestrationPowers} privateArgs
26+
* @param {Zone} zone
27+
* @param {OrchestrationTools} tools
28+
*/
29+
const contract = async (zcf, privateArgs, zone, tools) => {
30+
const { makeICA } = tools.orchestrateAll(flows, {});
31+
32+
const registerChainHandler = zone.exo('rch', undefined, {
33+
handle(seat, offerArgs) {
34+
trace('TODO: charge fee to register chain');
35+
mustMatch(offerArgs, registerArgsShape);
36+
const { name, chainInfo } = offerArgs;
37+
tools.chainHub.registerChain(name, chainInfo);
38+
return name;
39+
},
40+
});
41+
42+
const publicFacet = zone.exo('ICAProbeAPI', undefined, {
43+
makeRegisterChainInvitation() {
44+
return zcf.makeInvitation(registerChainHandler, 'register chain');
45+
},
46+
makeMakeICAIinvitation() {
47+
return zcf.makeInvitation(makeICA, 'makeICA');
48+
},
49+
});
50+
51+
return { publicFacet };
52+
};
53+
54+
export const start = withOrchestration(contract);
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { deeplyFulfilledObject } from '@agoric/internal';
2+
import { E } from '@endo/far';
3+
4+
/**
5+
* @import {CoreEvalBuilder, DeployScriptFunction} from '@agoric/deploy-script-support/src/externalTypes.js'
6+
*/
7+
8+
const trace = (...args) => console.log('ICAPd', ...args);
9+
10+
export const startICAProbe = async powers => {
11+
trace('startICAProbe');
12+
const {
13+
agoricNames,
14+
localchain,
15+
board,
16+
cosmosInterchainService,
17+
chainStorage,
18+
chainTimerService,
19+
} = powers.consume;
20+
const marshaller = await E(board).getReadonlyMarshaller();
21+
const privateArgs = await deeplyFulfilledObject(
22+
harden({
23+
agoricNames,
24+
localchain,
25+
marshaller,
26+
orchestrationService: cosmosInterchainService,
27+
storageNode: E(chainStorage).makeChildNode('StkC'),
28+
timerService: chainTimerService,
29+
}),
30+
);
31+
trace('privateArgs', Object.keys(privateArgs));
32+
const { startUpgradable } = powers.consume;
33+
const { ICAProbe: installation } = powers.installation.consume;
34+
const kit = E(startUpgradable)({
35+
label: 'ICAProbe',
36+
installation,
37+
privateArgs,
38+
});
39+
trace('started ICAProbe', Object.keys(kit));
40+
powers.instance.ICAProbe.produce(kit.instance);
41+
trace('done');
42+
};
43+
44+
const orchPermit = {
45+
consume: {
46+
agoricNames: true,
47+
chainTimerService: true,
48+
chainStorage: true,
49+
cosmosInterchainService: true,
50+
localchain: true,
51+
},
52+
};
53+
54+
export const getManifest = ({ restoreRef }, { installationRef, options }) => {
55+
return {
56+
manifest: {
57+
[startICAProbe.name]: {
58+
consume: { ...orchPermit.consume, board: true, startUpgradable: true },
59+
installation: { consume: { ICAProbe: true } },
60+
instance: { produce: { ICAProbe: true } },
61+
},
62+
},
63+
installations: { ICAProbe: restoreRef(installationRef) },
64+
options,
65+
};
66+
};
67+
68+
/** @satisfies {CoreEvalBuilder} */
69+
export const defaultProposalBuilder = async (
70+
{ publishRef, install },
71+
options,
72+
) =>
73+
harden({
74+
sourceSpec: './ica-probe.deploy.js',
75+
getManifestCall: [
76+
getManifest.name,
77+
{
78+
installationRef: publishRef(install('./ica-probe.contract.js')),
79+
options,
80+
},
81+
],
82+
});
83+
84+
export default async (homeP, endowments) => {
85+
// import dynamically so the module can work in CoreEval environment
86+
const dspModule = await import('@agoric/deploy-script-support');
87+
const { makeHelpers } = dspModule;
88+
const { writeCoreEval } = await makeHelpers(homeP, endowments);
89+
await writeCoreEval(startICAProbe.name, defaultProposalBuilder);
90+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// @ts-check
2+
import { makeTracer, mustMatch } from '@agoric/internal';
3+
4+
const trace = makeTracer('flows');
5+
6+
/**
7+
* @import {Orchestrator, OrchestrationFlow } from '@agoric/orchestration';
8+
* @import { ZCFSeat } from '@agoric/zoe/src/zoeService/zoe.js';
9+
* @import {Passable, CopyRecord} from '@endo/pass-style';
10+
*/
11+
12+
/**
13+
* @satisfies {OrchestrationFlow}
14+
* @param {Orchestrator} orch
15+
* @param {{ }} _ctx
16+
* @param {ZCFSeat & Passable} seat
17+
* @param {{ chainName: string } & CopyRecord } offerArgs
18+
*/
19+
export const makeICA = async (orch, _ctx, seat, { chainName }) => {
20+
trace('TODO: charge fee', seat.getProposal());
21+
const chain = await orch.getChain(chainName);
22+
trace('making ICA on', chainName);
23+
const ica = await chain.makeAccount();
24+
const addr = await ica.getAddress();
25+
trace('make ICA with addr', addr);
26+
trace('TODO: dispose of ICA? retain it?');
27+
return addr;
28+
};
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// prepare-test-env has to go 1st; use a blank line to separate it
2+
import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js';
3+
4+
import type { CoinSDKType } from '@agoric/cosmic-proto/cosmos/base/v1beta1/coin.js';
5+
import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js';
6+
import { heapVowE as VE } from '@agoric/vow/vat.js';
7+
import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js';
8+
import { E, passStyleOf } from '@endo/far';
9+
import { Nat } from '@endo/nat';
10+
import { M, mustMatch } from '@endo/patterns';
11+
import { createRequire } from 'module';
12+
import { ChainAddressShape } from '@agoric/orchestration';
13+
import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js';
14+
import { commonSetup } from './supports.js';
15+
16+
const nodeRequire = createRequire(import.meta.url);
17+
18+
const contractName = 'myOrchContract';
19+
const contractFile = nodeRequire.resolve('../src/ica-probe.contract.js');
20+
type StartFn = typeof import('../src/ica-probe.contract.js').start;
21+
22+
test('start my orch contract', async t => {
23+
const common = await commonSetup(t);
24+
const { zoe, bundleAndInstall } = await setUpZoeForTest();
25+
t.log('contract deployment', contractName);
26+
27+
const installation: Installation<StartFn> =
28+
await bundleAndInstall(contractFile);
29+
t.is(passStyleOf(installation), 'remotable');
30+
31+
const myKit = await E(zoe).startInstance(
32+
installation,
33+
{}, // issuers
34+
{}, // terms
35+
common.commonPrivateArgs,
36+
);
37+
t.notThrows(() =>
38+
mustMatch(
39+
myKit,
40+
M.splitRecord({
41+
instance: M.remotable(),
42+
publicFacet: M.remotable(),
43+
creatorFacet: M.remotable(),
44+
// ...others are not relevant here
45+
}),
46+
),
47+
);
48+
49+
{
50+
const toRegister = await E(myKit.publicFacet).makeRegisterChainInvitation();
51+
const { osmosis: chainInfo } = common.commonPrivateArgs.chainInfo;
52+
const seat = await E(zoe).offer(
53+
toRegister,
54+
{},
55+
{},
56+
{ name: 'osmosis', chainInfo },
57+
);
58+
const result = await E(seat).getOfferResult();
59+
t.log('register result', result);
60+
t.is(result, 'osmosis');
61+
}
62+
{
63+
const toMakeICA = await E(myKit.publicFacet).makeMakeICAIinvitation();
64+
const seat = await E(zoe).offer(
65+
toMakeICA,
66+
{},
67+
{},
68+
{ chainName: 'osmosis' },
69+
);
70+
const { vowTools } = common.utils;
71+
const result = await vowTools.when(await E(seat).getOfferResult());
72+
t.log('register result', result);
73+
t.deepEqual(result, {
74+
chainId: 'osmosis-1',
75+
encoding: 'bech32',
76+
value: 'cosmos1test',
77+
});
78+
}
79+
});

0 commit comments

Comments
 (0)