diff --git a/main/glossary/index.md b/main/glossary/index.md
index 946922bb9..b8be06b4d 100644
--- a/main/glossary/index.md
+++ b/main/glossary/index.md
@@ -14,13 +14,11 @@ A short form of [agoric-3-proposals](https://github.com/Agoric/agoric-3-proposal
A command line interface for initializing, deploying, and starting Agoric projects, as well as installing dependencies. See the [Agoric CLI documentation](/guides/agoric-cli/) for more information.
-## AllegedName
+## Alleged
-Human-readable name of a type of assets. The alleged name should
-not be trusted as an accurate depiction, since it is provided by
-the maker of the mint and could be deceptive, but is useful for debugging and double-checking.
+
-The AllegedName must be a string.
+See [DebugName](#debugname).
## Allocation
@@ -210,6 +208,20 @@ An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`
creator can use. It is usually used in contracts where the creator immediately
sells something (auctions, swaps, etc.).
+## DebugName
+
+A label for debugging / diagnostic purposes. aka Alleged name.
+Since debug names may be misleading,
+**no code should rely on an Alleged / DebugName for correctness.**
+
+See:
+
+- [Exo tags](/guides/zoe/contract-details#tag-naming-kinds-of-objects),
+ which are used as debug names.
+- [ERTP](/guides/ertp/) where Brand objects, not string names,
+ are used to reliably identify digital assets.
+- [Remotable in @endo/pass-style](https://endojs.github.io/endo/functions/_endo_pass_style.Remotable.html), where labels are bound to objects.
+
## Deposit Facet
A [facet](#facet) of a [purse](#purse). Anyone with a reference to its deposit facet object can add
diff --git a/main/guides/ertp/assets/alice-bob-ticket.png b/main/guides/ertp/assets/alice-bob-ticket.png
new file mode 100644
index 000000000..8fbf1aaa3
Binary files /dev/null and b/main/guides/ertp/assets/alice-bob-ticket.png differ
diff --git a/main/guides/ertp/assets/ertp-interfaces-1.mmd b/main/guides/ertp/assets/ertp-interfaces-1.mmd
index 2ffcdbcd2..466e61f38 100644
--- a/main/guides/ertp/assets/ertp-interfaces-1.mmd
+++ b/main/guides/ertp/assets/ertp-interfaces-1.mmd
@@ -13,6 +13,12 @@ classDiagram
}
ertp --> IssuerKit : makeIssuerKit
+ class IssuerKit {
+ mint: Mint
+ issuer: Issuer
+ brand: Brand
+ }
+
class Mint {
getIssuer()
}
diff --git a/main/guides/ertp/assets/ertp-interfaces-1.svg b/main/guides/ertp/assets/ertp-interfaces-1.svg
index 2c916b5df..7c7f4c4a8 100644
--- a/main/guides/ertp/assets/ertp-interfaces-1.svg
+++ b/main/guides/ertp/assets/ertp-interfaces-1.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/main/guides/ertp/index.md b/main/guides/ertp/index.md
index b53abf4a5..db2607f82 100644
--- a/main/guides/ertp/index.md
+++ b/main/guides/ertp/index.md
@@ -1,7 +1,134 @@
# ERTP Overview
-ERTP (_Electronic Rights Transfer Protocol_)
-is Agoric's token standard for transferring tokens and other digital assets in
+ERTP (_Electronic Rights Transfer Protocol_) is Agoric's digital asset standard.
+
+ERTP is a uniform way of transferring tokens and other digital assets in JavaScript. All kinds of digital assets can be easily created, but importantly, they can be transferred in exactly the same ways, with exactly the same security properties.
+
+For example, let's suppose Alice wants to buy a concert ticket from Bob for 10 bucks.
+
+::: tip Watch: erights -- credibly transferable ownership (Oct 2024)
+_25 minutes on ERTP at a conceptual level._
+
+
+[](https://www.youtube.com/watch?v=O8Bx_Abj9Qc&list=PLzDw4TTug5O1A-tkPJe4HVq0VBPcNOMHm)
+
+:::
+
+## Issuer, Brand, and Mint
+
+We start by using `makeIssuerKit` to make a `Mint`, `Brand`, and `Issuer` for **Bucks**.
+
+<<< @/../snippets/ertp/guide/test-readme.js#importErtp
+<<< @/../snippets/ertp/guide/test-readme.js#declareShared
+<<< @/../snippets/ertp/guide/test-readme.js#makeBucks
+
+The `bucks.brand` and `bucks.issuer` don't let anyone mint new assets, so sharing
+them widely is normal. We must be careful to guard the`bucksMint`, so we keep it separate.
+
+::: tip see also ZCFMint (TODO)
+
+...
+
+:::
+
+## Amount: Asset Descriptions
+
+Next we combine the Bucks brand with a value to make an `Amount`:
+
+<<< @/../snippets/ertp/guide/test-readme.js#bucksAmount
+
+An Amount is a value labeled with a brand.
+Amounts are descriptions of digital assets,
+answering the questions "how much" and "of what kind".
+
+Amounts have no economic scarcity or intrinsic value.
+
+:::tip More on Asset Use versus Mention
+_See also [The Settlers of Blockchain](https://agoric.com/blog/technology/the-settlers-of-blockchain) by Chris Hibbert, Jun 2021_
+:::
+
+## Minting Payments
+
+Next we use the mint to make a `Payment` of 100 bucks for Alice:
+
+<<< @/../snippets/ertp/guide/test-readme.js#bucksPayment100
+
+Likewise, we make a **Tickets** issuer kit make payments of 10 **Tickets** and 100 **Bucks**
+for Bob.
+
+<<< @/../snippets/ertp/guide/test-readme.js#amountMathProps
+<<< @/../snippets/ertp/guide/test-readme.js#bobPayments
+
+Where Amounts only describe assets, Payments actually convey digital assets/rights.
+Sending Payments must be done very carefully.
+
+## Making Purses
+
+Alice is acting as a buyer.
+She can make her own empty purses using the shared issuers, which she relies on.
+She depsits some **Bucks** that she is given into her Bucks purse.
+
+<<< @/../snippets/ertp/guide/test-readme.js#aliceBuyer1
+
+Purses also hold digital assets/rights.
+**Purses are normally not sent betwen parties.**
+
+## Credible Asset Transfer
+
+To buy a ticket, she withdraws a payment of 10 bucks and make a `buy` request
+to some vendor she was given.
+
+<<< @/../snippets/ertp/guide/test-readme.js#aliceBuyer2
+
+The seller has likewise created purses for **Bucks** and **Tickets** and made deposits.
+When they get a `buy` request, the argument may be anything, so it's called `allegedPayment`.
+But once they deposit it into their Bucks purse, they know it was
+a valid Bucks payment, and they know the amount.
+Provided the amount is sufficient, they withdraw a ticket (payment) and return it.
+
+<<< @/../snippets/ertp/guide/test-readme.js#bobSeller
+
+Now our buyer has an `allegedTicket`.
+Once she deposits it in her **Tickets** purse, she knows it was
+a valid payment and she knows its value. She can check that she
+got at least 1 ticket.
+
+<<< @/../snippets/ertp/guide/test-readme.js#aliceBuyer3
+
+To put it all together:
+
+<<< @/../snippets/ertp/guide/test-readme.js#aliceBuysFromBob
+
+## Non-Fungible and Semi-Fungible Assets
+
+::: tip: TODO: Non-Fungible and Semi-Fungible Assets
+
+...
+
+:::
+
+## ERTP Concepts Overview
+
+Each digital asset has Mint, Issuer, and Brand facets:
+
+{ width=200 height=200 }
+
+Use brands to make amounts.
+
+Use a Mint to create Payments. Use an Issuer to make Purses.
+Deposit payments into purses and withdraw them back out.
+
+
+
+Fungible and non-fungible kinds of assets are handled uniformly.
+
+
+
+# Obsolete material
+
+_aside from TODOs above_
+
+token standard for transferring tokens and other digital assets in
JavaScript. Using the [ERTP API](/reference/ertp-api/),
you can easily create and use digital assets, all of which are
transferred exactly the same way and with exactly the same security properties.
@@ -12,8 +139,6 @@ object, it can call methods on that object. If it doesn't have a
reference, it can't. For more on object capabilities, see
[Chip Morningstar's post](http://habitatchronicles.com/2017/05/what-are-capabilities/).
-## ERTP Concepts Overview
-
### Asset
There are three kinds of assets:
diff --git a/snippets/ertp/guide/test-readme.js b/snippets/ertp/guide/test-readme.js
index ae68e04b1..19c088fc2 100644
--- a/snippets/ertp/guide/test-readme.js
+++ b/snippets/ertp/guide/test-readme.js
@@ -1,5 +1,6 @@
/* eslint-disable import/order -- https://github.com/endojs/endo/issues/1235 */
import { test } from '../../prepare-test-env-ava.js';
+// @ts-check
import { E } from '@endo/eventual-send';
@@ -8,7 +9,9 @@ import { E } from '@endo/eventual-send';
// eslint-disable-next-line import/no-extraneous-dependencies
import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js';
-import { AmountMath, makeIssuerKit, AssetKind } from '@agoric/ertp';
+// #region importErtp
+import { makeIssuerKit, AmountMath, AssetKind } from '@agoric/ertp';
+// #endregion importErtp
test('ertp guide readme', async t => {
// #region makeIssuerKit
@@ -100,3 +103,115 @@ test('ertp guide readme', async t => {
t.truthy(allLive.every(a => a));
});
+
+test('MarkM 2024-10 talk', t => {
+ /** @type {Record} */
+
+ // #region amountMathProps
+ const { make, isGTE } = AmountMath;
+ // #endregion amountMathProps
+
+ // #region declareShared
+ const shared = {};
+ // #endregion declareShared
+
+ // #region aliceBuyer1
+ /** @param {{ bucks: Payment, vendor: any }} some */
+ const makeBuyer = some => {
+ const { bucks, tickets } = shared;
+ const my = {
+ bucks: bucks.issuer.makeEmptyPurse(),
+ tickets: tickets.issuer.makeEmptyPurse(),
+ };
+ my.bucks.deposit(some.bucks);
+ // #endregion aliceBuyer1
+
+ // #region aliceBuyer2
+ return harden({
+ buyTicket() {
+ const pmt = my.bucks.withdraw(make(bucks.brand, 10n));
+ const allegedTicket = some.vendor.buy(pmt);
+ // #endregion aliceBuyer2
+ // #region aliceBuyer3
+ const got = my.tickets.deposit(allegedTicket);
+ t.log('Alice got', got);
+ isGTE(got, make(tickets.brand, 1n)) || assert.fail();
+ return got;
+ },
+ getBalances: () => ({
+ bucks: my.bucks.getCurrentAmount(),
+ tickets: my.tickets.getCurrentAmount(),
+ }),
+ });
+ };
+ // #endregion aliceBuyer3
+
+ // #region bobSeller
+ /** @param {{ bucks: Payment, tickets: Payment}} some */
+ const makeSeller = some => {
+ const { bucks, tickets } = shared;
+ const my = {
+ bucks: bucks.issuer.makeEmptyPurse(),
+ tickets: tickets.issuer.makeEmptyPurse(),
+ };
+ my.bucks.deposit(some.bucks);
+ my.tickets.deposit(some.tickets);
+
+ return harden({
+ /** @param {Payment} allegedPayment */
+ buy(allegedPayment) {
+ const amt = my.bucks.deposit(allegedPayment);
+ isGTE(amt, make(bucks.brand, 10n)) || assert.fail();
+ t.log('Bob got', amt);
+ return my.tickets.withdraw(make(tickets.brand, 1n));
+ },
+ getBalances: () => ({
+ bucks: my.bucks.getCurrentAmount(),
+ tickets: my.tickets.getCurrentAmount(),
+ }),
+ });
+ };
+ // #endregion bobSeller
+
+ // #region makeBucks
+ const bucksKit = makeIssuerKit('Bucks');
+ const { mint: bucksMint, ...bucks } = bucksKit;
+ Object.assign(shared, { bucks });
+ // #endregion makeBucks
+
+ // #region bucksAmount
+ const bucks100 = AmountMath.make(bucks.brand, 100n);
+ // #endregion bucksAmount
+
+ // #region bucksPayment100
+ const paymentA = bucksMint.mintPayment(bucks100);
+ // #endregion bucksPayment100
+
+ // #region bobPayments
+ const { mint: ticketsMint, ...tickets } = makeIssuerKit('Tickets');
+ Object.assign(shared, { tickets });
+
+ const paymentsB = {
+ bucks: bucksMint.mintPayment(make(bucks.brand, 200n)),
+ tickets: ticketsMint.mintPayment(make(tickets.brand, 50n)),
+ };
+ // #endregion bobPayments
+
+ // #region aliceBuysFromBob
+ const bob = makeSeller(paymentsB);
+ const alice = makeBuyer({ bucks: paymentA, vendor: bob });
+
+ const howMuch = (bv, tv) => ({
+ bucks: make(bucks.brand, bv),
+ tickets: make(tickets.brand, tv),
+ });
+
+ t.deepEqual(alice.getBalances(), howMuch(100n, 0n));
+ t.deepEqual(bob.getBalances(), howMuch(200n, 50n));
+
+ alice.buyTicket();
+
+ t.deepEqual(alice.getBalances(), howMuch(90n, 1n));
+ t.deepEqual(bob.getBalances(), howMuch(210n, 49n));
+ // #endregion aliceBuysFromBob
+});