Royalty Enforcement Specification | Algorand Developer Portal
Royalty Enforcement Specification
Abstract
A specification to describe a set of methods that offer an API to enforce Royalty Payments to a Royalty Receiver given a policy describing the royalty shares, both on primary and secondary sales.
This is an implementation of an ARC-20 specification and other methods may be implemented in the same contract according to that specification.
Motivation
This ARC is defined to provide a consistent set of asset configurations and ABI methods that, together, enable a royalty payment to a Royalty Receiver. An example may include some music rights where the label, the artist, and any investors have some assigned royalty percentage that should be enforced on transfer. During the sale transaction, the appropriate royalty payments should be included or the transaction must be rejected.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 822.
- Royalty Policy - The name for the settings that define how royalty payments are collected.
- Royalty Enforcer - The application that enforces the royalty payments given the Royalty Policy and performs transfers of the assets.
- Royalty Enforcer Administrator - The account that may call administrative level methods against the Royalty Enforcer.
- Royalty Receiver - The account that receives the royalty payment. It can be any valid Algorand account.
- Royalty Basis - The share of a payment that is due to the Royalty Receiver.
- Royalty Asset - The ASA that should have royalties enforced during a transfer.
- Asset Offer - A data structure stored in local state for the current owner representing the number of units of the asset being offered and the authorizing account for any transfer requests.
- Third Party Marketplace - A third party marketplace may be any marketplace that implements the appropriate methods to initiate transfers.
Royalty Policy
interface RoyaltyPolicy {
royalty_basis: number // The percentage of the payment due, specified in basis points (0-10,000)
royalty_recipient: string // The address that should collect the payment
}
A Royalty Share consists of a royalty_receiver that should receive a Royalty payment and a royalty_basis representing some share of the total payment amount.
Royalty Enforcer
The Royalty Enforcer is an instance of the contract, an Application, that controls the transfer of ASAs subject to the Royalty Policy. This is accomplished by exposing an interface defined as a set of ABI Methods allowing a grouped transaction call containing a payment and a Transfer request.
Royalty Enforcer Administrator
The Royalty Enforcer Administrator is the account that has privileges to call administrative actions against the Royalty Enforcer. If one is not set the account that created the application MUST be used. To update the Royalty Enforcer Administrator the Set Administrator method is called by the current administrator and passed the address of the new administrator.
Royalty Receiver
The Royalty Receiver is a generic account that could be set to a Single Signature, a Multi Signature, a Smart Signature, or even to another Smart Contract. The Royalty Receiver is then responsible for any further royalty distribution logic, making the Royalty Enforcement Specification more general and composable.
Royalty Basis
The Royalty Basis is value representing the percentage of the payment made during a transfer that is due to the Royalty Receiver. The Royalty Basis MUST be specified in terms of basis points.
Royalty Asset
The Royalty Asset is an ASA subject to royalty payment collection and MUST be created with the appropriate parameters.
Because the protocol does not allow updating an address parameter after it’s been deleted, if the asset creator thinks they may want to modify them later, they must be set to some non-zero address.
Asset Offer
The Asset Offer is a data structure stored in the owner’s local state. It is keyed in local storage by the byte string representing the ASA Id.
interface AssetOffer {
auth_address: string // The address of a marketplace or account that may issue a transfer request
offered_amount: number // The number of units being offered
}
This concept is important to this specification because we use the clawback feature to transfer the assets. Without some signal that the current owner is willing to have their assets transferred, it may be possible to transfer the asset without their permission.
Royalty Asset Parameters
The Clawback parameter MUST be set to the Application Address of the Royalty Enforcer.
Since the Royalty Enforcer relies on using the Clawback mechanism to perform the transfer the Clawback should NEVER be set to the zero address. The Freeze parameter MUST be set to the Application Address of the Royalty Enforcer if
FreezeAddr != ZeroAddress, else set toZeroAddress. If the asset creator wants to allow an ASA to be Royalty Free after some conditions are met, it should be set to the Application Address. The Manager parameter MUST be set to the Application Address of the Royalty Enforcer ifManagerAddr != ZeroAddress, else set toZeroAddress. If the asset creator wants to update the Freeze parameter, this should be set to the application address. The Reserve parameter MAY be set to anything. TheDefaultFrozenMUST be set to true.
Third Party Marketplace
In order to support secondary sales on external markets this spec was designed such that the Royalty Asset may be listed without transferring it from the current owner’s account. A Marketplace may call the transfer request as long as the address initiating the transfer has been set as the auth_address through the offer method in some previous transaction by the current owner.
ABI Methods
The following is a set of methods that conform to the ABI specification meant to enable the configuration of a Royalty Policy and perform transfers. Any Inner Transactions that may be performed as part of the execution of the Royalty Enforcer application SHOULD set the fee to 0 and enforce fee payment through fee pooling by the caller.
Set Administrator:
set_administrator(
administrator: address,
)
Sets the administrator for the Royalty Enforcer contract. If this method is never called the creator of the application MUST be considered the administrator. This method SHOULD have checks to ensure it is being called by the current administrator.
Set Policy:
set_policy(
royalty_basis: uint64,
royalty_recipient: account,
)
Sets the policy for any assets using this application as a Royalty Enforcer. The royalty_basis is the percentage for royalty payment collection, specified in basis points (e.g., 1% is 100). A Royalty Basis SHOULD be immutable; if an application call is made that would overwrite an existing value, it SHOULD fail.
Set Payment Asset:
set_payment_asset(
payment_asset: asset,
allowed: boolean,
)
The payment_asset argument represents the ASA id that is acceptable for payment. The contract logic MUST opt into the asset specified in order to accept them as payment as part of a transfer.
Transfer:
transfer_algo_payment(
royalty_asset: asset,
royalty_asset_amount: uint64,
from: account,
to: account,
royalty_receiver: account,
payment: pay,
current_offer_amount: uint64,
)
And
transfer_asset_payment(
royalty_asset: asset,
royalty_asset_amount: uint64,
from: account,
to: account,
royalty_receiver: account,
payment: axfer,
payment_asset: asset,
current_offer_amount: uint64,
)
Transfers the Asset after checking that the royalty policy is adhered to. The royalty_asset is the ASA ID to be transferred. The from parameter is the account the ASA is transferred from. The to parameter is the account the ASA is transferred to.
Read Only Methods
Get Policy:
get_policy()(address,uint64)
Gets the current Royalty Policy setting for this Royalty Enforcer. The return value is a tuple of type (address,uint64).
Get Offer:
get_offer(
royalty_asset: asset,
from: account,
)(address,uint64)
Gets the current Asset Offer for a given asset as set by its owner.
Get Administrator:
get_administrator()address
Gets the Royalty Enforcer Administrator set for this Royalty Enforcer. The return value is of type address representing the account that may call administrative methods.
Storage
While the details of storage are described here, readonly methods are specified to provide callers with a method to retrieve the information without having to write parsing logic. The exact location and encoding of these fields are left to the implementer.
Global Storage
The parameters that describe a policy are stored in Global State. The relevant keys are:
royalty_basis - The percentage specified in basis points of the payment.
royalty_receiver - The account that should be paid the royalty.
Local Storage
For an offered Asset, the authorizing address and amount offered should be stored in a Local State field for the account offering the Asset.
Full ABI Spec
{
"name": "ARC18",
"methods": [
{
"name": "set_policy",
"args": [
{
"type": "uint64",
"name": "royalty_basis"
},
{
"type": "address",
"name": "royalty_receiver"
}
],
"returns": {
"type": "void"
},
"desc": "Sets the royalty basis and royalty receiver for this royalty enforcer"
},
{
"name": "get_policy",
"args": [],
"returns": {
"type": "(address,uint64)"
},
"read-only": true
}
],
"desc": "ARC18 Contract providing an interface to create and enforce a royalty policy over a given ASA, See https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0018.md for details.",
"networks": {}
}
Rationale
The motivation behind defining a Royalty Enforcement specification is the need to guarantee a portion of a payment is received by select royalty collector on sale of an asset. The use of a smart contract as a clawback address is a guaranteed way to know an asset transfer is only ever made when certain conditions are met.
Copyright
Copyright and related rights waived via CCO.