Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restrict "burn" to describing operations that destroy assets #655

Merged
merged 12 commits into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions main/ertp/api/brand.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ other `mint` or `issuer`.
- `issuer` `{Issuer}`
- Returns: `{Boolean}`

Return `true` if `issuer` is this brand's `issuer`, `false` if not.
Return `true` if `issuer` is the brand's `issuer`, `false` if not.

An `issuer` uniquely identifies its `brand`. A `brand` **unreliably** identifies
its `issuer`. If `brand` B claims its `issuer` is A, but A doesn't agree
that B is its `brand`, then the `brand` is unreliable.
Note that a `brand` from an untrusted source can misrepresent its association with
an `issuer`. The claim should be cross-checked against
[`issuer.getBrand()`](./issuer.md#issuer-getbrand) for mutual agreement.

```js
const isIssuer = brand.isMyIssuer(issuer);
Expand Down
96 changes: 41 additions & 55 deletions main/ertp/api/issuer.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ are ephemeral, so any object created there dies as soon as the script stops.
- `issuer` `{Issuer}`
- `brand` `{Brand}`
gibson042 marked this conversation as resolved.
Show resolved Hide resolved

Makes a new `issuer` as well as its one-to-one associated ERTP objects; a `mint` and a `brand`.
Create and return a new `issuer` and its associated `mint` and `brand`.
All are in unchangeable one-to-one relationships with each other.

The `allegedName` becomes part of the `brand` in asset descriptions. It
Expand Down Expand Up @@ -66,7 +66,7 @@ const combinedProperty = AmountMath.make(propertyTitleBrand, ['1292826', '102839
## `issuer.getAllegedName()`
- Returns: `{allegedName}`

Returns the `allegedName` for this `issuer`.
Return the `allegedName` for the `issuer` (the non-trusted human-readable name of its associated `brand`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's work having an example here, like how anyone can create a new issuer whose allegedName is BTC.


An alleged name is a human-readable string name
of a kind of digital asset. An alleged name
Expand All @@ -76,10 +76,10 @@ means there can be multiple issuers/mints/brands with the
same alleged name, and thus the name by itself does not
uniquely identify an issuer. Rather, the `brand` object does that.

To put it another way, nothing stops different people from creating
multiple `issuers` with the alleged name `Quatloos`...but that doesn't
make any of them **the** Quatloos `issuer`. The alleged name is just a
human readable version which is helpful for debugging.
To put it another way, nothing stops anyone from creating an `issuer`
with the alleged name "Quatloos" or even "BTC", regardless of whether
or not such a name is already in use. The alleged name is just a
human readable string which is helpful for debugging.
```js
const { issuer: quatloosIssuer } = makeIssuerKit('quatloos');
const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName();
Expand All @@ -89,8 +89,7 @@ const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName();
## `issuer.getAssetKind()`
- Returns: `{AssetKind}`

Get the kind of this `issuer`'s asset. It returns one of
`AssetKind.NAT` (`nat`) or `AssetKind.SET` (`set`).
Return the kind of the `issuer`'s asset; either `AssetKind.NAT` ("nat") or `AssetKind.SET` ("set").
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To anticipate a request, I think we'll want to document AssetKind.COPY_SET and AssetKind.COPY_BAG here, as was done in 85fc794#diff-567699eff5882f854f56340cee0537815d3e363b61e098208212dc172190dd3dR43 . But I think that belongs in a followup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


The `assetKind` value specifies what kind of values are used in amounts for this issuer.
`AmountMath` works for all the different kinds of values.
Expand All @@ -110,9 +109,9 @@ moolaIssuer.getAssetKind(); // Returns 'set', also known as 'AssetKind.SET`
- `payment` `{Payment}`
- Returns: `{Amount}`

Get the `payment`'s balance. Because the `payment` is not trusted, we cannot
trust it to provide its true value, and must rely on the `issuer` to validate
the `payment`'s `brand` and tell us how much it contains.
Describe the `payment`'s balance as an Amount. Because a `payment` from an untrusted
source cannot be trusted to provide its own true value, `issuer` must be used to
validate its `brand` and report how much it contains.

```js
const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand} = makeIssuerKit('quatloos');
Expand All @@ -123,7 +122,7 @@ quatloosIssuer.getAmountOf(quatloosPayment); // returns an amount of 100 Quatloo
## `issuer.getBrand()`
- Returns: `{Brand}`

Returns the `brand` for this `issuer`. The `brand` indicates the kind of digital asset
Return the `brand` for the `issuer`. The `brand` indicates the kind of digital asset
and is the same for the `issuer`'s associated `mint`, and any `purses` and `payments` of this particular
kind. The `brand` is not closely held, so this function should not be trusted to identify
an `issuer` alone. Fake digital assets and amounts can use another `issuer's` `brand`.
Expand All @@ -149,15 +148,15 @@ const quatloosPurse = quatloosIssuer.makeEmptyPurse();
- `optAmount` `{Amount}` - Optional
- Returns: `{Amount}`

Burn (destroy) all of the digital assets in the `payment`
and return an `amount` of what was burned.
Destroy all of the digital assets in the `payment`,
make it unavailable for later use,
and return an Amount of what was burned.

`optAmount` is optional. If `optAmount` is present,
the code insists the `payment` balance is equal to `optAmount`, to prevent sending the wrong `payment`
and other confusion.

If `payment` is a `promise` for a `payment`, the operation proceeds after the
`promise` resolves.
If `payment` is a promise, the operation proceeds after it resolves to a Payment.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, the parameter should have been typed ERef<Payment>. Why didn't TS alert us to this mismatch?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably because there's no direct link between TS and this documentation. It does seem correct in the agoric-sdk source—issuer.burn is typed as IssuerBurn, which is defined to accept ERef<Payment> and optional Pattern and return Promise<Amount>. I've opened #666 to address here.


```js
const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } =
Expand All @@ -174,19 +173,16 @@ const burntAmount = quatloosIssuer.burn(paymentToBurn, amountToBurn);
- `optAmount` `{Amount}`
- Returns: `{Payment}`

Transfer all digital assets from `payment` to a new `payment` and burn the
original. This allows the owner to be sure no other references to this
payment survive, so they are the exclusive owner.
Transfer all digital assets from `payment` to a new Payment and consume the
original, making it unavailable for later use.

`optAmount` is optional.
If `optAmount` is present, `payment`'s balance must be
equal to `optAmount`, to prevent sending the wrong `payment` and other confusion.
If `optAmount` does not equal the balance in the original `payment`
then it throws an error.

If a `payment` is a `promise` for a `payment`, the operation will
proceed after the `promise` resolves. Since you might also have a `promise` returned,
it might take a bit of time for the whole operation to resolve.
If `payment` is a promise, the operation proceeds after it resolves to a Payment.

```js
const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos');
Expand All @@ -201,16 +197,14 @@ const newPayment = quatloosIssuer.claim(originalPayment, amountToTransfer);
- `optTotalAmount` `{Amount}` - Optional.
- Returns: `{Payment}`

Combines multiple `payments` into one `payment`. If any `payment` in `paymentsArray` is
a `promise`, the operation proceeds after all the `payments`
resolve. The `payments` in `paymentsArray` are burned.
Combine multiple Payments into one new Payment. If any item in `paymentsArray` is
a promise, the operation proceeds after each such promise resolves to a Payment.
All Payments in `paymentsArray` are consumed and made unavailable for later use.

If the optional `optTotalAmount` is present, the total of all the `payment` `amounts` in the
array must equal `optTotalAmount` or it throws an error.
If the optional `optTotalAmount` is present, the total value of all Payments in `paymentsArray`
must equal `optTotalAmount` or it throws an error.

If a `payment` is a `promise` for a `payment`, the operation will
proceed after the `promise` resolves. Since you might also have a `promise` returned,
it might take a bit of time for the whole operation to resolve.
Each Payment in `paymentsArray` must be associated with the same Brand as `issuer`.

```js
const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos');
Expand All @@ -224,31 +218,20 @@ for (let i = 0; i < 100; i += 1) {
const combinedPayment = quatloosIssuer.combine(payments);
```

**Note**: You **cannot** combine `payments` from different `mints` (as they are of different `brands`):

```js
const { mint: otherMint, issuer: otherIssuer, brand: otherBrand } = makeIssuerKit('other');
const otherPayment = otherMint.mintPayment(AmountMath.make(otherBrand, 10n));
payments.push(otherPayment); // using the payments array from the above code

// throws error
const badPayment = quatloosIssuer.combine(payments);
```

## `issuer.split(payment, paymentAmountA)`
- `payment` `{Payment}`
- `paymentAmountA` `{Amount}`
- Returns: `{Array <Payment>}`

Split a single `payment` into two new `payments`, A and B, according to `paymentAmountA`.
Split a single `payment` into two new Payments, A and B, according to `paymentAmountA`.
For example, if the `payment` is for 10 Quatloos, and `paymentAmountA` is 3 Quatloos,
it returns an array of two `payments` with balances of 3 Quatloos and 7 Quatloos.
it returns an array of two Payments with respective balances of 3 Quatloos and 7 Quatloos.

The original `payment` is burned.
The original `payment` is consumed and made unavailable for later use.

If the original `payment` is a `promise` for a `payment`, the operation will
proceed after the `promise` resolves. Since you might also have a `promise` returned,
it might take a bit of time for the whole operation to resolve.
If `payment` is a promise, the operation proceeds after it resolves to a Payment.

`payment` and `paymentAmountA` must both be associated with the same Brand as `issuer`.

```js
const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit('quatloos');
Expand All @@ -262,12 +245,15 @@ const [paymentA, paymentB] = quatloosIssuer.split(oldPayment, AmountMath.make(qu
- `amountArray` `{Array <Amount>}`
- Returns: `{Array <Payment>}`

Split a single `payment` into multiple `payments`. The resulting array of `payments` is
as long as `amountArray`, and the `payments` will have `amounts` corresponding to
the `amountArray` contents. The original `payment` is burned. If the original `payment`
is a `promise`, the operation proceeds after the `promise` resolves. If the `amounts`
in `amountArray` don't add up to the value of `payment`, the operation fails. The `brands`
of the `amountArray` `amounts` must all be the same as the `payment` `brand`.
Split a single `payment` into multiple Payments.
The returned array includes a Payment item corresponding to each Amount of `amounts`, in order.

The original `payment` is consumed and made unavailable for later use.

If `payment` is a promise, the operation proceeds after it resolves to a Payment.

If the Amounts in `amountArray` don't add up to the value of `payment`, the operation fails.
`payment` and each Amount in `amountArray` must be associated with the same Brand as `issuer`.

```js
const { mint: quatloosMint, issuer: quatloosIssuer, brand: quatloosBrand} = makeIssuerKit('quatloos');
Expand All @@ -291,5 +277,5 @@ quatloosIssuer.splitMany(payment, badAmounts);
- `payment` `{Payment}`
- Returns: `{Boolean}`

Returns `true` if the `payment` was created by the issuer and has not yet been destroyed.
If `payment` is a promise, the operation proceeds upon resolution.
Return `true` if the `payment` was created by the issuer and is available for use (has not been consumed or burned).
If `payment` is a promise, the operation proceeds after it resolves to a Payment.
2 changes: 1 addition & 1 deletion main/ertp/api/mint.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ See [here](/ertp/api/issuer.md#makeissuerkit-allegedname-assetkind-displayinfo)
## `mint.getIssuer()`
- Returns: `{Issuer}`

Get the `Issuer` associated with this `mint`. From their creation, a `mint` is always
Return the `issuer` uniquely associated with the `mint`. From their creation, a `mint` is always
in an unchangeable one-to-one relationship with an `issuer`.

```js
Expand Down
50 changes: 26 additions & 24 deletions main/ertp/api/payment.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ take out, say, 3 Quatloos from it, leaving the `payment` with 7 Quatloos.

However, you can split a `payment` into multiple `payments`, for example
into two new `payments` of 3 Quatloos and 7 Quatloos.
The `split()` operation *burns* (destroys) the original 10 Quatloos `payment`.
The `split()` operation consumes the original 10 Quatloos `payment`,
making it unavailable for later use.

`Payments` are often received from other actors. Since they are not self-verifying,
you cannot trust `payments`. To get the verified balance of a `payment`, use the `issuer`
Comment on lines 17 to 18
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is stated in the correct terms (even if a bit unclear).

Expand All @@ -22,7 +23,8 @@ To convert a `payment` into a new `purse`:
2. Use the `issuer` to create an empty `purse` for that `brand`.
3. Deposit the `payment` into the new `purse`.

`purse.deposit(payment)` burns the `payment`.
`purse.deposit(payment)` consumes the `payment`,
making it unavailable for later use.

## `payment.getAllegedBrand()`
- Returns: `{Brand}`
Expand All @@ -40,29 +42,29 @@ const allegedBrand = payment.getAllegedBrand();
## Related Methods

The following methods on other ERTP components either operate
on or return a `payment`. While a brief description is given for each,
on or return a Payment. While a brief description is given for each,
you should click through to a method's main documentation entry for
full details on what it does and how to use it.

- [`issuer.burn(payment, optAmount)`](./issuer.md#issuer-burn-payment-optamount)
- Burn (destroy) all of the digital assets in the `payment`.
- [`issuer.claim(payment, optAmount)`](./issuer.md#issuer-claim-payment-optamount)
- Transfer all assets from the `payment` to a returned new `payment` and burn the original.
- [`issuer.combine(paymentsArray)`](./issuer.md#issuer-combine-paymentsarray-opttotalamount)
- Combine multiple `payments` into one, returned, `payment`.
- [`issuer.getAmountOf(payment)`](./issuer.md#issuer-getamountof-payment)
- Get a description of a `payment` balance as an `amount`.
- [`issuer.isLive(payment)`](./issuer.md#issuer-islive-payment)
- Returns `true` if the `issuer` says the `payment` exists (i.e. it's been created and hasn't been burned).
- [`issuer.split(payment, paymentAmountA)`](./issuer.md#issuer-split-payment-paymentamounta)
- Split one `payment` into two new ones.
- [`issuer.splitMany(payment, amountArray)`](./issuer.md#issuer-splitmany-payment-amountarray)
- Split `payment` into multiple `payments`, returned as an array.
- [`mint.mintPayment(newAmount)`](./mint.md#mint-mintpayment-newamount)
- Returns a new `payment` containing the newly minted assets corresponding to the `newAmount` argument.
- [`purse.deposit(payment, optAmount`)`](./purse.md#purse-deposit-payment-optamount)
- Deposit all of `payment` into this `purse`.
- [`issuer.burn(payment, optAmount)`](./issuer.md#issuer-burn-payment-optamount)
- Destroy all of the digital assets in the `payment`.
- [`issuer.claim(payment, optAmount)`](./issuer.md#issuer-claim-payment-optamount)
- Transfer all digital assets from `payment` to a new Payment.
- [`issuer.combine(paymentsArray)`](./issuer.md#issuer-combine-paymentsarray-opttotalamount)
- Combine multiple Payments into one new Payment.
- [`issuer.getAmountOf(payment)`](./issuer.md#issuer-getamountof-payment)
- Describe the `payment`'s balance as an Amount.
- [`issuer.isLive(payment)`](./issuer.md#issuer-islive-payment)
- Return `true` if the `payment` was created by the issuer and is available for use (has not been consumed or burned).
- [`issuer.split(payment, paymentAmountA)`](./issuer.md#issuer-split-payment-paymentamounta)
- Split a single `payment` into two new Payments.
- [`issuer.splitMany(payment, amountArray)`](./issuer.md#issuer-splitmany-payment-amountarray)
- Split a single `payment` into multiple Payments.
- [`mint.mintPayment(newAmount)`](./mint.md#mint-mintpayment-newamount)
- Create new digital assets of the `mint`'s associated `brand`.
- [`purse.deposit(payment, optAmount)`](./purse.md#purse-deposit-payment-optamount)
- Deposit all the contents of `payment` into `purse`.
- [`purse.getDepositFacet()`](./purse.md#purse-getdepositfacet)
- Creates a deposit-only facet on the `purse` that can be given to other parties to deposit `payments` in.
- [`purse.withdraw(amount)`](./purse.md#purse-withdraw-amount)
- Returns a new `payment` whose balance is described by the `amount` argument.
- Create and return a new deposit-only facet of the `purse` that allows arbitrary other parties to deposit Payments into `purse`.
- [`purse.withdraw(amount)`](./purse.md#purse-withdraw-amount)
- Withdraw the `amount` of specified digital assets from `purse` into a new `payment`.
14 changes: 7 additions & 7 deletions main/ertp/api/purse.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ const checkNotifier = async () => {
- `optAmount` `{Amount}` - Optional.
- Returns: `{Amount}`

Deposit all the contents of `payment` into this `purse`, returning an `amount` describing the
`payment`'s digital assets (i.e. the deposit amount). If the optional argument `optAmount` does not equal the balance of
`payment`, or if `payment` is an unresolved promise, it throws an error.
Deposit all the contents of `payment` into `purse`, returning an `amount` describing the
`payment`'s digital assets (i.e. the deposited amount). If the optional argument `optAmount` does not equal the balance of
`payment`, or if `payment` is a promise, it throws an error.

While the above applies to local and remote `purses`, for remote `purses` there may be effects on
this operation due to use of `promises` and asynchronicity. You
Expand Down Expand Up @@ -106,10 +106,10 @@ const depositAmountB = quatloosPurse.deposit(secondPayment, quatloos123);
```

## `purse.getDepositFacet()`
- Returns: `{DepositFacet}`

Returns a deposit-only facet on the `purse`. This is an object you can give to other parties
that lets them deposit `payments` to your `purse` without being able to withdraw assets from or check
the balance of the `purse`. This makes it a safe way to let other people send you `payments`.
Create and return a new deposit-only facet of the `purse` that allows arbitrary other parties to deposit `payments` into `purse` without the ability to check its balance or withdraw from it.
This makes it a safe way to let other people send you `payments`.

You can only deposit a `payment` into a deposit facet that's the same `brand` as the original `purse`
takes.
Expand Down Expand Up @@ -152,7 +152,7 @@ depositOnlyFacet.receive(payment);
- `amount` `{Amount}`
- Returns: `{Payment}`

Withdraw the `amount` specified digital assets from this `purse` into a new `payment`.
Withdraw the `amount` of specified digital assets from `purse` into a new `payment`.

If the call succeeds, it immediately extracts the value into a new `payment`.
The caller won't get the new `payment` until a later turn, since the call is (nearly always) remote.
Expand Down
Loading