Royalties with Soroban Smart Contracts: An Interoperable On-Chain Solution
Tags: nft, web3, royalties, soroban
Published: 2023-12-29 17:19:39

Returning for the second article in our series, this time we are tackling royalties and on-chain payment enforcements.

Royalties play a pivotal role in digital economies, yet the web3 industry still faces many challenges in implementing decentralized royalty payments.

Two key issues stand out:

- **Centralized control**: Echoing Web2, NFT marketplaces maintain significant control over royalty payments. The issues arising from optional royalties ([EIP-2981](https://eips.ethereum.org/EIPS/eip-2981)) were discussed during our session on the [Future of NFT](https://twitter.com/LitemintHQ/status/1581565573112401925) at Meridian 2022 in Rome—far-reaching implications for both builders and creators and still a lot of work needed here.
- **Narrowed markets**: Specialized smart contract solutions, while being decentralized, often constrict sales and cross-chain bridging opportunities for creators and collectors—also impacting the perception of asset ownership. A prime example is OpenSea's recent decision to discontinue their on-chain Operator Filter. [Their blog article](https://opensea.io/blog/articles/creator-fees-update) provides very insightful details into this issue.

In this article, I present a decentralized solution for enforcing royalty payments, simultaneously ensuring that creators and collectors can openly trade their NFTs—anywhere they want (as this series progresses, we'll explore _bridging_ with Soroban in detail).

Leveraging the _first-class citizen_ assets model of [Stellar](https://stellar.org/) and [Soroban](https://soroban.stellar.org/) smart contracts, this solution is being integrated into Litemint ([source on Github](https://github.com/litemint/litemint-soroban-contracts/tree/main/crates/litemint-royalty-contract)).

## How It Works

At its core, the system models an on-chain _**security interest**_ framework, where a Non-Fungible Token (NFT) is the collateral.

Effectively abstracting the NFT property from the royalty payment process, this approach offers two significant advantages:

- **Open and Interoperable**: The royalty smart contract does not need to take custody of or even interact with the NFT asset. This decoupling allows for complete freedom in issuance and transfer (i.e., eliminating the need for [authorization flags](https://developers.stellar.org/docs/issuing-assets/control-asset-access#controlling-access-to-an-asset-with-flags)). Seamless NFT compatibility with all SDEX-based services is maintained.
- **Decentralized and Unobtrusive**: The process for reclaiming ownership is managed autonomously by the smart contract. This setup provides collectors with a transparent guarantee of ownership, provided their royalty payment obligations are fulfilled. Notably, collecting royalties does not require control over the trade execution of NFTs. 

Here's a diagram of the process:

![Sequence diagram royalties](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0slwu1nrpuv0d0tu2hu.png)

As illustrated above, a _repossession lien_ token is issued to the royalty smart contract. The smart contract is designed to transfer the _lien_ to the NFT creator exclusively when royalty payment obligations are not met. The creator can then execute a _lien-dependent_ pre-authorized transaction to reclaim ownership of the asset.

💡 **Tip:** Although several strategies can be implemented with recovery depending on specific use cases (from an `account_merge` operation to a less destructive `re-issuance`), it should be executed atomically with a pre-auth transaction for predictability.

## Understanding Stellar NFTs

Although Stellar provides [recommendations](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0039.md), there is no NFT standard on Stellar. This brings to mind the question posed by Mara Bos, Rust team lead, about the necessity of a Rust standard—[…Do we need one?](https://blog.m-ou.se/rust-standard/).

In the tech world, late arrivals frequently improve upon existing models—they bring effective solutions that simply work. And just like Rust, I see Soroban and Stellar as perfect examples of this.

Contrasting with account-based ledger models like Ethereum, Stellar treats all assets, both native and user-defined, as _first-class abstractions_. This includes NFTs, as we can model _non-fungibility_ through asset properties, eliminating the need for smart contract-based issuance or separate asset classes.

As illustrated below, on Stellar an NFT is just a _regular_ asset with a single stroop supply `amount` and no `signers`. They have similar access to the interoperability layer, including the Layer 1 decentralized exchange (SDEX), cross-currency payments, liquidity pools, and are _de facto_ compatible with any Stellar wallet.

![NFTs are Assets on Stellar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1hgyek8vbtbg0i5qw30.png)

In this ecosystem, using Soroban smart contracts for NFT issuance or trading isn't a prerequisite—thereby avoiding the complexities mentioned previously.

Instead, smart contracts can be effectively leveraged to implement and enforce creators attached _royalty terms_, coupled with a transparent and decentralized ownership recovery process.

> With great _ownership_ comes great responsibility

In the Stellar Ecosystem, as outlined in [SEP-1](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0001.md), the `conditions` field under `[CURRENCIES]` already serves to communicate specific asset conditions for holders. Royalty NFTs can readily take advantage of this field. We are also introducing accessible tools to assist collectors and buyers in managing their obligations, getting notifications for subscriptions and more.

## Getting the Code on GitHub

The code for the Litemint royalty smart contract is located in this [GitHub repo](https://github.com/litemint/litemint-soroban-contracts/) (MIT License).

Besides providing an implementation of the system described above, the smart contract also provides the following features:

- Percentage-based royalty payments (see [compensation_percentage.rs](https://github.com/litemint/litemint-soroban-contracts/blob/master/crates/litemint-royalty-contract/src/agreement/compensation_percentage.rs)).
- Fixed royalty payments (see [compensation_fixed.rs](https://github.com/litemint/litemint-soroban-contracts/blob/master/crates/litemint-royalty-contract/src/agreement/compensation_fixed.rs)).
- Subscription royalty payments (see [compensation_subscription.rs](https://github.com/litemint/litemint-soroban-contracts/blob/master/crates/litemint-royalty-contract/src/agreement/compensation_subscription.rs)).
- Support for all currencies and markets.
- Optional NFT transfer fee.
- Configurable grace period and marketplace commission rate.

💡 **Tip:** The compensation scheme implementation uses the strategy design pattern so you can easily add new ones to fit your requirements.

Go ahead and clone the repository. Then, execute the following command to compile the contract:

```shell
$ soroban contract build
```

## Deployment and Configuration

We assume that the following network and identity are pre-configured (`soroban config`) and funded. Follow [this link](https://soroban.stellar.org/docs/getting-started/setup) if you need instructions.

| Type    | Name    | Description            |
| ------- | ------- | ---------------------- |
| Network | `TESTNET` | Stellar Testnet      |
| Account | `ADMIN`   | Contract admin      |

To deploy the royalty contract, use the following command:

```shell
$ soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/litemint_royalty_contract.wasm \
--source ADMIN --network TESTNET > ID
```
Configure the `ADMIN`. Additionally, the marketplace commission rate is set to 2% with this command:

```shell
$ soroban contract invoke --id $(cat ID) \
--source ADMIN --network TESTNET \
-- initialize --admin ADMIN \
--commission_rate 2
```

## Further Interaction

Until now in this series, we used the **Soroban CLI** to interact with contracts. However, for practical applications, you will likely need to interact via the [stellar-sdk](https://www.npmjs.com/package/stellar-sdk) within your own app, especially if you need to interact with accounts and assets on the Stellar blockchain.

To get you started, the following gist offers a sample script for interacting with the royalty smart contract. It invokes the `add_property` method, passing a `Terms` object that lets you define the NFT and various settings like compensation scheme (fixed, percentage, subscription), grace period, and transfer fees. It also shows how to `execute` the contract and retrieve the updated `License` state.

Don't hesitate to explore further! You can also access the [oracle subscriber](https://dev.to/kyung_jin/oracles-with-soroban-smart-contracts-a-practical-and-flexible-on-chain-framework-f3g) interface. Indeed, the Litemint royalty contract gets market price feeds via oracles on Soroban!

{% gist https://gist.github.com/FredericRezeau/6f9704234417accf29afe523bb863270 %}

## Wrapping Up

Two years back, I wrote this article [NFT Ownership During The Apocalypse](https://blog.litemint.com/nft-ownership-during-the-apocalypse/) discussing how, with the right approach, NFT ownership can remain verifiable—even if Litemint or Stellar disappear!

Likewise, NFT royalty payments should also _work_, sans intermediaries, for years to come. Web3 is all about creating a more open, fairer, less centralized environment, empowering creators to set their own rules for distributing their works.

That's a lot of challenges ahead. However, technologies like Soroban smart contracts provide opportunities to tackle them.

I hope you found this enjoyable! Stay tuned for more detailed tutorials showcasing the full range of [soroban-kit](https://github.com/FredericRezeau/soroban-kit) features!

If you have any questions, don't hesitate to reach out. I'm usually active on [X @FredericRezeau](https://x.com/FredericRezeau) and Discord where you can find me in the [Litemint](https://litemint.gg), [Stellar Global](https://discord.gg/stellar-global-761985725453303838) and [Stellar Developers](https://discord.gg/stellardev) servers!

Feel free to reach out on [GitHub](https://github.com/FredericRezeau) too.

Happy coding!