Skip to content

Commit

Permalink
feat: separate wallet implementation from ag-solo
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Aug 5, 2020
1 parent 1d2925a commit 0bf7eab
Show file tree
Hide file tree
Showing 15 changed files with 199 additions and 95 deletions.
18 changes: 14 additions & 4 deletions packages/cosmic-swingset/lib/ag-solo/init-basedir.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,29 @@ export default function initBasedir(
// Symlink the wallet.
let agWallet;
try {
agWallet = path.resolve(__dirname, '../../../wallet-frontend/build');
agWallet = path.resolve(__dirname, '../../../wallet-frontend');
let walletBuild = path.join(agWallet, 'build');
if (!fs.existsSync(agWallet)) {
const pjs = require.resolve('@agoric/wallet-frontend/package.json');
agWallet = path.join(path.dirname(pjs), 'build');
fs.statSync(agWallet);
agWallet = path.dirname(pjs);
walletBuild = path.join(agWallet, 'build');
fs.statSync(walletBuild);
}
fs.symlinkSync(agWallet, `${dstHtmldir}/wallet`);
fs.symlinkSync(walletBuild, `${dstHtmldir}/wallet`);
} catch (e) {
console.warn(
`${agWallet} does not exist; you may want to run 'yarn build' in 'wallet-frontend'`,
);
}

const walletDeploy = path.join(agWallet, 'wallet-deploy.js');
try {
fs.statSync(walletDeploy);
fs.symlinkSync(walletDeploy, path.join(basedir, 'wallet-deploy.js'));
} catch (e) {
console.warn(`${walletDeploy} does not exist; cannot autodeploy wallet`);
}

// Save our version codes.
const pj = 'package.json';
fs.copyFileSync(path.join(`${here}/../..`, pj), path.join(dstHtmldir, pj));
Expand Down
30 changes: 30 additions & 0 deletions packages/cosmic-swingset/lib/ag-solo/start.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import path from 'path';
import temp from 'temp';
import { exec } from 'child_process';
import { promisify } from 'util';
// import { createHash } from 'crypto';

Expand Down Expand Up @@ -246,6 +247,7 @@ export default async function start(basedir, argv) {
startTimer,
} = d;

let hostport;
await Promise.all(
connections.map(async c => {
switch (c.type) {
Expand Down Expand Up @@ -282,6 +284,7 @@ export default async function start(basedir, argv) {
if (broadcastJSON) {
throw new Error(`duplicate type=http in connections.json`);
}
hostport = `${c.host}:${c.port}`;
broadcastJSON = await makeHTTPListener(
basedir,
c.port,
Expand All @@ -301,4 +304,31 @@ export default async function start(basedir, argv) {
log.info(`swingset running`);
swingSetRunning = true;
deliverOutbound();

if (hostport && fs.existsSync('./wallet-deploy.js')) {
// Install the wallet.
let agoricCli;
try {
agoricCli = require.resolve('.bin/agoric');
} catch (e) {
// do nothing
console.log(`Cannot find agoric CLI:`, e);
}
// Launch the agoric deploy, letting it synchronize with the chain.
if (agoricCli) {
exec(
`${agoricCli} deploy --hostport=${hostport} ./wallet-deploy.js`,
(err, stdout, stderr) => {
if (err) {
console.warn(err);
return;
}
if (stderr) {
// Report the error.
console.error(stderr);
}
},
);
}
}
}
138 changes: 54 additions & 84 deletions packages/cosmic-swingset/lib/ag-solo/vats/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,6 @@ export function buildRootObject(vatPowers) {
D(cmdDevice).registerInboundHandler(httpVat);
}

async function setupWalletVat(httpObj, httpVat, walletVat) {
await E(httpVat).registerURLHandler(walletVat, '/private/wallet');
const bridgeURLHandler = await E(walletVat).getBridgeURLHandler();
await E(httpVat).registerURLHandler(
bridgeURLHandler,
'/private/wallet-bridge',
);
await E(walletVat).setHTTPObject(httpObj);
await E(walletVat).setPresences();
}

// Make services that are provided on the real or virtual chain side
async function makeChainBundler(vats, timerDevice, vatAdminSvc) {
// Create singleton instances.
Expand Down Expand Up @@ -124,27 +113,47 @@ export function buildRootObject(vatPowers) {
};
}

const pursePetnames = {
moola: 'Fun budget',
simolean: 'Nest egg',
};

const payments = await E(vats.mints).mintInitialPayments(
issuerNames,
harden([1900, 1900]),
);

const paymentInfo = issuerInfo.map(
({ petname: issuerPetname, issuer }, i) => ({
issuerPetname,
issuer,
payment: payments[i],
pursePetname:
pursePetnames[issuerPetname] || `${issuerPetname} purse`,
}),
);

const faucet = {
// A method to reap the spoils of our on-chain provisioning.
async tapFaucet() {
return paymentInfo;
},
};

const bundle = harden({
...additionalPowers,
chainTimerService,
sharingService,
contractHost,
faucet,
ibcport,
registrar: registry,
registry,
board,
zoe,
});

const payments = await E(vats.mints).mintInitialPayments(
issuerNames,
harden([1900, 1900]),
);

// return payments and issuerInfo separately from the
// bundle so that they can be used to initialize a wallet
// per user
return harden({ payments, issuerInfo, bundle });
return bundle;
},
});
}
Expand Down Expand Up @@ -225,62 +234,44 @@ export function buildRootObject(vatPowers) {
// objects that live in the client's solo vat. Some services should only
// be in the DApp environment (or only in end-user), but we're not yet
// making a distinction, so the user also gets them.
async function createLocalBundle(vats, userBundle, payments, issuerInfo) {
const { zoe, board } = userBundle;
async function createLocalBundle(vats) {
// This will eventually be a vat spawning service. Only needed by dev
// environments.
const spawner = E(vats.host).makeHost();

// Needed for DApps, maybe for user clients.
const uploads = E(vats.uploads).getUploads();

// Wallet for both end-user client and dapp dev client
await E(vats.wallet).startup({ zoe, board });
const wallet = E(vats.wallet).getWallet();
await Promise.all(
issuerInfo.map(({ petname, issuer }) =>
E(wallet).addIssuer(petname, issuer),
),
);

// Make empty purses. Have some petnames for them.
const pursePetnames = {
moola: 'Fun budget',
simolean: 'Nest egg',
};
await Promise.all(
issuerInfo.map(({ petname: issuerPetname }) => {
let pursePetname = pursePetnames[issuerPetname];
if (!pursePetname) {
pursePetname = `${issuerPetname} purse`;
pursePetnames[issuerPetname] = pursePetname;
}
return E(wallet).makeEmptyPurse(issuerPetname, pursePetname);
}),
);

// deposit payments
const [moolaPayment, simoleanPayment] = await Promise.all(payments);

await E(wallet).deposit(pursePetnames.moola, moolaPayment);
await E(wallet).deposit(pursePetnames.simolean, simoleanPayment);

// This will allow dApp developers to register in their api/deploy.js
let walletRegistered = false;
const httpRegCallback = {
send(obj, connectionHandles) {
return E(vats.http).send(obj, connectionHandles);
},
registerAPIHandler(handler) {
return E(vats.http).registerURLHandler(handler, '/api');
},
async registerWallet(wallet, handler, bridgeHandler) {
if (walletRegistered) {
throw Error(`Unimplemented multiple wallet registrations`);
}
walletRegistered = true;
await Promise.all([
E(vats.http).registerURLHandler(handler, '/private/wallet'),
E(vats.http).registerURLHandler(
bridgeHandler,
'/private/wallet-bridge',
),
E(vats.http).setWallet(wallet),
]);
},
};

return allComparable(
harden({
comms: vats.comms,
uploads,
spawner,
wallet,
network: vats.network,
http: httpRegCallback,
vattp: vats.vattp,
Expand Down Expand Up @@ -354,19 +345,12 @@ export function buildRootObject(vatPowers) {
GCI,
PROVISIONER_INDEX,
);
const { payments, bundle, issuerInfo } = await E(
demoProvider,
).getDemoBundle();
const localBundle = await createLocalBundle(
vats,
bundle,
payments,
issuerInfo,
);
const localBundle = await createLocalBundle(vats);
await E(vats.http).setPresences(localBundle);
const bundle = await E(demoProvider).getDemoBundle();
await E(vats.http).setPresences(localBundle, bundle, {
localTimerService,
});
await setupWalletVat(localBundle.http, vats.http, vats.wallet);
break;
}
case 'two_chain': {
Expand Down Expand Up @@ -437,18 +421,12 @@ export function buildRootObject(vatPowers) {
// addEgress(..., PROVISIONER_INDEX) is called in case two_chain
const demoProvider = E(vats.comms).addIngress(GCI, PROVISIONER_INDEX);
// Get the demo bundle from the chain-side provider
const b = await E(demoProvider).getDemoBundle('client');
const { payments, bundle, issuerInfo } = b;
const localBundle = await createLocalBundle(
vats,
bundle,
payments,
issuerInfo,
);
const localBundle = await createLocalBundle(vats);
await E(vats.http).setPresences(localBundle);
const bundle = await E(demoProvider).getDemoBundle('client');
await E(vats.http).setPresences(localBundle, bundle, {
localTimerService,
});
await setupWalletVat(localBundle.http, vats.http, vats.wallet);
break;
}
case 'three_client': {
Expand All @@ -467,22 +445,14 @@ export function buildRootObject(vatPowers) {
await setupCommandDevice(vats.http, devices.command, {
client: true,
});
const { payments, bundle, issuerInfo } = await E(
chainBundler,
).createUserBundle('localuser');
const localBundle = await createLocalBundle(vats);
await E(vats.http).setPresences(localBundle);
const bundle = await E(chainBundler).createUserBundle('localuser');

// Setup of the Local part /////////////////////////////////////
const localBundle = await createLocalBundle(
vats,
bundle,
payments,
issuerInfo,
);
await E(vats.http).setPresences(localBundle, bundle, {
localTimerService: bundle.chainTimerService,
});

setupWalletVat(localBundle.http, vats.http, vats.wallet);
break;
}
default:
Expand Down
16 changes: 15 additions & 1 deletion packages/cosmic-swingset/lib/ag-solo/vats/vat-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,20 @@ export function buildRootObject(vatPowers) {
provisioner = p;
},

setWallet(wallet) {
// This must happen only after the local and agoric objects have been
// installed in setPresences.
// We're guaranteed that because the deployment script that installs
// the wallet only runs after the chain has provisioned us.
exportedToCapTP = {
...exportedToCapTP,
local: { ...exportedToCapTP.local, wallet },
wallet,
};
replObjects.local.wallet = wallet;
replObjects.home.wallet = wallet;
},

setPresences(
privateObjects,
decentralObjects = undefined,
Expand All @@ -132,7 +146,7 @@ export function buildRootObject(vatPowers) {
...privateObjects, // TODO: Remove; replaced by .local
...handyObjects,
LOADING: loaded.p, // TODO: Remove; replaced by .agoric.LOADING
agoric: { decentralObjects, LOADING: loaded.p },
agoric: { ...decentralObjects, LOADING: loaded.p },
local: privateObjects,
};

Expand Down
1 change: 1 addition & 0 deletions packages/cosmic-swingset/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@agoric/wallet-frontend": "^0.2.7",
"@agoric/weak-store": "^0.0.8",
"@agoric/zoe": "^0.7.0",
"agoric": "^0.7.0",
"@babel/generator": "^7.6.4",
"@iarna/toml": "^2.2.3",
"anylogger": "^0.21.0",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 11 additions & 0 deletions packages/wallet-frontend/lib/wallet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* global harden */

// TODO: Don't just make this an adapter.
import { buildRootObject } from './vat-wallet';

function spawn(terms, _inviteMaker) {
const walletVat = buildRootObject();
return walletVat.startup(terms).then(_ => walletVat);
}

export default harden(spawn);
11 changes: 8 additions & 3 deletions packages/wallet-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"prepublish": "yarn build",
"start": "react-scripts start",
"test:interactive": "react-scripts test --env=jsdom",
"test": "exit 0",
"test": "tap --no-coverage --jobs=1 --timeout 600 'test/**/test*.js'",
"build": "react-scripts build",
"eject": "react-scripts eject"
},
Expand All @@ -30,9 +30,12 @@
]
},
"files": [
"build"
"build",
"lib",
"wallet-deploy.js"
],
"devDependencies": {
"@agoric/install-ses": "^0.2.0",
"@material-ui/core": "^4.9.3",
"@material-ui/icons": "^4.9.1",
"clsx": "^1.0.4",
Expand All @@ -50,7 +53,9 @@
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "^3.4.0",
"rimraf": "^3.0.2"
"rimraf": "^3.0.2",
"tap": "^14.10.5",
"tape-promise": "^4.0.0"
},
"publishConfig": {
"access": "public"
Expand Down
Loading

0 comments on commit 0bf7eab

Please sign in to comment.