Skip to main content

Royalties

Nifty Asset offers the ability to encode royalty enforcement directly into its transfer instruction using the Royalties extension, where creators can specify transfer constraints and royalties percentage.

The royalty extension uses a system of composable Constraints to create restrictions such as an allow or deny lists — these can be used to include or exclude specific programs as valid owners of asset accounts, preventing tranferring them.

The extension consists of:

info

Royalties constraints are validated on transfer and the transfer will only be completed if the validation is successful.

Constraints

Constraints are a way to enforce rules on the asset. They are composable and can be combined to create complex rules. The following constraints are available:

And

The And constraint is a composite contraint that requires all of its sub-contraints to pass.

Example:

{
"type": "And",
"constraints": [
{
"type": "OwnedBy",
"account": "Recipient",
"owners": ["11111111111111111111111111111111"]
},
{
"type": "PubkeyMatch",
"account": "Recipient",
"pubkeys": ["CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8"]
}
]
}

This constraint requires the recipient to be owned by the System Program (program address 11111111111111111111111111111111) and transferred to a specific public key (CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8). This simple example could be used to enforce that the asset can only be transferred to a specific address owned by a specific program.

Or

The Or constraint is a composite contraint that requires at least one of its sub-contraints to pass.

Example:

{
"type": "Or",
"constraints": [
{
"type": "OwnedBy",
"account": "Recipient",
"owners": ["11111111111111111111111111111111"]
},
{
"type": "PubkeyMatch",
"account": "Recipient",
"pubkeys": ["CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8"]
}
]
}

This constraint requires the recipient to be owned by the System Program (program address 11111111111111111111111111111111) or transferred to a specific public key (CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8). This simple example could be used to enforce that the asset can only be transferred to a specific address or any other address owner by a specific program.

Not

The Not constraint is a composite contraint that requires its sub-constraint to fail — it inverts the result of it.

Example:

{
"type": "Not",
"constraint": {
"type": "OwnedBy",
"account": "Recipient",
"owners": ["11111111111111111111111111111111"]
}
}

This constraint requires the recipient to not be owned by the System Program (program address 11111111111111111111111111111111).

Empty

The Empty constraint is a placeholder constraint that always passes.

Example:

{
"type": "Empty"
}

PubkeyMatch

The PubkeyMatch constraint requires the specified account to match one of the public keys in its list.

Example:

{
"type": "PubkeyMatch",
"account": "Asset",
"pubkeys": ["CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8"]
}

This simple example restricts transfers to a single specific asset public key (CcSZHtdnHTcW4En23vJfmXxhZceoAfZnAjc8kYvherJ8). Any other asset with a different public key cannot be transferred.

OwnedBy

The OwnedBy constraint requires that the specified account is owned by one of the specified public keys (address of a program).

Example:

{
"type": "OwnedBy",
"account": "Recipient",
"pubkeys": ["11111111111111111111111111111111"]
}

In this example, the recipient account in the transfer must be owned by the System program (11111111111111111111111111111111).

Adding Royalties

The Royalties extension can be created using either the allocate, create or update instructions.

import { allocate, royalties } from '@nifty-oss/asset';

const constraint = {
type: 'OwnedBy',
account: 'Recipient',
owners: [
publicKey('11111111111111111111111111111111'),
],
};
// 5% royalty fee
const basisPoints = 500;

await allocate(umi, {
asset,
payer,
extension: royalties(basisPoints, constraint),
}).sendAndConfirm(umi);
tip

You can specify your constraints using a JSON syntax:

const constraint: Constraint = JSON.parse(
'{ \
"type": "OwnedBy", \
"account": "Recipient", \
"pubkeys": ["11111111111111111111111111111111"] \

}'
);

Fetching Royalties

Given an asset account, it is possible to retrieve the royalties of an asset. Note that not all assets might have the extension, therefore it is necessary to assert if the extension was found.

import {
ExtensionType,
fetchAsset,
getExtension
} from '@nifty-oss/asset';

const asset = await fetchAsset(umi, address);
const royalties = getExtension(asset, ExtensionType.Royalties);

if (royalties) {
console.log('basisPoint=', royalties.basisPoint);
console.log('constraint=', royalties.constraint);
}