Skip to content

Commit

Permalink
feat: add 3 exercises for agoric-exercises
Browse files Browse the repository at this point in the history
  • Loading branch information
LuqiPan committed Feb 6, 2024
1 parent a252bf0 commit f068996
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 40 deletions.
57 changes: 53 additions & 4 deletions contract/src/agoric-basics-contract.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,59 @@
// @ts-check
import { AmountMath, AmountShape, AssetKind } from '@agoric/ertp';
import { Far } from '@endo/far';
import '@agoric/zoe/exported.js';
import { M } from '@endo/patterns';
import { atomicRearrange } from '@agoric/zoe/src/contractSupport/atomicTransfer.js';

const greet = who => `Hello, ${who}!`;
const { Fail, quote: q } = assert;

export const start = () => {
return {
publicFacet: Far('Hello', { greet }),
/**
* @param {ZCF<{joinPrice: Amount}>} zcf
*/
export const start = async zcf => {
const gameSeat = zcf.makeEmptySeatKit().zcfSeat;
// TODO: convert to COPY_BAG
const ticketMint = await zcf.makeZCFMint('Ticket', AssetKind.NAT);

const joinShape = harden({
give: { Price: AmountShape },
want: { Tickets: AmountShape },
exit: M.any(),
});

/** @param {ZCFSeat} playerSeat */
const joinHandler = playerSeat => {
const { give, want } = playerSeat.getProposal();

// TODO: update the checks here once AssetKind is converted to COPY_BAG
AmountMath.isGTE(
AmountMath.make(ticketMint.getIssuerRecord().brand, 1n),
want.Tickets,
) || Fail`${q(want.Tickets)} exceeds 1n ticket`;

// mintGains mints all amounts in `want`
// For more, see reference:
// https://docs.agoric.com/reference/zoe-api/zcfmint.html#azcfmint-mintgains-gains-zcfseat
const tmp = ticketMint.mintGains(want);
// atomicRearrange rearrange the assets between seats
atomicRearrange(
zcf,
harden([
[playerSeat, gameSeat, give],
// TODO: add another TransferPart below to pass the exercise 3 test
[tmp, playerSeat, want],
]),
);

playerSeat.exit(true);
return 'welcome to the game';
};

const publicFacet = Far('API', {
makeJoinInvitation: () =>
zcf.makeInvitation(joinHandler, 'join', undefined, joinShape),
});

return { publicFacet };
};
harden(start);
104 changes: 96 additions & 8 deletions contract/test/test-agoric-basics-contract.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,101 @@
/**
* @file Tests for agoric-basics-contract.js
*/

// @ts-check
import '@endo/init';
import { E } from '@endo/far';

// eslint-disable-next-line import/no-unresolved -- https://github.com/avajs/ava/issues/2951
import test from 'ava';
import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js';

import bundleSource from '@endo/bundle-source';
import { makeZoeKitForTest } from '@agoric/zoe/tools/setup-zoe.js';
import { E, passStyleOf } from '@endo/far';
import { createRequire } from 'module';
import { AmountMath, makeIssuerKit } from '@agoric/ertp';

test('exercise 1: bundleSource bundles the contract for use with zoe', async t => {
const myRequire = createRequire(import.meta.url);
const contractPath = myRequire.resolve(`../src/agoric-basics-contract.js`);

// bundleSource() bundles contract and all of its modules into a single artifact
// and is the first thing you need to do in order to deploy a contract
// For more, see reference: https://docs.agoric.com/guides/zoe/#bundling-a-contract

// TODO: initialize the const `bundle` using bundleSource() to pass the test below
// Tips 1: you can import bundleSource() from @endo/bundle-source
// Tips 2: don't forget to use `await` to get the fulfilled value
const bundle = await bundleSource(contractPath);

t.is(bundle.moduleFormat, 'endoZipBase64');
t.true(bundle.endoZipBase64.length > 10_000);
});

test('exercise 2: start zoe instance', async t => {
const myRequire = createRequire(import.meta.url);
const contractPath = myRequire.resolve(`../src/agoric-basics-contract.js`);
const bundle = await bundleSource(contractPath);
const { zoeService: zoe } = makeZoeKitForTest();
const installation = await E(zoe).install(bundle);
t.is(passStyleOf(installation), 'remotable');

const playMoney = makeIssuerKit('PlayMoney');
const playMoneyIssuer = { Price: playMoney.issuer };
const joinPrice = AmountMath.make(playMoney.brand, 5n);

// startInstance creates an instance of the installed smart contract, with terms speicific to the instance
// similar to how a JavaScript object is an instance of its class
const { instance } = await E(zoe).startInstance(
installation,
playMoneyIssuer,
{
// TODO: initialize the instance with the expected joinPrice to pass the test below
joinPrice: joinPrice,

Check failure on line 52 in contract/test/test-agoric-basics-contract.js

View workflow job for this annotation

GitHub Actions / all

Expected property shorthand
},
);
const terms = await E(zoe).getTerms(instance);

t.is(terms.joinPrice, joinPrice);
});

test('exercise 3: atomicRearrange', async t => {
const myRequire = createRequire(import.meta.url);
const contractPath = myRequire.resolve(`../src/agoric-basics-contract.js`);
const bundle = await bundleSource(contractPath);
const { zoeService: zoe } = makeZoeKitForTest();
const installation = await E(zoe).install(bundle);

const playMoney = makeIssuerKit('PlayMoney');
const playMoneyIssuer = { Price: playMoney.issuer };

const { instance } = await E(zoe).startInstance(
installation,
playMoneyIssuer,
{
joinPrice: AmountMath.make(playMoney.brand, 5n),
},
);
const publicFacet = await E(zoe).getPublicFacet(instance);
const terms = await E(zoe).getTerms(instance);
const alicePurse = playMoney.issuer.makeEmptyPurse();
const amountOfMoney = AmountMath.make(playMoney.brand, 5n);
const moneyPayment = playMoney.mint.mintPayment(amountOfMoney);
alicePurse.deposit(moneyPayment);

const { issuers, brands, joinPrice } = terms;
const proposal = {
give: { Price: joinPrice },
want: { Tickets: AmountMath.make(brands.Ticket, 1n) },
};

const Price = await E(alicePurse).withdraw(joinPrice);

import { start } from '../src/agoric-basics-contract.js';
const toJoin = E(publicFacet).makeJoinInvitation();

test('contract greets by name', async t => {
const { publicFacet } = start();
const actual = await E(publicFacet).greet('Bob');
t.is(actual, 'Hello, Bob!');
const seat = E(zoe).offer(toJoin, proposal, { Price });
const tickets = await E(seat).getPayout('Tickets');
const actual = await E(issuers.Ticket).getAmountOf(tickets);
// How do we complete the trade, i.e deduct the amount from alice's purse and mint her a ticket?
// Hint: use atomicRearrange()
// TODO: update atomicRearrange in agoric-basics-contract.js
t.deepEqual(actual, proposal.want.Tickets);
});
28 changes: 0 additions & 28 deletions contract/test/test-bundle-source.js

This file was deleted.

0 comments on commit f068996

Please sign in to comment.