# Issuers and Mints
# Issuers
Note: You should not create an Issuer in a deploy script. Deploy scripts are ephemeral, so any object created there dies as soon as the script stops.
Behind the scenes, an issuer
maps minted digital assets to their location in a purse
or payment
. An issuer
verifies, moves, and manipulates digital assets.
Its special admin facet is a mint
which it has a one-to-one
relationship with. Only a mint
can issue new digital assets; an issuer
cannot.
An issuer
also has a one-to-one relationship with a brand
. So, if
our brand
is the imaginary currency Quatloos, only
the issuer
in the one-to-one relationship with the Quatloos brand
can:
- Create a new empty
purse
that can store Quatloos. - Manipulate a
payment
in Quatloos to be claimed, split, combined, burned, or have its amount gotten.
An issuer
should be obtained from a trusted source and
then relied upon as the authority as to whether an untrusted payment
of the same brand
is valid.
Issuer
methods:
- Return information about an
issuer
. - Create a new
issuer
. - Create a new
purse
. - Operate on
payment
arguments.
The following is
a brief description and example of each Issuer
method. For
more detail, click the method's name to go to its entry in the ERTP
API Reference.
- Create issuer operation
Makes an
issuer
and its relatedmint
andbrand
. Returns{ mint, issuer, brand }
Themint
andbrand
are in unchangeable one-to-one relationships with theissuer
and each other.The
allegedName
is available from thebrand
to describe assets, but should not be trusted.assetKind
specifies if the associated asset is of kindAssetKind.NAT
(nat
) (the default value) orAssetKind.SET
(set
); see theAmountMath
page for details.displayInfo
is the number of places to the right of the decimal point to display of anyvalues
associated with the createdbrand
. It defaults toundefined
import { AmountMath, makeIssuerKit, AssetKind } from '@agoric/ertp';
const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand, } = makeIssuerKit('quatloos'); // This is merely an amount, describing assets. // It does not create new assets. const quatloos2 = AmountMath.make(quatloosBrand, 2n); // Non-fungible asset, which needs an AssetKind // of AssetKind.SET const { mint: titleMint, issuer: titleIssuer } = makeIssuerKit( 'alamedaCountyPropertyTitle', AssetKind.SET, );
- Get information about the issuer operations
issuer.getBrand()
- Returns the
brand
theissuer
is in a one-to-one relationship with. Thebrand
is not closely held, so it can be used by fake digital assets andamounts
. Do not trust this method alone to ensure theissuer
has the rightbrand
. const { issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit( 'quatloos', ); // myQuatloosBrand === quatloosBrand const myQuatloosBrand = quatloosIssuer.getBrand();
- Returns the
issuer.getAllegedName()
- Returns the
issuer
/mint
'sallegedName
, the non-trusted human-readable name of theissuer
's associatedbrand
. const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName(); // quatloosIssuerAllegedName === 'quatloos'
- Returns the
issuer.getAssetKind()
- Get the kind of asset for this
issuer
, eitherAssetKind.NAT
(nat
), orAssetKind.SET
(set
). const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); const kind = quatloosIssuer.getAssetKind(); // 'nat', the default value for makeIssuerKit()
- Get the kind of asset for this
- Purse operation
issuer.makeEmptyPurse()
- Returns a new empty
purse
for thebrand
associated with theissuer
. Thepurse
only accepts valid deposits of its associatedbrand
, so you can retroactively identify a validpayment
of thatbrand
by successfully depositing it into thispurse
. const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); // The new empty purse contains 0 Quatloos const quatloosPurse = quatloosIssuer.makeEmptyPurse();
- Returns a new empty
- Payment operations
-
- Returns the
payment
balance, anamount
. Using theissuer
rather than thepayment
lets us trust the result even if someone we do not trust sent us thepayment
. const quatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 100n), ); // returns an amount with a value of 100 and the quatloos brand quatloosIssuer.getAmountOf(quatloosPayment);
- Returns the
issuer.burn(payment, optAmount)
- Burns (destroys) all of the
payment
argument's digital assets and deletes all mention of thepayment
from theissuer
. If optional argumentoptAmount
is present, thepayment
balance must be equal tooptAmount
's value. Ifpayment
is a promise, the operation happens after the promise resolves. Returns the value of the burnedpayment
. const amountToBurn = AmountMath.make(quatloosBrand, 10n); const paymentToBurn = quatloosMint.mintPayment(amountToBurn); // burntAmount is 10 quatloos const burntAmount = await quatloosIssuer.burn(paymentToBurn, amountToBurn);
- Burns (destroys) all of the
issuer.claim(payment, optAmount)
- Transfer all digital assets from the
payment
argument to a newpayment
and burn the original so no other references to thispayment
survive. Returns the newpayment
If optional argumentoptAmount
is present, thepayment
balance must be equal tooptAmount
's balance, otherwise it throws an error. Ifpayment
is a promise for a payment, the operation happens after the promise resolves. const amountToTransfer = AmountMath.make(quatloosBrand, 2n); const originalPayment = quatloosMint.mintPayment(amountToTransfer); const newPayment = await quatloosIssuer.claim( originalPayment, amountToTransfer, );
- Transfer all digital assets from the
-
- Combine multiple
payments
into onepayment
. If anypayment
inpaymentsArray
is a promise for a payment, the operation happens after all promises resolve. Everypayment
is burned except for the returned one. If you try to combinepayments
of differentbrands
, it throws an exception and eachpayment
is unaffected. // create an array of 100 payments of 1 unit each const payments = []; for (let i = 0; i < 100; i += 1) { payments.push(quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1n))); } // combinedPayment equals 100 const combinedPayment = quatloosIssuer.combine(harden(payments));
- Combine multiple
issuer.split(payment, paymentAmountA
)- Split a single
payment
into two newpayments
, A and B, according to thepaymentAmountA
argument's value. In other words, the result has A equal topaymentAmountA
and B equal to the originalpayment
minuspaymentAmountA
. The originalpayment
argument is burned. If the originalpayment
is a promise, the operation happens when the promise resolves. const oldPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 30n), ); const [paymentA, paymentB] = await quatloosIssuer.split( oldPayment, AmountMath.make(quatloosBrand, 10n), ); // paymentA is 10 quatloos, payment B is 20 quatloos.
- Split a single
issuer.splitMany(payment, paymentAmountArray)
- Returns multiple
payments
in an array from splitting its singlepayment
argument. The resulting number ofpayments
is specified as the length of thepaymentAmountArray
argument, with the newly splitpayments
havingamounts
corresponding to those inpaymentAmountArray
. If thepaymentAmountArray
argumentamounts
don't add up to thevalue
of thepayment
argument, the operation fails. If the operation is successful, the originalpayment
is burned. If the operation fails, the originalpayment
is not burned. const oldQuatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 100n), ); const goodQuatloosAmounts = Array(10).fill( AmountMath.make(quatloosBrand, 10n), ); const arrayOfNewPayments = await quatloosIssuer.splitMany( oldQuatloosPayment, harden(goodQuatloosAmounts), ); // Note that the total amount in the amountArray must equal the // amount in the original payment, in the above case, 100 Quatloos in each. const anotherQuatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 1000n), ); // total amounts in badQuatloosAmounts equal 20, when it should equal 1000 const badQuatloosAmounts = Array(2).fill(AmountMath.make(quatloosBrand, 10n)); // throws error t.throwsAsync( () => quatloosIssuer.splitMany( anotherQuatloosPayment, harden(badQuatloosAmounts), ), { message: /rights were not conserved/ }, );
- Returns multiple
-
- Returns
true
if thepayment
argument is still active (i.e. has not been used or burned and was issued by thisissuer
). Ifpayment
is a promise, the operation happens on its resolution. const isItLive = quatloosIssuer.isLive(payment);
- Returns
-
Related Methods:
Note: None of these methods return a canonical result. If the issuer
itself doesn't acknowledge that
the mint
, brand
or purse
are associated with it, then they're invalid. These methods help you find
the right issuer
, but aren't authoritative.
mint.getIssuer()
- Return the associated
issuer
for themint
. const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit( 'quatloos', ); const quatloosMintIssuer = quatloosMint.getIssuer(); // returns true const sameIssuer = quatloosIssuer === quatloosMintIssuer;
- Return the associated
brand.isMyIssuer(issuer)
- Returns
true
if thebrand
comes from thisissuer
. const isIssuer = quatloosBrand.isMyIssuer(quatloosIssuer);
- Returns
# Mints
A mint
issues new digital assets of its associated brand
as a new
payment
object. These assets may be currency-like (our imaginary
Quatloos currency), goods-like valuables (magic swords for games), or
electronic rights (the right to participate in a contract). Only a
holder of a mint
object can create new assets from it.
In other words, let's say there
are 1000 Quatloos in circulation. Only holders of the Quatloos associated
mint
can make any more Quatloos that'd boost the amount in circulation to, say, 2000.
Since these relationships are one-to-one and unchangeable:
- A
mint
created to make an assetbrand
, say Quatloos, can only create thatbrand
asset. For example, only Quatloos, not Moola or anything else. - A
mint
that creates an assetbrand
is the onlymint
that can create thatbrand
. Only the one Quatloosmint
can create new Quatloos. - A
mint
that creates an assetbrand
can never be changed to create a differentbrand
. So a Quatloosmint
can never become a Moolamint
, or any other non-Quatloos asset.
There are two mint
methods, and the method that creates new mints. Click the method's name to go to its entry in the ERTP
API Reference.
mint.getIssuer()
- Returns the
issuer
uniquely associated with themint
. const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit( 'quatloos', ); const quatloosMintIssuer = quatloosMint.getIssuer(); // returns true const sameIssuer = quatloosIssuer === quatloosMintIssuer;
- Returns the
mint.mintPayment(newAmount)
Returns a new
payment
containing newly minted assets with a balance equal tonewAmount
. In other words, it mintsnewAmount
of digital assets and creates apayment
to hold those new assets. The assets are of themint
's associatedbrand
.Important:
mint.mintPayment()
is the only way in ERTP to create new digital assets. There is no other way. The Zoe Contract Facet (zcf
) can also create a mint in Zoe that can create new digital assets.const { mint: quatloosMint, brand: quatloosBrand } = makeIssuerKit( 'quatloos', ); const quatloos1000 = AmountMath.make(quatloosBrand, 1000n); const newPayment = quatloosMint.mintPayment(quatloos1000);
makeIssuerKit(allegedName, assetKind, displayInfo)
- While not a method called on a
mint
, clearly you should know how to create a newmint
.makeIssuerKit()
returns a newissuer
,mint
, andbrand
. import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; // #region import import { AmountMath, makeIssuerKit, AssetKind } from '@agoric/ertp'; // #endregion import test('ertp guide issuers and mints makeIssuerKit', async t => { // #region makeIssuerKit const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand, } = makeIssuerKit('quatloos'); // This is merely an amount, describing assets. // It does not create new assets. const quatloos2 = AmountMath.make(quatloosBrand, 2n); // Non-fungible asset, which needs an AssetKind // of AssetKind.SET const { mint: titleMint, issuer: titleIssuer } = makeIssuerKit( 'alamedaCountyPropertyTitle', AssetKind.SET, ); // #endregion makeIssuerKit t.truthy(quatloosIssuer); t.truthy(quatloosMint); t.truthy(quatloosBrand); t.deepEqual(quatloos2, { brand: quatloosBrand, value: 2n }); t.truthy(titleMint); t.truthy(titleIssuer); }); test('ertp guide issuers and mints getBrand', async t => { // #region getBrand const { issuer: quatloosIssuer, brand: quatloosBrand } = makeIssuerKit( 'quatloos', ); // myQuatloosBrand === quatloosBrand const myQuatloosBrand = quatloosIssuer.getBrand(); // #endregion getBrand t.is(quatloosBrand, myQuatloosBrand); }); test('ertp guide issuers and mints getAllegedName', async t => { // #region getAllegedName const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); const quatloosIssuerAllegedName = quatloosIssuer.getAllegedName(); // quatloosIssuerAllegedName === 'quatloos' // #endregion getAllegedName t.is(quatloosIssuerAllegedName, 'quatloos'); }); test('ertp guide issuers and mints getAssetKind', async t => { // #region getAssetKind const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); const kind = quatloosIssuer.getAssetKind(); // 'nat', the default value for makeIssuerKit() // #endregion getAssetKind t.is(kind, 'nat'); }); test('ertp guide issuers and mints makeEmptyPurse', async t => { // #region makeEmptyPurse const { issuer: quatloosIssuer } = makeIssuerKit('quatloos'); // The new empty purse contains 0 Quatloos const quatloosPurse = quatloosIssuer.makeEmptyPurse(); // #endregion makeEmptyPurse t.deepEqual(await quatloosPurse.getCurrentAmount(), { brand: quatloosIssuer.getBrand(), value: 0n, }); }); test('ertp guide issuers and mints payment methods', async t => { const { issuer: quatloosIssuer, brand: quatloosBrand, mint: quatloosMint, } = makeIssuerKit('quatloos'); // #region getAmountOf const quatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 100n), ); // returns an amount with a value of 100 and the quatloos brand quatloosIssuer.getAmountOf(quatloosPayment); // #endregion getAmountOf // #region burn const amountToBurn = AmountMath.make(quatloosBrand, 10n); const paymentToBurn = quatloosMint.mintPayment(amountToBurn); // burntAmount is 10 quatloos const burntAmount = await quatloosIssuer.burn(paymentToBurn, amountToBurn); // #endregion burn t.deepEqual(burntAmount, amountToBurn); // #region claim const amountToTransfer = AmountMath.make(quatloosBrand, 2n); const originalPayment = quatloosMint.mintPayment(amountToTransfer); const newPayment = await quatloosIssuer.claim( originalPayment, amountToTransfer, ); // #endregion claim t.deepEqual(await quatloosIssuer.getAmountOf(newPayment), amountToTransfer); t.not(originalPayment, newPayment); // #region combine // create an array of 100 payments of 1 unit each const payments = []; for (let i = 0; i < 100; i += 1) { payments.push(quatloosMint.mintPayment(AmountMath.make(quatloosBrand, 1n))); } // combinedPayment equals 100 const combinedPayment = quatloosIssuer.combine(harden(payments)); // #endregion combine t.deepEqual(await quatloosIssuer.getAmountOf(combinedPayment), { brand: quatloosBrand, value: 100n, }); // #region split const oldPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 30n), ); const [paymentA, paymentB] = await quatloosIssuer.split( oldPayment, AmountMath.make(quatloosBrand, 10n), ); // paymentA is 10 quatloos, payment B is 20 quatloos. // #endregion split const paymentAAmount = await quatloosIssuer.getAmountOf(paymentA); const paymentBAmount = await quatloosIssuer.getAmountOf(paymentB); t.deepEqual(paymentAAmount, AmountMath.make(quatloosBrand, 10n)); t.deepEqual(paymentBAmount, AmountMath.make(quatloosBrand, 20n)); // #region splitMany // #region splitManyConcise const oldQuatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 100n), ); const goodQuatloosAmounts = Array(10).fill( AmountMath.make(quatloosBrand, 10n), ); const arrayOfNewPayments = await quatloosIssuer.splitMany( oldQuatloosPayment, harden(goodQuatloosAmounts), ); // #endregion splitManyConcise // Note that the total amount in the amountArray must equal the // amount in the original payment, in the above case, 100 Quatloos in each. const anotherQuatloosPayment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 1000n), ); // total amounts in badQuatloosAmounts equal 20, when it should equal 1000 const badQuatloosAmounts = Array(2).fill(AmountMath.make(quatloosBrand, 10n)); // throws error t.throwsAsync( () => quatloosIssuer.splitMany( anotherQuatloosPayment, harden(badQuatloosAmounts), ), { message: /rights were not conserved/ }, ); // #endregion splitMany t.is(arrayOfNewPayments.length, 10); t.deepEqual(await quatloosIssuer.getAmountOf(arrayOfNewPayments[0]), { value: 10n, brand: quatloosBrand, }); const payment = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 100n), ); // #region isLive const isItLive = quatloosIssuer.isLive(payment); // #endregion isLive t.truthy(isItLive); // #region getIssuer const quatloosMintIssuer = quatloosMint.getIssuer(); // returns true const sameIssuer = quatloosIssuer === quatloosMintIssuer; // #endregion t.truthy(sameIssuer); // #region isMyIssuer const isIssuer = quatloosBrand.isMyIssuer(quatloosIssuer); // #endregion isMyIssuer t.truthy(isIssuer); }); test('ertp guide issuers and mints mint.getIssuer', async t => { // #region mintGetIssuer const { issuer: quatloosIssuer, mint: quatloosMint } = makeIssuerKit( 'quatloos', ); const quatloosMintIssuer = quatloosMint.getIssuer(); // returns true const sameIssuer = quatloosIssuer === quatloosMintIssuer; // #endregion mintGetIssuer t.truthy(sameIssuer); }); test('ertp guide issuers and mints mint.mintPayment', async t => { // #region mintMintPayment const { mint: quatloosMint, brand: quatloosBrand } = makeIssuerKit( 'quatloos', ); const quatloos1000 = AmountMath.make(quatloosBrand, 1000n); const newPayment = quatloosMint.mintPayment(quatloos1000); // #endregion mintMintPayment const issuer = quatloosMint.getIssuer(); t.truthy(issuer.isLive(newPayment)); }); test('ertp guide mints makeIssuerKit', async t => { // #region makeIssuerKitMint const { issuer: quatloosIssuer, mint: quatloosMint, brand: quatloosBrand, } = makeIssuerKit('quatloos'); // Mint a new 2 Quatloos payment const paymentQuatloos2 = quatloosMint.mintPayment( AmountMath.make(quatloosBrand, 2n), ); // #endregion makeIssuerMint t.truthy(quatloosIssuer.isLive(paymentQuatloos2)); t.truthy(quatloosIssuer); t.truthy(quatloosMint); t.truthy(quatloosBrand); });
- While not a method called on a