Add a built-in and automatic “Trust Limit” control for issuers

190 views
Skip to first unread message

Kuknos Core Team

unread,
Mar 8, 2021, 10:09:25 AM3/8/21
to Stellar Developers

As said in issue #85, some financial institutions need to set the maximum amount of asset that can be owned by a holder. Although asset issuers can enforce this kind of limitation by manually checking “Trust Limit” value requested in the “Change Trust” operation (using authorization and “Allow Trust” operation); We propose using an automated and built-in solution, which could help issuers to preventively control maximum asset balance for each account. This would provide a simple use and built-in “Trust Limit” control mechanism.
The steps of this mechanism are as following:

  • The issuer should set a “Data Entry”, that points to the corresponding asset and represents the maximum amount of the asset that can be owned by an account.

    • We name this “Data Entry” as “Asset Limit”.

    • “Asset Limit” key name, should be defined by convention. We propose using ASSETCODE + “_limit”.

    • “Asset Limit” value is the maximum number of the asset that can be owned by the holder.

  • “Change Trust” operation should check the existence of “Asset Limit” in the issuer account.

  • If “Asset Limit” exists, the operation would make sure the “Trust Limit” requested by the user is less than or equal to “Asset Limit”. Otherwise, the operation is rejected.

Code:

/// This function is called at the end of doApply() function. And checks the asset limit validation.
bool ChangeTrustOpFrame::doCheckAssetLimit(AbstractLedgerTxn& ltx, AccountID const& issuerID){
     std::string assetCode = "";
     if (mChangeTrust.line.type() == ASSET_TYPE_CREDIT_ALPHANUM4){
          assetCodeToStr(mChangeTrust.line.alphaNum4().assetCode, assetCode);
     }else if (mChangeTrust.line.type() == ASSET_TYPE_CREDIT_ALPHANUM12){
          assetCodeToStr(mChangeTrust.line.alphaNum12().assetCode, assetCode);
     }
     auto const& assetLimitKey = assetCode + "_limit";
     LedgerTxnEntry const& limitEntry =
     stellar::loadData(ltx, issuerID, assetLimitKey);
     if (limitEntry){
          std::string limitValueStr = "";
          auto const& limitValue = limitEntry.current().data.data().dataValue;
          for (int i = 0; i < limitValue.size(); i++){
               limitValueStr += (char(limitValue[i]));
          }
          CLOG(ERROR, "Tx") << "check limit: " <<  assetLimitKey << ", value: " << limitValueStr << ". Requested: " << mChangeTrust.limit;
          unsigned long long assetLimit = 0;
          try{
               assetLimit = std::stoull(limitValueStr);
          }catch (std::exception& cerr){
               CLOG(ERROR, "Tx") << "check limit: " << cerr.what();
          }
          if (assetLimit > 0 && assetLimit < mChangeTrust.limit){
               return false;
          }
     }
     return true;
}

Jonathan Jove

unread,
Mar 8, 2021, 10:49:02 AM3/8/21
to Kuknos Core Team, Stellar Developers
Can you tell us more about the business issue you are facing? Following up with some of the comments from https://github.com/stellar/stellar-protocol/issues/85:

- Do you really need to control only the limit, or do you need other controls such as the amount sent/received?
- Why are the functionalities that were enabled by https://github.com/stellar/stellar-protocol/blob/master/core/cap-0018.md insufficient to achieve your goals?

--
You received this message because you are subscribed to the Google Groups "Stellar Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to stellar-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/stellar-dev/74969b18-a47c-4f86-a2ae-2d8111496122n%40googlegroups.com.

Kuknos Core Team

unread,
Mar 9, 2021, 3:13:12 PM3/9/21
to Stellar Developers

Thanks for the reply.

A simple business sample:

Suppose that a company wants to supply its shares to the market. A management policy of the company is that no shareholder could have more than 50 percent of the company’s shares. If the company decides to use Stellar to implement this solution, it would issue 100 tokens (for example) of an asset that each of them represents one percent of the company’s shares. but there is no way to enforce this policy automatically, using a built-in mechanism.

In addition, 

  • The company needs to announce the limit to everyone that wants to buy the shares. 

  • The company should commit to shareholders that no shareholder is able to own more than 50 percent of the shares. So no shareholder is concerned about other shareholders owning more than 50 percent of the company’s share.

As a description for the proposed solution:

  • Existence of the “Asset Limit” data entry would play the role of the announcement. 

  • The built-in limit checking process that is done in the extended “Change Trust” operation, is the passive commitment of the issuer to shareholders.

In addition, the built-in limit checking would help the issuer to easily manage this enforcement. Instead of checking every “Change Trust” operation and validating the requested limit by the user, the “Asset Limit” would be defined once and the limit control would be done by the network automatically. This would reduce the “Change Trust” authorization processing load on the issuer node and also prevents any mistake that may occur during the limit checking process on the issuer node.

The answer to the first question:

3 following feature is needed:

  • Issuer needs to control the asset limit automatically.

  • Issuer needs to announce the limit to everyone.

  • Issuer should commit to everyone that the announced limit is enforced for every account.

No other controls such as amount sent/received are needed.

The answer to the second question:

The CAP18 is introducing a way that issuer could control everything. this is not our need, issuer wants that the authorized asset holder to be free for everything, except owning the tokens more than an announced limit. The issuer wants to enforce this limit automatically.

Also, there is no way of representing the issuer’s commitment that demonstrates this limit would be enforced for every asset holder.

Leigh McCulloch

unread,
Mar 10, 2021, 2:10:27 PM3/10/21
to Stellar Developers
I suspect that even if there was a limit control placed on trustlines of accounts, users could still find ways to conceptually hold more than the limit. The reason for that is any user could circumvent the limit by moving an amount of the asset into a Claimable Balance that is only claimable by them. Or any user could create a second account, and move an amount of the asset into that second account.

Kuknos Core Team

unread,
Mar 15, 2021, 9:26:52 AM3/15/21
to Stellar Developers

Issuer should use authorization to prevent any asset holder from having more than one account.

“Claimable Balance” is the problem that puts this method under question. We are working on providing some better solutions. One of those would be extending CAP18 solution, by adding a flag to authorization flags, named AUTHORIZED_FOR_LIMTIED_BALANCE that would be used to resolve this issue.

Any other idea or hint would be appreciated.

Nicolas Barry

unread,
Mar 15, 2021, 8:02:17 PM3/15/21
to Kuknos Core Team, Stellar Developers
CAP18 allows to address exactly this kind of situation: enforcing arbitrary limits on assets (be limits on balance or transfer per unit of time like daily limits etc) that are specific to some tokens without having to over time add more and more complicated logic in the core layer.

If you're trying to standardize on which limits can be placed on assets, the best place to start is at the SEP layer.

Nicolas



Kuknos Core Team

unread,
Mar 25, 2021, 10:12:37 AM3/25/21
to Stellar Developers

Thanks for the replies.

After some checks and discussions on our use-cases, we ended up with the following problem  that can not be solved using CAP18:

  • The issuer just wants to issue an asset that has the so-called balance limit. 

  • The issuer does not want to bother himself anymore and does not want to actively control all the transactions of the issued asset.

  • The issuer even does not want to use authorization flag, the issuer is sure that every account belongs to a different person using a KYC mechanism.


One reason for the issuer unwillingness to actively control the asset, is that the issuer account is a multi-signature account that is actually locked after issuing the asset. No other operation on the issuer account is possible due to financial and security policies, so the CAP 18 can not be used here.


Is there any solution for the above problem?

Jonathan Jove

unread,
Mar 25, 2021, 10:27:10 AM3/25/21
to Kuknos Core Team, Stellar Developers
> The issuer even does not want to use authorization flag, the issuer is sure that every account belongs to a different person using a KYC mechanism.

I was wondering if you could provide some more context on how this is expected to work? If the issuer does not use AUTH_REQUIRED_FLAG, then any account can create a trust line and hold the asset. For example, suppose that you verified the identity of people P and Q and issued each of them 100 X (X represents your asset) which is the maximum balance you permit. Then P creates another account and convinces Q to send that account 100 X. Now P owns 200 X, which violates your policy, even though you verified the identities of both P and Q. I don't see how you can avoid this situation without using the AUTH_REQUIRED_FLAG.

> No other operation on the issuer account is possible due to financial and security policies, so the CAP 18 can not be used here.

One thing that might be of interest to you here is that different operations have different signature requirements. AllowTrust (used in CAP-0018) is low threshold. Most other operations are medium or high threshold. So it is possible to disallow higher threshold operations while still taking advantage of CAP-0018.

Kuknos Core Team

unread,
Apr 6, 2021, 6:51:11 AM4/6/21
to Stellar Developers

There exists a way that issuer could use CAP18 to manage this problem. But this is not a good solution.

Issuer just wants to enforce a single policy. The only solution here is to use CAP18, which enables the issuer to control everything. Issuer just wants to control a single thing and it should be able to control only that thing.

We are facing some other problems like this in other scenarios, for example, an issuer just wants to issue an asset that is not allowed to be used in Claimable Balance operations. Or the issuer just wants to issue an asset that is not allowed to be traded on DEX. the only existing solution here is to use CAP18. Which is a centralized way of processing asset transactions (all the transactions are centered on the issuer sign). that is inconsistent with blockchain distributed processing concept.

The issuer wants to disable some features on the asset without having any permissions to influence other features.

We want issuer to be able to set the following features for an asset:

  • The asset is claimable or not.

  • The asset is tradable or not.

  • The asset is NFT or not.

  • Set a maximum balance limit for the asset holder.

One solution here is to implement a mechanism that sets some property for the issued asset at the asset creation time, as said here. After setting the asset property by the issuer, a built-in mechanism would apply the policies on the blockchain. We can add some flags to Change Trust operation that would set the asset property.
Reply all
Reply to author
Forward
0 new messages