diff --git a/main/.vuepress/config.js b/main/.vuepress/config.js index d2a7e7fc3..d693ee2a8 100644 --- a/main/.vuepress/config.js +++ b/main/.vuepress/config.js @@ -58,7 +58,12 @@ module.exports = { children: [ '/ertp/guide/', '/ertp/guide/getting-started', - '/ertp/guide/assays', + '/ertp/guide/mint', + '/ertp/guide/assay', + '/ertp/guide/extent', + '/ertp/guide/units', + '/ertp/guide/label', + '/ertp/guide/unit-ops', '/ertp/guide/default-configuration', '/ertp/guide/contract-hosts' ] @@ -69,12 +74,12 @@ module.exports = { collapsable: false, sideBarDepth: 3, children: [ - '/ertp/api/', '/ertp/api/mint', - { - title: 'UnitOps', - path: '/ertp/api/unitOps' - } + '/ertp/api/assay', + '/ertp/api/purse', + '/ertp/api/payment', + '/ertp/api/extent-ops', + '/ertp/api/unit-ops' ] } ], diff --git a/main/ertp/api/README.md b/main/ertp/api/README.md index f5282f537..4e2e4e8f1 100644 --- a/main/ertp/api/README.md +++ b/main/ertp/api/README.md @@ -3,9 +3,8 @@ The ERTP API is divided into the following sections: - [Mint](/ertp/api/mint) - - [Assay](/ertp/api/mint.html#assay) - - [Purse](/ertp/api/mint.html#purse) - - [Payment](/ertp/api/mint.html#payment) - - [ExtentOps](/ertp/api/mint.html#extentops) - -- [UnitOps](/ertp/api/unitOps.html#unitops-api) +- [Assay](/ertp/api/assay) +- [Purse](/ertp/api/purse) +- [Payment](/ertp/api/payment) +- [ExtentOps](/ertp/api/extentops) +- [UnitOps](/ertp/api/unit-ops) diff --git a/main/ertp/api/assay.md b/main/ertp/api/assay.md new file mode 100644 index 000000000..e32c7e888 --- /dev/null +++ b/main/ertp/api/assay.md @@ -0,0 +1,230 @@ +# Assay + +An Assay represents the identity of an issuer. Holding an Assay provides the ability to create `units` and empty purses, but confers no rights. It is also the mechanism used to get exclusive access to a Purse or Payment that you already hold, or to burn some or all of the contained rights. + +## assay.getLabel() +- Returns: `{Label}` The label for the assay. + +Get the label for this Assay. Labels can be used to manually construct `units`. + +```js +import { makeMint } from '@agoric/ertp/core/mint'; +import config from 'customConfig.js'; + +// Initial mint +const happyTownBucks = makeMint('happyTownBucks'); +const assay = happyTownBucks.getAssay(); +const { allegedName } = assay.getLabel(); + +// Make a child mint using the initial mint's allegedName +const childMint = makeMint(allegedName, config); +``` + +## assay.getUnitOps() +- Returns: `{UnitOps}` - returns the unit operations for the Assay + +Get the `UnitOps` for this Assay. + +```js +const galleryPixel = makeMint('galleryPixel'); +const galleryPixelAssay = galleryPixel.getAssay(); +const galleryPixelUnitOps = galleryPixelAssay.getUnitOps(); +``` + +After getting the `UnitOps` of an `Assay`, `UnitOps` methods can be called to verify properties of the `units`. See the [UnitOps API](/api/unitOps) for all available methods. + +```js +function insist(asset, units) { + !assay.getUnitOps().isEmpty(units); + // no use rights present in units ${units}`; +} + +function insistAssetHasUnits(assay, asset, units) { + insist(assay.getUnitOps().includes(asset.getBalance(), units)); + // ERTP asset ${asset} does not include units ${units}`; +} + +function getPixelList(assay, units) { + return assay.getUnitOps().extent(units); +} +``` + +## assay.getExtentOps() +- Returns: `{ExtentOps}` - returns the extent operations for the Assay + +Get the `ExtentOps` for this Assay. + +```js +const exampleExtentOps = exampleAssay.getExtentOps(); +``` + +## assay.makeUnits(extent) +- `extent` `{Extent}` +- Returns: `{Units}` + +Make Units that contain the indicated extent. + +```js +import { setup } from '../setupBasicMints'; + +const { assays: originalAssays, mints, unitOps } = setup(); +const assays = originalAssays.slice(0, 2); + +// In this scenario, purses are created for two different assays. +// We provide Units, containing an extent, from the Moola and Simolean assays to create the appropriate purses. +const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(3)); +const aliceSimoleanPurse = mints[1].mint(assays[1].makeUnits(0)); +``` + +## assay.makeEmptyPurse(name) +- `name` `{String}` +- Returns: `{Purse}` + +Make an empty purse associated with this kind of right. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); + +// After creating an assay you can create an empty purse: +const targetPurse = assay.makeEmptyPurse(); + +// Returns 0 +targetPurse.getBalance(); +``` + +## assay.combine(paymentsArray, name) +- `paymentsArray` `{Array }` - A list of payments to combine into a new payment +- `name` `{String}` - Name to call this combination of payments +- Returns: `{Payment}` + +Combine multiple payments into one payment. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +// Create a payments array. Each element, or payment, has a value of 1. +const payments = []; +for (let i = 0; i < 100; i += 1) { + payments.push(purse.withdraw(1)); +} + +// Combine all the payments in the`payments` array +const combinedPayment = assay.combine(payments); + +// Returns 100 +combinedPayment.getBalance(); +``` + +## assay.split(payment, unitsArray) +- `payment` `{Payment}` +- `unitsArray` `{Array }` +- Returns: `{Array }` + +Split a single payment into multiple payments, according to the `units` and names passed in. + +```js +// Assume a mint has already been set up. +const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(40)); +const aliceMoolaPayment = aliceMoolaPurse.withdrawAll(); +const moola10 = assays[0].makeUnits(10); +const moola20 = assays[0].makeUnits(20); + +// The following divides the aliceMoolaPayment into three payments: +const aliceMoolaPayments = assays[0].split(aliceMoolaPayment, [ + moola10, + moola10, + moola20, +]); +// aliceMoolaPayments is now an array of three Payment objects, with balances of 10, 10, 20, respectively. +``` + +## assay.claimExactly(units, src, name) +- `units` `{Units}` +- `src` `{Payment}` +- `name` `{String}` - name of a new `Payment`, optional +- Returns: `{Payment}` + +Make a new `Payment` that has exclusive rights to all the contents of `src`. If `units` does not equal the balance of the `src` payment, throws error. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payment = await purse.withdraw(7); +const newPayment = await assay.claimExactly(7, payment); + +// .claimExactly() will throw an error because the the balance of wrongPayment does not equal the units +const wrongPayment = await purse.withdraw(7); +const wrongNewPayment = await assay.claimExactly(8, wrongPayment); +``` + +## assay.claimAll(src, name) +- `src` `{Payment}` +- `name` `{String}` - name of a new `Payment` +- Returns: `{Payment}` + +Make a new `Payment` that has exclusive rights to all the contents of `src`. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payment = await purse.withdraw(10); +const newPayment = await assay.claimAll(payment); + +// Returns 10 +newPayment.getBalance(); +``` + +## assay.burnExactly(units, src) +- `units` `{Units}` +- `src` `{Payment}` +- Returns: `{Units}` + +Burn all of the rights from `src`. If `units` does not equal the balance of the `src` payment, throw error. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payment = await purse.withdraw(10); + +// Throws error: +await assay.burnExactly(6, payment); + +// Successful burn: +await assay.burnExactly(10, payment); +``` + +## assay.burnAll(src) +- `src` `{Payment}` +- Returns: `{Units}` + +Burn all of the rights from `src`. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payment = await purse.withdraw(10); +await assay.burnAll(payment); +``` diff --git a/main/ertp/api/extent-ops.md b/main/ertp/api/extent-ops.md new file mode 100644 index 000000000..a85870b92 --- /dev/null +++ b/main/ertp/api/extent-ops.md @@ -0,0 +1,152 @@ +# ExtentOps + +All of the difference in how a unitOps behaves can be reduced to the behavior of the set operations on extents (think: arithmetic) such as `empty`, `with`, `without`, `includes`, etc. We extract this custom logic into an extentOps. ExtentOps are about extent arithmetic, whereas UnitOps are about Units, which are labeled extents. UnitOps use ExtentOps to do their extent arithmetic, and then label the results, making new Units. + +## extentOps.insistKind(allegedExtent) +- `allegedExtent` `{Extent}` +- Returns: `{Extent}` + +Check the kind of this extent and throw if it is not the expected kind. + +```js +const startPixel = { x: 0, y: 0 }; +const secondPixel = { x: 0, y: 1 }; +const thirdPixel = { x: 0, y: 2 }; +const pixelList = [startPixel, secondPixel, thirdPixel]; + +// Creates an array of pixels +const pixelExtentOps = makePixelExtentOps(); + +// Successful check +pixelExtentOps.insistKind(pixelList)); + +// Throws error because pixelExtentOps expects an array +pixelExtentOps.insistKind(startPixel); +``` + +## extentOps.empty() +- Returns: `{Extent}` + +Get the representation for empty. + +```js +const empty = exampleExtentOps.empty(); +``` + +## extentOps.isEmpty(extent) +- `extent` `{Extent}` +- Returns: `{boolean}` + +Is the extent empty? + +```js +const isExtentEmpty = exampleExtentOps.isEmpty(randomExtent); +``` + +## extentOps.includes(whole, part) +- `whole` `{Extent}` +- `part` `{Extent}` +- Returns: `{boolean}` + +Does the whole include the part? + +```js +const startPixel = { x: 0, y: 0 }; +const secondPixel = { x: 0, y: 1 }; +const thirdPixel = { x: 0, y: 2 }; +const fourthPixel = { x: 9, y: 1 }; + +// Create extent operations (extentOps) for the asset. +const extentOps = makePixelExtentOps(); + +// returns true: +extentOps.include([], []); +extentOps.include([startPixel], []); +extentOps.include([startPixel], [startPixel]); +extentOps.include([startPixel, secondPixel], [startPixel]); + +// returns false: +extentOps.include([], [startPixel]); +extentOps.include([startPixel], [secondPixel]); +extentOps.include([startPixel, thirdPixel], [secondPixel, fourthPixel]); +extentOps.include([startPixel, secondPixel, thirdPixel], [thirdPixel, fourthPixel]); +``` + +## extentOps.equals(left, right) +- `left` `{Extent}` +- `right` `{Extent}` +- Returns: `{Extent}` + +Does left equal right? + +```js +const startPixel = { x: 0, y: 0 }; +const secondPixel = { x: 0, y: 1 }; + +// Create extent operations (extentOps) for the asset. +const extentOps = makePixelExtentOps(); + +// returns true: +extentOps.equals([], []); +extentOps.equals([startPixel], [startPixel]); + +// returns false: +extentOps.equals([startPixel], []); +``` + +## extentOps.with(left, right) +- `left` `{Extent}` +- `right` `{Extent}` +- Returns: `{Extent}` + +Return the left combined with the right + +```js +const startPixel = { x: 0, y: 0 }; +const secondPixel = { x: 0, y: 1 }; + +// Create extent operations (extentOps) for the asset. +const extentOps = makePixelExtentOps(); + +// returns [] +extentOps.with([], []); + +// returns [startPixel] +extentOps.with([startPixel]), []); + +// returns [startPixel] +extentOps.with([], [startPixel]); + +// returns [startPixel] +extentOps.with([startPixel], [startPixel]); + +// returns [startPixel, secondPixel] +extentOps.with([startPixel], [secondPixel]); + +// returns [startPixel, secondPixel] +extentOps.with([startPixel, secondPixel], [startPixel]); +``` + +## extentOps.without(whole, part) +- `whole` `{Extent}` +- `part` `{Extent}` +- Returns: `{Extent}` + +Return what remains after removing the part from the whole. + +```js +const startPixel = { x: 0, y: 0 }; +const secondPixel = { x: 0, y: 1 }; + +// Create extent operations (extentOps) for the asset. +const extentOps = makePixelExtentOps(); + +// returns [] +extentOps.without([]), []); + +// returns [startPixel] +extentOps.without([startPixel]), []); + +// throws error +extentOps.without([]), [startPixel]); +``` diff --git a/main/ertp/api/mint.md b/main/ertp/api/mint.md index cb8c446d9..11a19e848 100644 --- a/main/ertp/api/mint.md +++ b/main/ertp/api/mint.md @@ -3,9 +3,7 @@ Holding a Mint carries the right to control issuance and destruction of purses and payments containing `units` of a particular currency. Purses and payments associated with a particular assay can only transfer value to others using the same mint. -## makeMint - -### makeMint(allegedName, makeConfig) +## makeMint(allegedName, makeConfig) - `allegedName` `{String}` - Description of the mint; becomes part of the label used by the `unitOps` @@ -30,7 +28,7 @@ const happyTownBucks = makeMint('happyTownBucks'); const sadTownBucks = makeMint('sadTownBucks'); ``` -### mint.getAssay() +## mint.getAssay() - Returns: `{Assay}` Get the Assay for this mint. @@ -43,552 +41,3 @@ const happyTownBucks = makeMint('happyTownBucks'); // Get the assay for the mint const assay = happyTownBucks.getAssay(); ``` - -## Assay - -An Assay represents the identity of an issuer. Holding an Assay provides the ability to create `units` and empty purses, but confers no rights. It is also the mechanism used to get exclusive access to a Purse or Payment that you already hold, or to burn some or all of the contained rights. - -### assay.getLabel() -- Returns: `{Label}` The label for the assay. - -Get the label for this Assay. Labels can be used to manually construct `units`. - -```js -import { makeMint } from '@agoric/ertp/core/mint'; -import config from 'customConfig.js'; - -// Initial mint -const happyTownBucks = makeMint('happyTownBucks'); -const assay = happyTownBucks.getAssay(); -const { allegedName } = assay.getLabel(); - -// Make a child mint using the initial mint's allegedName -const childMint = makeMint(allegedName, config); -``` - -### assay.getUnitOps() -- Returns: `{UnitOps}` - returns the unit operations for the Assay - -Get the `UnitOps` for this Assay. - -```js -const galleryPixel = makeMint('galleryPixel'); -const galleryPixelAssay = galleryPixel.getAssay(); -const galleryPixelUnitOps = galleryPixelAssay.getUnitOps(); -``` - -After getting the `UnitOps` of an `Assay`, `UnitOps` methods can be called to verify properties of the `units`. See the [UnitOps API](/api/unitOps) for all available methods. - -```js -function insist(asset, units) { - !assay.getUnitOps().isEmpty(units); - // no use rights present in units ${units}`; -} - -function insistAssetHasUnits(assay, asset, units) { - insist(assay.getUnitOps().includes(asset.getBalance(), units)); - // ERTP asset ${asset} does not include units ${units}`; -} - -function getPixelList(assay, units) { - return assay.getUnitOps().extent(units); -} -``` - -### assay.getExtentOps() -- Returns: `{ExtentOps}` - returns the extent operations for the Assay - -Get the `ExtentOps` for this Assay. - -```js -const exampleExtentOps = exampleAssay.getExtentOps(); -``` - -### assay.makeUnits(extent) -- `extent` `{Extent}` -- Returns: `{Units}` - -Make Units that contain the indicated extent. - -```js -import { setup } from '../setupBasicMints'; - -const { assays: originalAssays, mints, unitOps } = setup(); -const assays = originalAssays.slice(0, 2); - -// In this scenario, purses are created for two different assays. -// We provide Units, containing an extent, from the Moola and Simolean assays to create the appropriate purses. -const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(3)); -const aliceSimoleanPurse = mints[1].mint(assays[1].makeUnits(0)); -``` - -### assay.makeEmptyPurse(name) -- `name` `{String}` -- Returns: `{Purse}` - -Make an empty purse associated with this kind of right. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); - -// After creating an assay you can create an empty purse: -const targetPurse = assay.makeEmptyPurse(); - -// Returns 0 -targetPurse.getBalance(); -``` - -### assay.combine(paymentsArray, name) -- `paymentsArray` `{Array }` - A list of payments to combine into a new payment -- `name` `{String}` - Name to call this combination of payments -- Returns: `{Payment}` - -Combine multiple payments into one payment. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -// Create a payments array. Each element, or payment, has a value of 1. -const payments = []; -for (let i = 0; i < 100; i += 1) { - payments.push(purse.withdraw(1)); -} - -// Combine all the payments in the`payments` array -const combinedPayment = assay.combine(payments); - -// Returns 100 -combinedPayment.getBalance(); -``` - -### assay.split(payment, unitsArray) -- `payment` `{Payment}` -- `unitsArray` `{Array }` -- Returns: `{Array }` - -Split a single payment into multiple payments, according to the `units` and names passed in. - -```js -// Assume a mint has already been set up. -const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(40)); -const aliceMoolaPayment = aliceMoolaPurse.withdrawAll(); -const moola10 = assays[0].makeUnits(10); -const moola20 = assays[0].makeUnits(20); - -// The following divides the aliceMoolaPayment into three payments: -const aliceMoolaPayments = assays[0].split(aliceMoolaPayment, [ - moola10, - moola10, - moola20, -]); -// aliceMoolaPayments is now an array of three Payment objects, with balances of 10, 10, 20, respectively. -``` - -### assay.claimExactly(units, src, name) -- `units` `{Units}` -- `src` `{Payment}` -- `name` `{String}` - name of a new `Payment`, optional -- Returns: `{Payment}` - -Make a new `Payment` that has exclusive rights to all the contents of `src`. If `units` does not equal the balance of the `src` payment, throws error. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payment = await purse.withdraw(7); -const newPayment = await assay.claimExactly(7, payment); - -// .claimExactly() will throw an error because the the balance of wrongPayment does not equal the units -const wrongPayment = await purse.withdraw(7); -const wrongNewPayment = await assay.claimExactly(8, wrongPayment); -``` - -### assay.claimAll(src, name) -- `src` `{Payment}` -- `name` `{String}` - name of a new `Payment` -- Returns: `{Payment}` - -Make a new `Payment` that has exclusive rights to all the contents of `src`. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payment = await purse.withdraw(10); -const newPayment = await assay.claimAll(payment); - -// Returns 10 -newPayment.getBalance(); -``` - -### assay.burnExactly(units, src) -- `units` `{Units}` -- `src` `{Payment}` -- Returns: `{Units}` - -Burn all of the rights from `src`. If `units` does not equal the balance of the `src` payment, throw error. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payment = await purse.withdraw(10); - -// Throws error: -await assay.burnExactly(6, payment); - -// Successful burn: -await assay.burnExactly(10, payment); -``` - -### assay.burnAll(src) -- `src` `{Payment}` -- Returns: `{Units}` - -Burn all of the rights from `src`. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payment = await purse.withdraw(10); -await assay.burnAll(payment); -``` - -## Purse -Purses hold verified `units` of certain rights issued by Mints. Purses can transfer part of the balance they hold in a payment, which has a narrower interface. A purse's balance can rise and fall, through the action of depositExactly() and withdraw(). Operations on payments (`burnExactly()`, `depositExactly()`, `assay.claimExactly()`) kill the original payment and create new payments if applicable. The primary use for Purses and Payments is for currency-like and goods-like valuables, but they can also be used to represent other kinds of rights, such as the right to participate in a particular contract. - -### purse.getName() -- Returns: `{String}` - -Get the name of this purse. - -```js -Examples -``` - -### purse.getAssay() -- Returns: `{Assay}` - -Get the Assay for this purse. - -```js -// Assume a mint has already been set up. -const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(40)); -const aliceSimoleanPurse = mints[0].mint(assays[1].makeUnits(40)); - -const moolaAssay = await E(aliceMoolaPurse).getAssay(); -const simoleanAssay = await E(aliceSimoleanPurse).getAssay(); -``` - -### purse.getBalance() -- Returns: `{Units}` - -Get the `units` contained in this purse, confirmed by the assay. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -// Returns 1000 -purse.getBalance(); -``` - -### purse.depositExactly(units, src) -- `units` `{Units}` -- `src` `{Payment}` -- Returns: `{Units}` - -Deposit all the contents of `src` Payment into this purse, returning the `units`. If the `units` does not equal the balance of `src` Payment, throw error. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); -const targetPurse = assay.makeEmptyPurse(); -const payment = await purse.withdraw(7); - -// Throws error -await wrongTargetPurse.depositExactly(8, payment); - -// Successful deposit -await targetPurse.depositExactly(7, payment); -``` - -### purse.depositAll(srcPayment) -- `srcPayment` `{Payment}` -- Returns: `{Units}` - -Deposit all the contents of `srcPayment` into this purse, returning the `units`. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); -const targetPurse = assay.makeEmptyPurse(); - -const payment = await purse.withdraw(22); -await targetPurse.despositAll(payment); - -// Returns 22 -targetPurse.getBalance(); -``` - -### purse.withdraw(units, name) -- `units` `{Units}` -- `name` `{String}` - Optional -- Returns: `{Payment}` - -Withdraw `units` from this purse into a new Payment. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payments = []; -payments.push(purse.withdraw(20)); - -// Returns 20 -payments.getBalance(); -``` - -### purse.withdrawAll(name) -- `name` `{String}` -- Returns: `{Payment}` - -Withdraw entire content of this purse into a new Payment. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payment = purse.withdrawAll(); - -// Returns 1000 -payment.getBalance(); -``` - -## Payment -Payments hold verified units of certain rights issued by Mints. Units from payments can be deposited in purses, but otherwise, the entire unit is available when the payment is transferred. A payment's balance can only fall, through the action of `depositExactly()`, `claimExactly()` or `burnExactly()`. Payments can be converted to Purses by getting a verified assay and calling `assay.makeEmptyPurse().depositAll(payment)`; - -### payment.getName() -- Returns: `{String}` - -Get the name of this purse. - -```js -Examples -``` - -### payment.getAssay() -- Returns: `{Assay}` - -Get the Assay for this payment. - -```js -const paymentAssay = anyPayment.getAssay(); -``` - -### payment.getBalance() -- Returns: `{Units}` - -Get the units contained in this payment, confirmed by the assay. - -```js -import { makeMint } from './core/mint'; - -const mint = makeMint('fungible'); -const assay = mint.getAssay(); -const purse = mint.mint(1000); - -const payments = []; -payments.push(purse.withdraw(20)); - -// Returns 20 -payments.getBalance(); -``` - -## ExtentOps -All of the difference in how an unitOps behaves can be reduced to the behavior of the set operations on extents (think: arithmetic) such as `empty`, `with`, `without`, `includes`, etc. We extract this custom logic into an extentOps. ExtentOps are about extent arithmetic, whereas UnitOps are about Units, which are labeled extents. UnitOps use ExtentOps to do their extent arithmetic, and then label the results, making new Units. - -### extentOps.insistKind(allegedExtent) -- `allegedExtent` `{Extent}` -- Returns: `{Extent}` - -Check the kind of this extent and throw if it is not the expected kind. - -```js -const startPixel = { x: 0, y: 0 }; -const secondPixel = { x: 0, y: 1 }; -const thirdPixel = { x: 0, y: 2 }; -const pixelList = [startPixel, secondPixel, thirdPixel]; - -// Creates an array of pixels -const pixelExtentOps = makePixelExtentOps(); - -// Successful check -pixelExtentOps.insistKind(pixelList)); - -// Throws error because pixelExtentOps expects an array -pixelExtentOps.insistKind(startPixel); -``` - -### extentOps.empty() -- Returns: `{Extent}` - -Get the representation for empty. - -```js -const empty = exampleExtentOps.empty(); -``` - -### extentOps.isEmpty(extent) -- `extent` `{Extent}` -- Returns: `{boolean}` - -Is the extent empty? - -```js -const isExtentEmpty = exampleExtentOps.isEmpty(randomExtent); -``` - -### extentOps.includes(whole, part) -- `whole` `{Extent}` -- `part` `{Extent}` -- Returns: `{boolean}` - -Does the whole include the part? - -```js -const startPixel = { x: 0, y: 0 }; -const secondPixel = { x: 0, y: 1 }; -const thirdPixel = { x: 0, y: 2 }; -const fourthPixel = { x: 9, y: 1 }; - -// Create extent operations (extentOps) for the asset. -const extentOps = makePixelExtentOps(); - -// returns true: -extentOps.include([], []); -extentOps.include([startPixel], []); -extentOps.include([startPixel], [startPixel]); -extentOps.include([startPixel, secondPixel], [startPixel]); - -// returns false: -extentOps.include([], [startPixel]); -extentOps.include([startPixel], [secondPixel]); -extentOps.include([startPixel, thirdPixel], [secondPixel, fourthPixel]); -extentOps.include([startPixel, secondPixel, thirdPixel], [thirdPixel, fourthPixel]); -``` - -### extentOps.equals(left, right) -- `left` `{Extent}` -- `right` `{Extent}` -- Returns: `{Extent}` - -Does left equal right? - -```js -const startPixel = { x: 0, y: 0 }; -const secondPixel = { x: 0, y: 1 }; - -// Create extent operations (extentOps) for the asset. -const extentOps = makePixelExtentOps(); - -// returns true: -extentOps.equals([], []); -extentOps.equals([startPixel], [startPixel]); - -// returns false: -extentOps.equals([startPixel], []); -``` - -### extentOps.with(left, right) -- `left` `{Extent}` -- `right` `{Extent}` -- Returns: `{Extent}` - -Return the left combined with the right - -```js -const startPixel = { x: 0, y: 0 }; -const secondPixel = { x: 0, y: 1 }; - -// Create extent operations (extentOps) for the asset. -const extentOps = makePixelExtentOps(); - -// returns [] -extentOps.with([], []); - -// returns [startPixel] -extentOps.with([startPixel]), []); - -// returns [startPixel] -extentOps.with([], [startPixel]); - -// returns [startPixel] -extentOps.with([startPixel], [startPixel]); - -// returns [startPixel, secondPixel] -extentOps.with([startPixel], [secondPixel]); - -// returns [startPixel, secondPixel] -extentOps.with([startPixel, secondPixel], [startPixel]); -``` - -### extentOps.without(whole, part) -- `whole` `{Extent}` -- `part` `{Extent}` -- Returns: `{Extent}` - -Return what remains after removing the part from the whole. - -```js -const startPixel = { x: 0, y: 0 }; -const secondPixel = { x: 0, y: 1 }; - -// Create extent operations (extentOps) for the asset. -const extentOps = makePixelExtentOps(); - -// returns [] -extentOps.without([]), []); - -// returns [startPixel] -extentOps.without([startPixel]), []); - -// throws error -extentOps.without([]), [startPixel]); -``` diff --git a/main/ertp/api/payment.md b/main/ertp/api/payment.md new file mode 100644 index 000000000..a69871503 --- /dev/null +++ b/main/ertp/api/payment.md @@ -0,0 +1,39 @@ +# Payment +Payments hold verified units of certain rights issued by Mints. Units from payments can be deposited in purses, but otherwise, the entire unit is available when the payment is transferred. A payment's balance can only fall, through the action of `depositExactly()`, `claimExactly()` or `burnExactly()`. Payments can be converted to Purses by getting a verified assay and calling `assay.makeEmptyPurse().depositAll(payment)`; + +## payment.getName() +- Returns: `{String}` + +Get the name of this purse. + +```js +Examples +``` + +## payment.getAssay() +- Returns: `{Assay}` + +Get the Assay for this payment. + +```js +const paymentAssay = anyPayment.getAssay(); +``` + +## payment.getBalance() +- Returns: `{Units}` + +Get the units contained in this payment, confirmed by the assay. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payments = []; +payments.push(purse.withdraw(20)); + +// Returns 20 +payments.getBalance(); +``` diff --git a/main/ertp/api/purse.md b/main/ertp/api/purse.md new file mode 100644 index 000000000..9d54cc141 --- /dev/null +++ b/main/ertp/api/purse.md @@ -0,0 +1,125 @@ +# Purse +Purses hold verified `units` of certain rights issued by Mints. Purses can transfer part of the balance they hold in a payment, which has a narrower interface. A purse's balance can rise and fall, through the action of depositExactly() and withdraw(). Operations on payments (`burnExactly()`, `depositExactly()`, `assay.claimExactly()`) kill the original payment and create new payments if applicable. The primary use for Purses and Payments is for currency-like and goods-like valuables, but they can also be used to represent other kinds of rights, such as the right to participate in a particular contract. + +## purse.getName() +- Returns: `{String}` + +Get the name of this purse. + +```js +Examples +``` + +## purse.getAssay() +- Returns: `{Assay}` + +Get the Assay for this purse. + +```js +// Assume a mint has already been set up. +const aliceMoolaPurse = mints[0].mint(assays[0].makeUnits(40)); +const aliceSimoleanPurse = mints[0].mint(assays[1].makeUnits(40)); + +const moolaAssay = await E(aliceMoolaPurse).getAssay(); +const simoleanAssay = await E(aliceSimoleanPurse).getAssay(); +``` + +## purse.getBalance() +- Returns: `{Units}` + +Get the `units` contained in this purse, confirmed by the assay. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +// Returns 1000 +purse.getBalance(); +``` + +## purse.depositExactly(units, src) +- `units` `{Units}` +- `src` `{Payment}` +- Returns: `{Units}` + +Deposit all the contents of `src` Payment into this purse, returning the `units`. If the `units` does not equal the balance of `src` Payment, throw error. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); +const targetPurse = assay.makeEmptyPurse(); +const payment = await purse.withdraw(7); + +// Throws error +await wrongTargetPurse.depositExactly(8, payment); + +// Successful deposit +await targetPurse.depositExactly(7, payment); +``` + +## purse.depositAll(srcPayment) +- `srcPayment` `{Payment}` +- Returns: `{Units}` + +Deposit all the contents of `srcPayment` into this purse, returning the `units`. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); +const targetPurse = assay.makeEmptyPurse(); + +const payment = await purse.withdraw(22); +await targetPurse.despositAll(payment); + +// Returns 22 +targetPurse.getBalance(); +``` + +## purse.withdraw(units, name) +- `units` `{Units}` +- `name` `{String}` - Optional +- Returns: `{Payment}` + +Withdraw `units` from this purse into a new Payment. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payments = []; +payments.push(purse.withdraw(20)); + +// Returns 20 +payments.getBalance(); +``` + +## purse.withdrawAll(name) +- `name` `{String}` +- Returns: `{Payment}` + +Withdraw entire content of this purse into a new Payment. + +```js +import { makeMint } from './core/mint'; + +const mint = makeMint('fungible'); +const assay = mint.getAssay(); +const purse = mint.mint(1000); + +const payment = purse.withdrawAll(); + +// Returns 1000 +payment.getBalance(); +``` diff --git a/main/ertp/api/unitOps.md b/main/ertp/api/unit-ops.md similarity index 67% rename from main/ertp/api/unitOps.md rename to main/ertp/api/unit-ops.md index 5f66ddedb..9366e8b18 100644 --- a/main/ertp/api/unitOps.md +++ b/main/ertp/api/unit-ops.md @@ -1,67 +1,11 @@ -# UnitOps API - -## Definitions - -### Extent -Extents answer the question 'how much?' or 'how many?'. Fungible -extents are normally represented by natural numbers. For instance, if -we refer to "3 bucks", the "3" is the extent. Other extents may be -represented as strings naming a particular right (e.g. seat 'G19'), or -an arbitrary object that sensibly represents the rights at issue. -Extents must be pass-by-copy and Comparable. Extents are unlabeled, -meaning that they alone are not necessarily associated with a -particular assay or mint. - -### Units -Units are labeled extents. To be specific, units are a record with two -parts: a label, which identifies an assay, and an extent. The balance -of a purse or payment is in units. For example, the balance of a purse -might be 3 bucks, written in units as: +# UnitOps -```js -{ - label: { - allegedName: 'bucks', - assay: bucksAssay, - }, - extent: 3, -} -``` - -### UnitOps UnitOps are the "arithmetic" operations on units, used for actions like withdrawing a payment from a purse. All of the custom behavior is -stored in the ExtentOps, allowing for UnitOps to be polymorphic, +stored in the [ExtentOps](./extent-ops), allowing for UnitOps to be polymorphic, exposing the same interface while allowing custom behavior. -Units are the canonical description of tradable goods. They are -manipulated by mints, and represent the goods and currency carried by -purses and payments. They can be used to represent things like -currency, stock, and the abstract right to participate in a particular -exchange. - -### Label -The label in units identifies the assay, and includes an allegedName -that was provided by the maker of the mint. This allegedName should -not be trusted as accurate (for instance, anyone can create a mint -with allegedName 'BTC'), but the allegedName can be useful for -debugging and double-checking actions. - -## Types of UnitOps - -### UniUnitOps -UniUnitOps represents units that have unique descriptions. It is a refinement of UnitOps that we've found useful, but has no special place in the protocol. - -The extent must either be null, in which case it is empty,or be some truthy comparable value, in which case it represents a single unique unit described by that truthy extent. Combining two uni units with different truthy extents fails, as they represent non-combinable rights. - -### NatUnitOps -UnitOps for a labeled natural number describing a extent of fungible erights. The label describes what kinds of rights these are. NatUnitOps is a refinement of UnitOps that we've found useful, but has no special place in the protocol. - -Empty units have an extent equal to 0. 'includes()' verifies that leftUnits is greater than or equal to rightUnits. 'with()' and 'without()' add and subtract their contents. - -## unitOps Methods - -### unitOps.getLabel() +## unitOps.getLabel() - Returns: `{Label}` @@ -75,7 +19,7 @@ const localAssay = localMint.getAssay(); const localLabel = localAssay.getLabel(); ``` -### unitOps.make(allegedExtent) +## unitOps.make(allegedExtent) - `allegedExtent` `{Extent}` - [TOOD: add secod and third (optional) params] @@ -87,7 +31,7 @@ Make a new verified Units containing the `allegedExtent`. inviteMaker.make('writer', bobSeat); ``` -### unitOps.coerce(allegedUnits) +## unitOps.coerce(allegedUnits) - `allegedUnits` `{Units}` - An Units object made by this particular UnitOps. Function will error otherwise. - Returns: `{Units}` @@ -108,7 +52,7 @@ function insistUnitsEqualsPaymentBalance(units, payment) { } ``` -### unitOps.extent(units) +## unitOps.extent(units) - `units` `{Units}` - Returns: `{Extent}` @@ -123,7 +67,7 @@ const fungibleExtent = fungibleUnitOps.extent(1); const rightsExtent = rightsUnitOps.extent('This is an example of a string as an extent for rightsUnitOps.'); ``` -### unitOps.empty() +## unitOps.empty() - Returns: `{Units}` @@ -133,7 +77,7 @@ Return an empty units. Conveys no authority. const emptyUnits = exampleUnitOps.empty(); ``` -### unitOps.isEmpty(units) +## unitOps.isEmpty(units) - `units` `{Units}` - Returns: `{boolean}` @@ -151,7 +95,7 @@ exampleUnitOps.isEmpty(emptyUnits); exampleUnitOps.isEmpty(notEmptyUnits); ``` -### unitOps.includes(leftUnits, rightUnits) +## unitOps.includes(leftUnits, rightUnits) - `leftUnits` `{Units}` - `rightUnits` `{Units}` @@ -184,7 +128,7 @@ galleryPixelUnitOps.include([startPixel, thirdPixel], [secondPixel, fourthPixel] galleryPixelUnitOps.include([startPixel, secondPixel, thirdPixel], [thirdPixel, fourthPixel]); ``` -### unitOps.equals(leftUnits, rightUnits) +## unitOps.equals(leftUnits, rightUnits) - `leftUnits` `{Units}` - `rightUnits` `{Units}` @@ -210,7 +154,7 @@ galleryPixelUnitOps.equals([startPixel], [startPixel]); galleryPixelUnitOps.equals([startPixel], []); ``` -### unitOps.with(leftUnits, rightUnits) +## unitOps.with(leftUnits, rightUnits) - `leftUnits` `{Units}` - `rightUnits` `{Units}` @@ -247,7 +191,7 @@ galleryPixelUnitOps.with([startPixel], [secondPixel]); galleryPixelUnitOps.with([startPixel, secondPixel], [startPixel]); ``` -### unitOps.without(leftUnits, rightUnits) +## unitOps.without(leftUnits, rightUnits) - `leftUnits` `{Units}` - `rightUnits` `{Units}` diff --git a/main/ertp/glossary/README.md b/main/ertp/glossary/README.md new file mode 100644 index 000000000..34ebc847e --- /dev/null +++ b/main/ertp/glossary/README.md @@ -0,0 +1,40 @@ +# ERTP Glossary + +## Assay +An Assay represents the identity of an issuer. Holding an Assay provides the ability to create units and empty purses, but confers no rights. It is also the mechanism used to get exclusive access to a Purse or Payment that you already hold, or to burn some or all of the contained rights. + +## AssetHolder +Purses and Payments are AssetHolders. + +## ContractHost +A platform for evaluating contract code and handing out seats in that contract + +## ERTP +Electronic Rights Transfer Protocol - a smart contract framework that uses object capabilities to enforce access control. Instead of having to prove ownership of a corresponding private key, in the world of object capabilities, if your program has a reference to an 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/). + +## Extent +How much, how many, or description of unique asset. (Pixel(3,2), $3 or ‘Right to occupy on Tuesdays’) + +## ExtentOps +“Arithmetic” operations on Extents + +## Label +AllegedName (made by maker of mint) + Assay + +## Mint +The autority to mint. The right to control issuance and destruction of purses and payments containing `units` of a particular currency. + +## Purse +An [AssetHolder](#assetholder). Purses hold verified units of certain rights issued by Mints, specifically units that are _stationary_. Purses can transfer part of the balance they hold in a [payment](#payment), which has a narrower interface. [Purse API](/ertp/api/mint.html#purse) + +## Payment +An [AssetHolder](#assetholder). Payments hold verified units of certain rights issued by Mints, specifically units that are in _transit_. Units from payments can be deposited in [purses](#purse), but otherwise, the entire unit is available when the payment is transferred. Payments can be converted to Purses. [Payment API](/ertp/api/mint.html#payment) + +## Unit +Label (allegedName + assay) + Extent + +## UnitOps +"Arithmetic" operations on [Units](#unit) + +## UseObj +A object associated with purses and payments that has custom behavior associated with the use of digital assets diff --git a/main/ertp/guide/assay.md b/main/ertp/guide/assay.md new file mode 100644 index 000000000..25a789647 --- /dev/null +++ b/main/ertp/guide/assay.md @@ -0,0 +1,13 @@ +# Assays + +## Assays in ERTP + +An Assay represents the identity of an issuer. Holding an Assay provides the ability to create `units` and empty purses, but confers no rights. It is also the mechanism used to get exclusive access to a Purse or Payment that you already hold, or to burn some or all of the contained rights. + +## Other Definition +::: tip Definition +As a noun, assay means a test or appraisal to determine the components of a substance or object. +As a verb, it refers to the act of analyzing, or of conducting that test. + +[Source: Vocabulary.com](https://www.vocabulary.com/dictionary/assay) +::: diff --git a/main/ertp/guide/assays.md b/main/ertp/guide/assays.md deleted file mode 100644 index 6dd7996d1..000000000 --- a/main/ertp/guide/assays.md +++ /dev/null @@ -1,17 +0,0 @@ -# Assays - -## Definition - -::: tip -As a noun, assay means a test or appraisal to determine the components of a substance or object. -As a verb, it refers to the act of analyzing, or of conducting that test. - -[Source: Vocabulary.com](https://www.vocabulary.com/dictionary/assay) -::: - - -## Assays in ERTP - -Assays are a key concept of ERTP. - -In ERTP, you can think of Assays as tests to ensure that the information being passed in meets the requirements set. diff --git a/main/ertp/guide/extent.md b/main/ertp/guide/extent.md new file mode 100644 index 000000000..aad8319ee --- /dev/null +++ b/main/ertp/guide/extent.md @@ -0,0 +1,11 @@ +# Extent + +Extents answer the question 'how much?' or 'how many?'. Fungible +extents are normally represented by natural numbers. For instance, if +we refer to "3 bucks", the "3" is the extent. Other extents may be +represented as strings naming a particular right (e.g. seat 'G19'), or +an arbitrary object that sensibly represents the rights at issue. + +Extents must be pass-by-copy and Comparable. Extents are unlabeled, +meaning that they alone are not necessarily associated with a +particular assay or mint. diff --git a/main/ertp/guide/label.md b/main/ertp/guide/label.md new file mode 100644 index 000000000..8b1600f85 --- /dev/null +++ b/main/ertp/guide/label.md @@ -0,0 +1,17 @@ +# Label + +The label in units identifies the assay, and includes an `allegedName` +that was provided by the maker of the mint. + +```js +label: { + allegedName: 'bucks', + assay: bucksAssay, +} +``` + +## allegedName +This `allegedName` should +not be trusted as accurate (for instance, anyone can create a mint +with allegedName 'BTC'), but the `allegedName` can be useful for +debugging and double-checking actions. diff --git a/main/ertp/guide/mint.md b/main/ertp/guide/mint.md new file mode 100644 index 000000000..85e093298 --- /dev/null +++ b/main/ertp/guide/mint.md @@ -0,0 +1,15 @@ +# Mint + +Holding a Mint carries the right to control issuance and destruction of `purses` and `payments` containing `units` of a particular currency. + +Purses and payments associated with a particular assay can only transfer value to others using the same mint. + +The primary use for Purses and Payments is for currency-like and goods-like valuables, but they can also be used to represent other kinds of rights, such as the right to participate in a particular contract. + +## Purses + +Purses hold verified `units` of certain rights issued by Mints. Purses can transfer part of the balance they hold in a payment, which has a narrower interface. + +## Payments + +Payments hold verified units of certain rights issued by Mints. Units from payments can be deposited in purses, but otherwise, the entire unit is available when the payment is transferred. Payments can be converted to Purses. diff --git a/main/ertp/guide/unit-ops.md b/main/ertp/guide/unit-ops.md new file mode 100644 index 000000000..3d47f7754 --- /dev/null +++ b/main/ertp/guide/unit-ops.md @@ -0,0 +1,17 @@ +# UnitOps +UnitOps are the "arithmetic" operations on units, used for actions like +withdrawing a payment from a purse. All of the custom behavior is +stored in the [ExtentOps](./extent), allowing for UnitOps to be polymorphic, +exposing the same interface while allowing custom behavior. + +## Types of UnitOps + +### UniUnitOps +UniUnitOps represents units that have unique descriptions. It is a refinement of UnitOps that we've found useful, but has no special place in the protocol. + +The extent must either be null, in which case it is empty,or be some truthy comparable value, in which case it represents a single unique unit described by that truthy extent. Combining two uni units with different truthy extents fails, as they represent non-combinable rights. + +### NatUnitOps +UnitOps for a labeled natural number describing a extent of fungible erights. The label describes what kinds of rights these are. NatUnitOps is a refinement of UnitOps that we've found useful, but has no special place in the protocol. + +Empty units have an extent equal to 0. 'includes()' verifies that leftUnits is greater than or equal to rightUnits. 'with()' and 'without()' add and subtract their contents. diff --git a/main/ertp/guide/units.md b/main/ertp/guide/units.md new file mode 100644 index 000000000..cbde201c6 --- /dev/null +++ b/main/ertp/guide/units.md @@ -0,0 +1,22 @@ +# Units +Units are the canonical description of tradable goods. They are +manipulated by mints, and represent the goods and currency carried by +purses and payments. They can be used to represent things like +currency, stock, and the abstract right to participate in a particular +exchange. + +## Labeled extents +Units are labeled extents. To be specific, units are a record with two +parts: a label, which identifies an assay, and an extent. The balance +of a purse or payment is in units. For example, the balance of a purse +might be 3 bucks, written in units as: + +```js +{ + label: { + allegedName: 'bucks', + assay: bucksAssay, + }, + extent: 3, +} +```