Skip to content

Instantly share code, notes, and snippets.

@dckc
Last active December 2, 2022 15:39
Show Gist options
  • Save dckc/0988dfe516c24a1e925a1d68b3a69217 to your computer and use it in GitHub Desktop.
Save dckc/0988dfe516c24a1e925a1d68b3a69217 to your computer and use it in GitHub Desktop.

example run:

$ yarn test snippets/test-sell1.js 
yarn run v1.22.5
$ ava snippets/test-sell1.js

  ✔ sell 1 thing (211ms)
    ℹ Alice offers to sell {
        give: {
          Item: {
            brand: Object @Alleged: Thing brand {},
            value: Array [ … ],
          },
        },
        want: {
          Price: {
            brand: Object @Alleged: Moola brand {},
            value: 100n,
          },
        },
      }
    ℹ result from offer to sell: ready to sell
    ℹ bob proposes {
        give: {
          Price: {
            brand: Object @Alleged: Moola brand {},
            value: 100n,
          },
        },
        want: {
          Item: {
            brand: Object @Alleged: Thing brand {},
            value: Array [ … ],
          },
        },
      }
    ℹ alice received: {
        brand: Object @Alleged: Moola brand {},
        value: 100n,
      }
    ℹ bob received {
        brand: Object @Alleged: Thing brand {},
        value: [
          'Thing 1',
        ],
      } {
        brand: Object @Alleged: Moola brand {},
        value: 0n,
      }
  ─

  1 test passed
Done in 1.45s.
// @ts-check
import { Far } from '@endo/marshal'; // TODO: @endo/far
/** @param {ZCF} zcf */
export const start = zcf => {
let sellerSeat;
/** @type {OfferHandler} */
const sellHandler = seat => {
if (sellerSeat) {
throw Error('already selling');
}
sellerSeat = seat;
// WARNING! proposal needs validation
return 'ready to sell';
};
const buyHandler = seat => {
if (!sellerSeat) {
throw Error('not yet selling');
}
const { give, want } = seat.getProposal();
// swap item for price
sellerSeat.incrementBy(seat.decrementBy({ Price: give.Price }));
seat.incrementBy(sellerSeat.decrementBy({ Item: want.Item }));
zcf.reallocate(seat, sellerSeat);
seat.exit();
sellerSeat.exit();
return 'sold. nice doing business with you';
};
const creatorFacet = Far('creatorFacet', {
makeSellInvitation: () => zcf.makeInvitation(sellHandler, 'sell item'),
});
const publicFacet = Far('pub', {
makeBuyInvitation: () => zcf.makeInvitation(buyHandler, 'buy'),
});
return { publicFacet, creatorFacet };
};
// @ts-check
/* eslint-disable import/order -- https://github.com/endojs/endo/issues/1235 */
import { test } from './prepare-test-env-ava.js';
import url from 'url';
import { resolve as importMetaResolve } from 'import-meta-resolve';
import { E } from '@endo/eventual-send';
import { makeZoeKit } from '@agoric/zoe';
import { makeIssuerKit, AmountMath, AssetKind } from '@agoric/ertp';
import { makePromiseKit } from '@endo/promise-kit';
// #region importBundleSource
import bundleSource from '@endo/bundle-source';
// #endregion importBundleSource
import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin.js';
test.before(async t => {
const { zoeService } = makeZoeKit(makeFakeVatAdmin().admin);
// #region bundle
const sell1Url = await importMetaResolve('./sell1.js', import.meta.url);
const sell1Path = url.fileURLToPath(sell1Url);
const sell1Bundle = await bundleSource(sell1Path);
// #endregion bundle
const installation = await E(zoeService).install(sell1Bundle);
t.context = { zoeService, installation };
});
test('sell 1 thing', async t => {
/** @type {{ zoeService: ZoeService }} */
const { zoeService: zoe, installation } = t.context;
// Both Alice and Bob know about the issuers and brands for moola, things
// but the mints are closely held.
const common = () => {
const { mint: moolaMint, ...moolaKit } = makeIssuerKit('Moola');
const { mint: thingMint, ...thingKit } = makeIssuerKit(
'Thing',
AssetKind.SET,
);
const moolaAmt = val => AmountMath.make(moolaKit.brand, val);
const thingAmt = val => AmountMath.make(thingKit.brand, val);
const thing1 = thingMint.mintPayment(thingAmt(harden(['Thing 1'])));
const moola200 = moolaMint.mintPayment(moolaAmt(200n));
const share = makePromiseKit();
const scenario = harden({ item: thing1, payment: moola200, share });
return { moolaKit, thingKit, moolaAmt, thingAmt, scenario };
};
const { moolaKit, thingKit, moolaAmt, thingAmt, scenario } = common();
// Alice starts the contract and offers to sell thing1 for 100 moola.
const actAsAlice = async (thing1, shareInstance) => {
const thing1Amt = await E(thingKit.issuer).getAmountOf(thing1);
const proposalToSell = harden({
give: { Item: thing1Amt },
want: { Price: moolaAmt(100n) },
});
const issuers = {
Item: thingKit.issuer,
Price: moolaKit.issuer,
};
const terms = { Item: thing1Amt, Price: moolaAmt(100n) };
const { instance, creatorFacet } = await E(zoe).startInstance(
installation,
issuers,
terms,
);
const invitationToSell = await E(creatorFacet).makeSellInvitation();
t.log('Alice offers to sell', proposalToSell);
const seat = await E(zoe).offer(
invitationToSell,
proposalToSell,
harden({ Item: thing1 }),
);
const result = await E(seat).getOfferResult();
t.log('result from offer to sell:', result);
shareInstance(instance); // with prospective buyers
const proceeds = await E(seat).getPayout('Price');
const procAmt = await E(moolaKit.issuer).getAmountOf(proceeds);
t.log('alice received:', procAmt);
t.deepEqual(procAmt, proposalToSell.want.Price);
};
// Bob buys thing1
const actAsBob = async (funds, instanceP) => {
const purse = moolaKit.issuer.makeEmptyPurse();
purse.deposit(funds);
// Bob checks the terms of the contract
const instance = await instanceP;
const { Price, Item } = await E(zoe).getTerms(instance);
t.deepEqual(Price, moolaAmt(100n));
t.deepEqual(Item, thingAmt(harden(['Thing 1'])));
const proposal = harden({ give: { Price }, want: { Item } });
// exercise: try this proposal instead
// const proposal = harden({ give: { Price: moolaAmt(50n) }, want: { Item } });
// or this one
// const proposal = harden({
// give: { Price },
// want: { Item: thingAmt(harden(['Thing 2'])) },
// });
t.log('bob proposes', proposal);
const publicFacet = E(zoe).getPublicFacet(instance);
const buyInv = await E(publicFacet).makeBuyInvitation();
const seat = await E(zoe).offer(buyInv, proposal, {
Price: purse.withdraw(proposal.give.Price),
});
const property = await E(seat).getPayout('Item');
const refund = await E(seat).getPayout('Price');
const pAmt = await E(thingKit.issuer).getAmountOf(property);
const rAmt = await E(moolaKit.issuer).getAmountOf(refund);
t.log('bob received', pAmt, rAmt);
t.deepEqual(pAmt, Item);
t.deepEqual(rAmt, moolaAmt(0n));
};
await Promise.all([
actAsAlice(scenario.item, scenario.share.resolve),
actAsBob(scenario.payment, scenario.share.promise),
]);
});
@dckc
Copy link
Author

dckc commented Dec 2, 2022

I suggest ./api/deploy.js is not relevant. I would delete the entire api directory.

@cboydstun
Copy link

Sam and i tried that together but we started getting all sorts of weird errors about the cache because it expects an api directory. It's running now without the api directory and i won't run the api/deploy.js script until we need some external data - thanks.

Ag-solo running locally, contract deployed, and wallet connected. Unfortunately, my browser renders Agoric wallet: Unknown with all the JS intact from faucet-dapp - I've only stripped away styling and extra content.

Browser Console Errors:

(TypeError#1) [ses.umd.js:6540:24](http://localhost:3000/__parcel_source_root/node_modules/ses/dist/ses.umd.js)
    levelMethod ses.umd.js:6540
    tameConsole ses.umd.js:6827
TypeError#1: $debug is null [ses.umd.js:6500:29](http://localhost:3000/__parcel_source_root/node_modules/ses/dist/ses.umd.js)
    logError ses.umd.js:6500
    logSubErrors ses.umd.js:6443
    levelMethod ses.umd.js:6541
    tameConsole ses.umd.js:6827

No errors in any terminal. Please advise thanks. @dckc

@dckc
Copy link
Author

dckc commented Dec 2, 2022

I don't recall seeing $debug is null. I don't have any advice on that.

@dckc
Copy link
Author

dckc commented Dec 2, 2022

That stack trace doesn't seem to indicate where the problem is. Debugging with bundlers is at the edge of my working knowledge. If it were me, I'd hold off on react and work without a bundler until I got something working.

I'm not sure how to integrate the wallet connection component without a bundler, though.

I guess I tried snowpack for a while https://github.com/agoric-labs/gov-demo1/blob/main/package.json#L4

more recently I've been using esbuild https://github.com/agoric-labs/gov-demo1/blob/smart-wallet/package.json#L6

dunno if those would help, though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment