# Purse

Purses hold digital assets. They are created to hold assets of a single brand, and their brand cannot be changed. For example, you might create a purse to hold Quatloos. That purse can only hold Quatloos; it can't hold Moola or theater tickets or anything else. And you can't change that purse so that it now holds Moola instead; you need to create a purse that holds only Moola.

Digital assets in purses and payments can be any of:

  • Currency-like, such as our imaginary Quatloos currency.
  • Goods-like digital assets, such as magic weapons for use in a game or theater tickets.
  • Other kinds of rights, such as the right to participate in a particular contract.

While each purse can only hold assets of one brand, any number of purses can be created that hold that brand. So you could have, say, three Quatloos purses, your friend Alice could have eight Quatloos purses, and so on.

You change a purse's balance by calling either deposit() (to add assets) or withdraw() (to remove assets) on it. A purse can be empty, which if it holds a fungible currency means it has a value of 0. If it holds non-fungible theatre tickets, it means it just doesn't have any tickets.

Unlike payments, purses are not meant to be sent to others. To transfer digital assets, you should withdraw a payment from a purse and send the payment to another party.

# issuer.makeEmptyPurse()

  • Returns: {Purse}

While not a method called on a purse, clearly it's important to know how to create a new purse. Call makeEmptyPurse() on the issuer associated with the brand of assets you want the new purse to hold. It returns the new purse with an empty balance.

const {issuer: quatloosIssuer} = makeIssuerKit('quatloos');
quatloosPurse1 = quatloosIssuer.makeEmptyPurse();
quatloosPurse2 = quatloosIssuer.makeEmptyPurse();

# purse.getCurrentAmount()

  • Returns: {Amount}

Get an amount describing the current digital assets balance in the purse. Of course, the returned amount value might be different the next time you call getCurrentAmount() on the same purse if assets have been deposited or withdrawn from it in-between calls.

const { issuer: quatloosIssuer } = makeIssuerKit('quatloos');
const quatloosPurse = quatloosIssuer.makeEmptyPurse();
// quatloos5 is a payment with balance of 5 quatloos
const quatloosPurse.deposit(quatloos5);
// Returns an amount with value = 5 and brand = quatloos
const currentBalance = quatloosPurse.getCurrentAmount();

# purse.getCurrentAmountNotifier()

  • Returns: {Notifier<Amount>}

Returns a lossy notifier for changes to this purse's balance. For more details, see Notifiers.

const notifier = purse.getCurrentAmountNotifier();
let nextUpdate = notifier.getUpdateSince();

const checkNotifier = async () => {
  const { value: balance, updateCount } = await nextUpdate;
  nextUpdate = notifier.getUpdateSince(updateCount);
};

# purse.deposit(payment, optAmount)

  • payment {Payment}
  • 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.

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 have to have a non-promise payment before calling deposit(). When you call deposit() you get a response back (after waiting only for the round trip) telling you if it succeeded. All later arriving calls see the value has been transferred into the purse, and the payment is are no longer valid.

If any withdrawals are waiting for promises to resolve, a deposit operation may pass them by. This is safe, as even if all the assets are withdrawn, the deposit still works on an empty purse.

const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand } = 
      makeIssuerKit('quatloos');
const quatloosPurse = quatloosIssuer.makeEmptyPurse();
const payment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 123n));
const quatloos123 = AmountMath.make(quatloosBrand, 123n);

// Deposit a payment for 123 Quatloos into the purse. 
const depositAmountA = quatloosPurse.deposit(payment, quatloos123);

const secondPayment = quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 100n));
// Throws error
const depositAmountB = quatloosPurse.deposit(secondPayment, quatloos123);

# purse.getDepositFacet()

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.

You can only deposit a payment into a deposit facet that's the same brand as the original purse takes.

const depositOnlyFacet = purse.getDepositFacet();

// Give depositOnlyFacet to someone else. Anyone with a deposit facet reference can tell it to receive
// a payment, thus depositing the payment assets in the purse associated with the deposit facet.
depositOnlyFacet.receive(payment);

Once you have created a depositFacet, there is one method you can call on it. depositFacet.receive(payment). The depositFacet takes the payment and adds it to the balance of the facet's associated purse. The payment must be of the same brand as what the purse holds.

Note the difference in method names for adding assets between a purse and its depositFacet. To add assets to a purse directly, you use purse.deposit(). To add assets to a purse via its depositFacet, you use depositFacet.receive().

# depositFacet.receive(payment, optAmount?)

  • payment {Payment}
  • optAmount {Amount} (optional)
  • Returns {Amount}

The depositFacet takes the payment and adds it to the balance of the facet's associated purse.

If the optional argument optAmount does not equal the balance of payment, or if payment is an unresolved promise, it throws an error.

const depositOnlyFacet = purse.getDepositFacet();

// Give depositOnlyFacet to someone else. Anyone with a deposit facet reference can tell it to receive
// a payment, thus depositing the payment assets in the purse associated with the deposit facet.
depositOnlyFacet.receive(payment);

# purse.withdraw(amount)

  • amount {Amount}
  • Returns: {Payment}

Withdraw the amount specified digital assets from this 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. But as soon as the message is processed, the value is gone from the purse.

// Create a purse and give it a balance of 10 Quatloos
const { issuer, mint, brand } = makeIssuerKit('quatloos');
const purse = issuer.makeEmptyPurse();
const payment = mint.mintPayment(AmountMath.make(brand, 10n));
const quatloos10 = AmountMath.make(brand, 10n);
purse.deposit(payment, quatloos10);

// Withdraw an amount of 3 from the purse
const quatloos3 = AmountMath.make(brand, 3n);
const withdrawalPayment = purse.withdraw(quatloos3);

// The balance of the withdrawal payment is 3 Quatloos
issuer.getAmountOf(withdrawalPayment);

// The new balance of the purse is 7 Quatloos
purse.getCurrentAmount();

# purse.getAllegedBrand()

  • Returns: {Brand}

Returns an alleged brand (Note: a Brand, not a string as allegedName() methods do), indicating what kind of digital asset the purse purports to hold. This can identify the purse's brand if the purse was made by a trusted issuer using issuer.makeEmptyPurse().

const purseBrand = quatloosPurse.getAllegedBrand();