Skip to content

Commit

Permalink
feat(wallet-vat,autoswap-vat): Create wallet & autoswap backend
Browse files Browse the repository at this point in the history
  • Loading branch information
jfparadis committed Nov 1, 2019
1 parent 6317d24 commit 207f884
Show file tree
Hide file tree
Showing 10 changed files with 695 additions and 44 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ require (
github.com/tendermint/tendermint v0.32.6
github.com/tendermint/tm-db v0.2.0
golang.org/x/sys v0.0.0-20190329044733-9eb1bfa1ce65 // indirect
google.golang.org/appengine v1.4.0 // indirect
google.golang.org/genproto v0.0.0-20190327125643-d831d65fe17d // indirect
)
115 changes: 82 additions & 33 deletions lib/ag-solo/init-autoswap.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,91 @@
import harden from '@agoric/harden';
import { makeMint } from '@agoric/ertp/core/mint';
import { upload } from './upload-contract';

const CONTRACT_NAME = 'zoe:autoswap'

// Usage:
// ag-solo bundle -e init-autoswap zoe:autoswap=../node_modules/@agoric/ertp/core/zoe/contracts/autoswap.js

export default async ({ home, bundle }) => {
// Install all the bundle entries that have a TARGET:NAME.
// TARGET may be 'zoe' or 'contractHost' for example.
const keyNames = Object.keys(bundle).sort().reduce((prior, key) => {
const match = key.match(/^[^:]+:(.*)/);
if (match) {
prior.push([key, match[1]]);
}
return prior;
}, []);
await upload(home, bundle, keyNames.map(([k, n]) => k));

// Register the installations.
const nameIds = {};
let autoswapKey;
await Promise.all(keyNames.map(([k, n]) =>
n === 'autoswap' ? autoswapKey = k : home~.uploads~.get(k).then(u => home~.registrar~.register(n, u))
.then(id => nameIds[n] = id)));

// TODO: This is just a sketch of how we might convert home.moolaMint into
// funds for the autoswap instance.

// Instantiate autoswap with some fresh moola and register the instance.
if (autoswapKey) {
const installHandle = await home~.uploads~.get(autoswapKey);
const options = {
assays: await Promise.all([home~.moolaMint~.getAssay()]),
purses: await Promise.all([home~.moolaMint~.mint(100000)]),
};
const instance = home~.zoe~.makeInstance(installHandle, harden(options));
nameIds['autoswap'] = await home~.registrar~.register('autoswap', instance);

console.log('*** AUTOSWAP');

// AUTOSWAP INSTALL

// 1. Load & install the autoswap contract.
await upload(home, bundle, [ CONTRACT_NAME ]);

// 2. Get the autoswap contract installation.
const installationHandle = await home~.uploads~.get(CONTRACT_NAME);

// 3. Store the contract installation in the registry.
const installationId = await home~.registrar~.register(CONTRACT_NAME, installationHandle);

console.log('- Autoswap intallation', CONTRACT_NAME, '=>', installationId);

// AUTOSWAP INSTANCE

// 1. Assays
const assays = await Promise.all([
home~.moolaMint~.getAssay(),
home~.simoleanMint~.getAssay(),
]);

// 2. Contract instrance.
try {
await home~.zoe~.makeInstance(installationHandle, { assays });
} catch(e) {}
const { instance, instanceHandle, terms } = await home~.zoe~.makeInstance(installationHandle, { assays });

// 3. Offer rules
const units = await Promise.all([
terms~.assays~.[0]~.makeUnits(10000),
terms~.assays~.[1]~.makeUnits(10000),
terms~.assays~.[2]~.makeUnits(0),
]);

const offerRules = harden({
payoutRules: [
{
kind: 'offerExactly',
units: units[0],
},
{
kind: 'offerExactly',
units: units[1],
},
{
kind: 'wantAtLeast',
units: units[2],
},
],
exitRule: {
kind: 'onDemand',
},
});

// 4. Payments (from mint, not from purse)

const faucets = await Promise.all([
home~.moolaMint~.mint(units[0]),
home~.simoleanMint~.mint(units[1]),
]);

const payments = await Promise.all([
faucets[0]~.withdrawAll(),
faucets[1]~.withdrawAll(),
]);

// 5. Liquidities.
const { escrowReceipt } = await home~.zoe~.escrow(offerRules, payments);
const liquidityOk = await instance~.addLiquidity(escrowReceipt);
console.log(liquidityOk);

if (liquidityOk) {
// Only store if the contract instance has liquidities.
const instanceId = await home~.registrar~.register(CONTRACT_NAME, instanceHandle);
console.log('- Autoswap instance', CONTRACT_NAME, '=>', instanceId);
}

// Output the record from contract IDs to registered names to stdout.
console.log(JSON.stringify(nameIds, undefined, 2));
};
}
28 changes: 26 additions & 2 deletions lib/ag-solo/vats/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ export default function setup(syscall, state, helpers) {
async function createPrivateBundle(vats, exposeMint) {
return harden({
uploads: await E(vats.uploads).getUploads(),
moolaMint: await E(vats.moola).getMint(),
moolaMint: await E(vats.mints).getMint('moola'),
simoleanMint: await E(vats.mints).getMint('simolean'),
wallet: await E(vats.wallet).getWallet(),
});
}

Expand All @@ -64,15 +66,19 @@ export default function setup(syscall, state, helpers) {
const registrar = await E(vats.registrar).getSharedRegistrar();
const chainTimerService = await E(vats.timer).createTimerService();
const pixelBundle = await E(vats.pixel).createPixelBundle(nickname);
const moola = await E(vats.moola).getSomeMoola(nickname, jackpot);
const moola = await E(vats.mints).getNewPurse('moola', 'Moola purse');
const simolean = await E(vats.mints).getNewPurse('simolean', 'Simolean purse');
const exchange = await E(vats.exchange).getExchange();
const zoe = await E(vats.zoe).getZoe();
return harden({
...pixelBundle,
chainTimerService,
sharingService,
moola,
simolean,
contractHost,
registrar,
exchange,
zoe,
});
},
Expand Down Expand Up @@ -209,11 +215,29 @@ export default function setup(syscall, state, helpers) {
await E(vats.pixel).startup(host);
await E(vats.timer).registerTimerDevice(devices.timer);
const bundle = await makeBundler(host, vats).createDemoBundle('localuser');
// fixme
await E(vats.exchange).startup(host, bundle.zoe, bundle.registrar);
await E(vats.wallet).startup(host, bundle.zoe, bundle.registrar);

const wallet = await E(vats.wallet).getWallet();

const moola = await E(vats.mints).getNewPurse('moola', 'Marketing');
const simolean = await E(vats.mints).getNewPurse('simolean', 'Operating Account');
await E(wallet).addPurse(moola);
await E(wallet).addPurse(simolean);

await setupCommandDevice(vats, devices, { client: true });
// fixme
await E(vats.http).registerCommandHandler(vats.exchange);
await E(vats.http).registerCommandHandler(vats.wallet);

await E(vats.http).setPresences(
bundle,
await createPrivateBundle(vats, true),
);

await E(vats.wallet).setCommandDevice(devices.command);
await E(vats.wallet).setPresences();
} else {
throw new Error(`ROLES was not recognized: ${ROLES}`);
}
Expand Down
120 changes: 120 additions & 0 deletions lib/ag-solo/vats/lib-exchange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import harden from '@agoric/harden';

function checkOrder(a0, a1, b0, b1) {
if (a0 === b0 && a1 === b1) {
return true;
}

if (a0 === b1 && a1 === b0) {
return false;
}

throw new TypeError('Canot resove asset ordering');
}

export async function makeExchange(E, log, host, zoe, registrar) {
// === API

async function getPrice(instanceId, extent0, assayId0, assayId1) {
const instanceHandle = await E(registrar).get(instanceId);

// Find the assays in the registrar
const registrarAssays = await Promise.all([
E(registrar).get(assayId0),
E(registrar).get(assayId1),
]);

// Get the assays in the contract.
// Get the contract instance.
const {
terms: { assays: contractAssays },
instance,
} = await E(zoe).getInstance(instanceHandle);

// Check whether we sell on contract assay 0 or 1.
const normal = checkOrder(
registrarAssays[0],
registrarAssays[1],
contractAssays[0],
contractAssays[1],
);

// Units of the input amount.
const unit0 = await E(registrarAssays[0]).makeUnits(extent0);

// Order the units accordingly.
const units = [
normal ? unit0 : undefined,
normal ? undefined : unit0,
undefined,
];

// Extract the price (multi steps for debugging).
const unit1 = await E(instance).getPrice(units);
const { extent } = unit1;
return extent;
}

async function getOfferRules(instanceId, extent, assayId0, assayId1) {
const instanceHandle = await E(registrar).get(instanceId);

// Find the assays by id in the registrar.
const registrarAssays = await Promise.all([
E(registrar).get(assayId0),
E(registrar).get(assayId1),
]);

// Get the assays in the contract.
const {
terms: { assays: contractAssays },
} = await E(zoe).getInstance(instanceHandle);

// Check whether we sell on contract assay 0 or 1.
const normal = checkOrder(
registrarAssays[0],
registrarAssays[1],
contractAssays[0],
contractAssays[1],
);

// Contrust the rules for serialization (no instance).
// This rule is the payment
const rule0 = {
kind: 'offerExactly',
units: { assayId: assayId0, extent },
};
// This rule is the payout
const rule1 = {
kind: 'wantAtLeast',
units: { assayId: assayId1 },
};

// Order the rules accordingly.
const offerRules = harden({
payoutRules: [
normal ? rule0 : rule1,
normal ? rule1 : rule0,
{
kind: 'wantAtLeast',
units: {},
},
],
exitRule: {
kind: 'onDemand',
},
});

return offerRules;
}

const autoswap = harden({
userFacet: {
getPrice,
getOfferRules,
},
adminFacet: {},
readFacet: {},
});

return autoswap;
}
Loading

0 comments on commit 207f884

Please sign in to comment.