Invocation model
Maybe just a detail, but we should not need to introduce a new way to have "contractID" (or maybe you meant this to be some extension to what is described in CAP-0047?) - there is a need for core managed contracts, we could just have a special account reserved for "the network" that can be managed like any other core-protocol upgrade.
It may be implemented as a combo WASM + higher privileged host functions (which would allow to share code between "basic" S-ERC20 (Stellar's version of ERC20) reference implementation and this classic interop, or if we have the ability as a "native contract", taking advantage of Rust). This can be modeled as an extension of top of "normal" contracts (from a contract + manifest point of view).
Strong dependency on "S-ERC20".
The problem I see here is that we do not have that base contract defined yet, and this CAP doesn't really go in detail on choices being made here (I suspect that S-ERC20 should be its own SEP).
The contract has some weird things in there: uses generic "String" to manage assets seems like a footgun as Strings are not strongly typed (in JS, Solidity's cousin, it makes sense, but we're trying to be strongly typed with Rust as to catch errors at compile time).
It also inherits some of the security issues from ERC20 (see ERC20 API: An Attack Vector on Approve/TransferFrom Methods - Google Docs ) that we should fix/mitigate.
Allowances
Why are "allowances" implemented differently than what a "basic" S-ERC20 implementation would do (using custom ledger entries)? This depends on what the "auth model" is for ERC20, but I do not see a reason to "one off" this one (I guess this is related to my question around why not sharing the implementation with smart code, we'll surely have a reference implementation).
"NATIVE"
The CAP is very light on how it interfaces with NATIVE, but should be specified.
Re: Issue: Issuer Balance
I think this should always be 0:
regardless of fixed supply or not, I suspect that the main use case for using this balance is to exclude it from "total supply" (which is not really available anyways).
Re: Issue: Not Compatible With High Supply Assets
I do not think this is true as long as you cannot "mint" more than INT64_MAX at a time (I do not see "mint"/"burn" covered in this CAP but we should just not allow to mint more than that number for classic assets to be 100% compatible if we add a mint method).
When interacting with ERC20 tokens, contracts would have to deal with uint256 total supply, which cannot reasonably be reached in INT64_MAX increments.
Re: Issue: Classic Payments To Contracts
I do not understand that section. Which destination address a classic payment would use that would correspond to a smart contract? I do not see this covered in this CAP.
Also I think we should *not* allow to burn/mint with payments using that ERC20 interface.
CAP-0049:
Defines "S-ERC20"
same thing than for CAP-0048, we need to discuss this in detail.
Defines a "compliance interface".
This one seems kind of odd: the requirements around "compliance" in smart seem very fluid. I do not know if the proposed interface meets any specific requirements on that front (the reason they work in "classic" is that we can leave the ledger in a "compliant state" when auth is revoked for example), for a wrapped asset auth revocation would have a different meaning than its classic counterpart. Also for "clawback" to really work, it's not as simple as adding a "clawback" method: this is clearly not enough to make it work with an AMM for example (you would not blindly clawback from the AMM's reserve).
I think we're probably better off iterating outside of the protocol on this aspect.
Usability
Having to keep track of both the classic asset and the wrapped one looks like some serious complexity at that layer (which explodes exponentially as we go higher in the stack).
Compliance
There is the larger question on the consequences of auth revocation: in classic "revoke" implies that the revoked account loses control over that token and the protocol works extra hard to also recover liabilities (offers get cancelled for example) so that things like "clawback" works.
It seems to me that allowing a blanket "bridge" for classic assets may break compliance and we need to discuss this a bit more with the community.
At a minimum, I think we cannot allow to bridge balances that are "clawback enabled" for CAPs (following the precedent from ClaimableBalances).
I *think* that for simple "auth required" assets, things are broken: in today's protocol we cancel offers/pools on auth revocation. If there is a "smart pool", we would not be able to recover the assets locked in that pool. This may be acceptable by the ecosystem.
If this is not acceptable, we'll have to also disallow "auth required" assets to move to smart.
We could do something more complicated in the future to open things up some more:
Allow issuers to "deploy" their own "bridge override" under their account that implements S-ERC20.
That override could implement additional restrictions, for example, only allow accounts to interop with specific contracts that implement certain compliance interfaces or use a "trust list" of sorts.
This could work well for CAP48 (they would have full access to trustlines for assets issued by them, except for liabilities that are not accessible).
For CAP-0049 it would be similar, they'd have access to the "unwrap" internals.
Comparing CAP-0048 and CAP-0049
Both require us to commit at the protocol layer to a specific protocol "S-ERC20", which is not necessarily a bad thing to have on day one.
Originally I thought that CAP-0049 would be a lot better as it starts with it seems a much narrower interface with classic, but I think a lot of the advantages vanish as we specify things in terms of S-ERC20. Then the type of interactions that we allow on trustlines is small enough that I can even see opening things up to smart contracts entirely.
With CAP-0049, we'd have "total supply" still broken as it's only tracking a portion of the assets.
Nicolas
--
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/039866ef-a2bf-454a-abf7-22ea6fe7a3dcn%40googlegroups.com.
Hello,
Attempted to focus feedback on usability from the dApp user / developer perspective.
TL;DR
CAP-49 makes sense if the long term goal will be centralized access points (ex. Vibrant) and smart contract assets (ex. Aave's aUSDC) are intended to be created outside of Stellar Classic assets. CAP-48 with totalSupply makes sense if the long term goal is decentralized access points (ex. accessing Aave through an IPFS node) and smart contract assets (ex. Aave's aUSDC) are intended to be created as Stellar Classic assets.
## CAP-48Lack of TotalSupply()
I think this is a requirement for supporting useful smart contracts. Tracking “shares” makes determining the value of a user's deposit into a smart contract much simpler, and is used in AMMs, lending protocols, and various token vaults.
Uniswap’s V2 “mint” as an example: https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L118
Stellar Classic as Primary Control Point
It is likely that a contract will want the ability to “mint” and “burn” tokens. It is unclear to me if this can be supported easily. Would the “contractId” need to match the issuing account of the asset to ensure it has the appropriate signatures to mint new tokens? On that note, would the addition of multi-sig to the issuing account on the classic side break the smart contract? Apologies if I’m just missing something here.
Issue: Available Balance vs Balance
I don’t recall how the liability mechanic works well enough to have a strong opinion. It seems to make the most sense that `token.balanceOf(account)` returns the amount of token that the account has available to spend. However, this reads like the sum of all account balances for the token would be less than the total supply if a liability exists (which is weird). If this is the case, as long as `transfer` and `transferFrom` ensure the liability edge cases are supported, returning the full balance including liabilities would be the clearest.
Usability
Users only having to maintain a single asset for Stellar USDC is a massive plus. Further, this allows dApp UIs to display things like “USDC” and “XLM” to the user, since we can make use of the Stellar Classic asset. Lastly, this allows smart contract native assets (like an aUSDC token from Aave) to take advantage of future things like Speedex.
Another point to note is that smart contract developers will eventually want something more out of the asset object, resulting in new CAPs or weird mixture of smart contract tokens and Stellar Classic tokens. I think a mixture of Stellar Classic assets and "smart contract native" assets should be avoided if possible.
## CAP-49Issue: Not Compatible With High Supply Assets
Does the Rust environment have support for a native double or floating point number? Might be worth exploring for developer simplicity over the typical `uint` route of today. I know there has been work/discussion to improve fixed point support in Solidity: https://github.com/ethereum/solidity/issues/409
Usability
There are a few outlying things with a “S-ERC20” bridge contract.
Will “smart contract native” tokens be able to be bridged to Stellar Classic? I can’t wrap my head around if this would be a net advantage to make use of things like Speedex / lower cost transactions, or a net negative due to liquidity fragmentation.
UIs will look pretty weird for dApps, since the majority of assets will be wrapped assets from Stellar Classic. Is there any way that users could verify that this `wUSDC` contract is the actual wrapped USDC from Circle’s Stellar USDC instead of something malicious?
> With CAP-0049, we'd have "total supply" still broken as it's only tracking a portion of the assets.
This is a good point, but I don’t think it blocks smart contracts like the totalSuppy of CAP-48
Consider a “smart contract native” asset. The creation/destruction of tokens is controlled in full by the deployed contract, so it always has the correct look of `totalSupply`, regardless of if the tokens can get bridged to Stellar Classic or not. This meets the requirements for building things like AMMs, lending protocols, and token vaults that utilize the token “share” mechanism for tracking user deposit value.
For a bridged asset, the totalSupply would represent the total amount bridged. Smart contract developers just need to be aware that this isn’t the full amount, and UI developers can still get the full amount if Horizon adds a `wrapped_amount` section to the `assets` call.
Best,Coming back to this thread now that have a better understanding of some of the challenges in the space (some of the conversations around clawback and CAP-0050 at least helped me even if sometimes it may seem like we're running in circle).
I think the priority in terms of interop should be to optimize for innovation.
What do I mean by this?
In the short term our version of how to model a "classic" token is going to be quite primitive: an "ERC-20" without much guarantees.
As we iterate on token standards with the ecosystem, I think that we're going to find that certain things make a lot more sense than others.
For example:
With that said, I think that the approach that we'll take should allow the interop protocol to keep up with the ecosystem instead of slowing it down.
Related to this, one of the pattern that I found useful so far in deciding on how to integrate a feature in the core protocol vs not is to first start with a solution that allows for maximum expressiveness and extensibility in client code, and add core protocol features to enable some "high value" scenario so that they become easier/faster (in other words: core level support should be considered as a way to "promote" parts of what can be done in SEPs that reached broad acceptance into CAPs).
So, going back to CAP-0048 vs CAP-0049 (and following up on some of the comments from Alex).
I also think that the split balance from CAP-0049 is a minor inconvenience (I flagged it as "a major UX issue" previously), because systems like Horizon can just always return the wrapped and unwrapped balances.
As the wrapped/unwrapped asset is a core concept, we can add that concept to the `Asset` type in a similar way that we added "muxed" enum values when we introduced multiplexed account (basically: reserve one bit on the asset code to mean "wrapped").
Allocating part of a given balance to the classic or smart side is still low friction: it's just a matter of executing 1 transaction. If this ends up being a "high frequency" type of scenario, we can always make it faster/more efficient later.
I also think (going back to what I wrote earlier), that with CAP-0049 it will be relatively easy to add new capabilities to the Classic-Wrapped token as it is for the most part just like any other token on the network. So if we want to add a better compliance protocol (the one from the CAP is too simplistic), we will be able to do it regardless of where we land with the broader community.
CAP-0048 on the other hand is a hard commitment on the interop front. It's tightly coupled with the quirks of the classic protocol, and every time we want to add a new capability we'll have to perform a deep analysis on its consequences with the classic implementation.
I think that things get interesting when considering the interop in the other direction (that was not discussed at all so far):
How does things look like for tokens that are issued on the smart side, how do they get exposed to classic? I believe that "classic" (or a better version of it), is the future for some highly specialized operations on the network (like payments) so supporting this direction of interop is critical.
In a CAP-0049 like world, wrap/unwrap semantics are already there, so I can envision future protocol changes that would just mimic what CAP-0049 does but in reverse (there are some failure modes to consider, but it's basically just that). This can potentially be done with the issuer contract in full control (as classic access control is not granular, this is required). Operations normally granted to the issuer would not be granted on the classic side (as there would not be any way to fulfill them).
In a CAP-0048 like world, I think it gets kinda weird. There needs to be a classic asset usable.
So the two options are: