Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide an easier deposit/airdrop workflow when users don't have a trustline or account #303

Closed
accordeiro opened this issue May 8, 2019 · 23 comments
Labels
CAP Represents an issue that requires a CAP. SEP Represents an issue that requires a SEP.

Comments

@accordeiro
Copy link
Member

accordeiro commented May 8, 2019

As discussed with @tomquisel, this issue aims to document an alternative approach for making the deposit and sending assets workflow better in Stellar.

Tom Quisel and Jeremy Rubin have created a Python script named transfer.py as a proof of concept. It is basically a simplified special case of SEP-016.

Our initial thought was to create a new SEP that explains what transfer.py does, splitting it into:

  • Wallet part of the implementation; and
  • Issuer part of the implementation

A few important details to keep in mind:

  • The reason that we would want to merge accounts at all (rather than just allow a user to have many accounts on which they are a signer) is that the user may not have all trustlines on all accounts, so it makes things like creating an offer between two assets they hold tricky. It greatly simplifies things if the user has just one account that all incoming airdrops / deposits get merged into as soon as possible.
  • It would also be interesting if we could tweak the protocol to support the use case of an issuer claiming back a deposit.
@accordeiro accordeiro changed the title Make the deposit and sending assets workflow better in Stellar Provide an easier deposit/airdrop workflow when users don't have a trustline or account May 8, 2019
@theaeolianmachine
Copy link
Contributor

As a general update on this issue — the protocol working group for this issue is meeting again this week to reconsider other CAP forward designs to help solve this problem. If a sufficient solution can be proposed and approved, it will likely change the content of this substantially. Will continue to update here as progress is made.

@theaeolianmachine theaeolianmachine added CAP Represents an issue that requires a CAP. SEP Represents an issue that requires a SEP. labels Jun 14, 2019
@tomquisel
Copy link
Contributor

One improvement we need to make to transfer.py before rolling out the new SEP is to add a demonstration of handling AUTHORIZATION_REQUIRED trustlines properly.

@MonsieurNicolas
Copy link
Contributor

So it looks like this is the issue tracking CAP-0023.

CAP23 is interesting, @jonjove

General questions:

  • Doesn't belong in the CAP, but what are the implications ecosystem wise of such change? Does Horizon need some sort of lookup/indexing service on top of those new ledger entries (to lookup by source/destination)? What is the new flow for the various scenarios that the CAP is trying to enable (I think SEP16 had the full list)?
  • Should there be a link back to the tx hash that created the BalanceEntry? For example, if we need MEMO or other context?
  • What are the rules around AuthorizeBalance? Same than for an account? In particular when it comes to "auth revocable"
  • What are the thresholds? Medium (and low for "Authorize?")?
  • "Balance" may not be the right term. It seems to be more like a "bank's check" type of equivalent. Following this analogy, should issuers be able to clean up any such ledger entry (provided they have the rights, and move the "reserve" to the fee pool for example)?
  • From an extensibility point of view, should the rules around "who can claim" be encoded as an array of conditions instead (and have "base reserve gives you 2 conditions free")? Right now it looks to me that the encoding is tightly coupled with the operations manipulating the BalanceEntry. I don't see a reason to only have one condition met at any time for example, maybe open up future extensions like what is proposed in CAP021
    • could this be used to simplify payment channels? For example I could see uses for certain pre-conditions to enforce that multiple BalanceEntry objects are all claimed at once by a transactions (or fail).
  • do we need deterministic accounts at all if we have this construct? It seems to me that this is a very narrow and limited version of those (in a good way).
    • related to this question, it may be interesting to go through the exercise of using BalanceEntry as the foundation for a "deterministic account" type of construct where those things are used as one time ratchets. It may change a few things, like maybe we don't need AuthorizeBalance (as the issuer can reference the BalanceEntry as destination account), and potentially allows new things like using them as collateral for an offer.

Nits:

  • I think that ClaimBalance can fail due to "too many trustlines"
  • Abstract doesn't mention "AuthorizeBalance"
  • Operation names should end with "Op"
  • BalanceEntry needs an extension point

@tomquisel
Copy link
Contributor

tomquisel commented Aug 21, 2019

@msfeldstein I just wanted to put this issue on your radar as an important SEP-6 improvement. CAP-23 (sending a balance via a 2-part payment) that Nico mentions above is probably pretty far out, so I'm thinking the best approach is to improve the flow that Alex points out in transfer.py and then create a SEP for it. Wallets & anchors can implement that as a stop-gap solution that avoids the special cases mentioned in SEP-6.

To just review the context, the problem is that the current way we deal with users who make a deposit but have no account goes like this:

  • User initiates deposit in wallet via SEP-6, giving the issuer their account id
  • When the money hits (days later), the issuer uses some of the funds to create the user's account, and then waits for a trustline to be added to complete the flow
  • The user must log back into their wallet and approve a trustline
  • The anchor can then complete the deposit, but the use will likely wait an unspecified amount of time because the anchor may not notice the trustline immediately

This is a really bad user experience because they must take two actions, and wait (possibly days) two times to make the deposit happen. If they mess it up or don't log back into the wallet, it appears that the anchor or someone simply took their money.

The transfer.py approach has just two steps for the user, after which they immediately receive their funds: initiate the deposit in the anchor, then accept the deposit in the wallet. This is the better UX we're going for.

@msfeldstein
Copy link
Contributor

I'm ramping up on the details here, but out of curiosity, could we do the existing flow but have the end user create a pre-signed transaction creating the trustline that the anchor can then submit after creating the account? Then the user doesn't need to come back online for anything.

  • User initiates deposit in wallet via SEP-6 giving the issuer both their account id and a signed transaction adding the trustline with sequence#1
  • Issuer submits a create_account transaction with the users account id, funding it enough for reserve + 1 trustline
  • Issuer submits the pre-signed transaction, creating the trustline
  • Issuer completes the deposit into the users account
  • Users wallet is listening for payments and sees that its complete.

@MonsieurNicolas
Copy link
Contributor

MonsieurNicolas commented Aug 30, 2019

@msfeldstein

User initiates deposit in wallet via SEP-6 giving the issuer both their account id and a signed transaction adding the trustline with sequence#1

an account is not created with sequence number 1, it would be possible to use bumpSeqOp but this would have to be done using an account controlled by the issuer. transfer.py is an implementation of a protocol that works around most of the problems that come with this scenario.

@msfeldstein
Copy link
Contributor

msfeldstein commented Aug 30, 2019 via email

@tomerweller
Copy link
Contributor

@msfeldstein, no. the starting seq number depends on the ledger in which the account was created:
https://github.com/stellar/stellar-core/blob/859fae6222320381697189534d3bc8f70b9d46ca/src/transactions/TransactionUtils.cpp#L640

@tomquisel
Copy link
Contributor

@msfeldstein I just wanted to check in that you're feeling like transfer.py is a solid approach, or if you're still exploring an alternative based on pre-signed transactions. We explored many of those approaches and ultimately decided they were worse, but we may have missed something.

@msfeldstein
Copy link
Contributor

msfeldstein commented Sep 5, 2019 via email

@msfeldstein
Copy link
Contributor

It seems like this needs the "Accounts for Signer" endpoint to be enabled before we can really make the right experience here, am i understanding that correctly?

@tomquisel
Copy link
Contributor

@msfeldstein yep, great point that Accounts for Signer is needed. Since it's already live on horizon.stellar.org, though, it's probably not a blocking dependency.

@msfeldstein
Copy link
Contributor

msfeldstein commented Sep 12, 2019

I have a javascript version of this running that shows pretty clearly whats supposed to be happening on both ends, including the new accounts-for-signer endpoint. I do feel this will work in real wallets. It currently runs through accounts that are created but have no trustline and works great, i need to verify it works for accounts that haven't been created yet.

https://github.com/msfeldstein/airdrop-script
Try it out with $ npx msfeldstein-airdrop-script

@tomquisel
Copy link
Contributor

Cool! This great. Have you dealt with the case of an AUTH_REQUIRED asset? I think that's the last edge case we need to tackle 🎉

@MonsieurNicolas
Copy link
Contributor

@jonjove here are some comments based on the latest CAP0023 draft

ClaimPredicate

  • Which predicate do we actually need for the first version? It seems we have too many for a v1.
  • Should the time condition (both absolute and relative) be replaced by pairs like for Transaction (allows to do the same by setting low bound to 0 or high bound to max, but also match a specific interval)? NB: not needed if we get rid of weights (see below)

ClaimCondition

  • Should destination be optional? This would allow conditions to be shared, and also allow for the degenerate case of "anybody can claim this balance entry".
    • In general, maybe all we want is to be able to express some generic condition on the claimant (starting with just ANY and AccountID).
    • I see the comment later in the section "ClaimableBalanceEntry claimants are accounts", but that seems to be an orthogonal problem that can be solved in a different way (we could add a new flag to issuers or maybe use the existing ones, to enforce some minimum bar for the condition if people really want that)
  • Why limit weight to 255, we could just make the threshold an uint64 and not have to worry about this?

ClaimableBalanceEntry

  • condition should be conditions (typo), and if we think that many conditions will share the same destination (a relatively large field, especially if we turn this more into claimant condition), we should factor out destination by removing it from ClaimCondition and do something like
    • conditions -> vector of { destination: X, conditions: vector of ClaimCondition}
  • In general, do we really want to use the weight + threshold approach for conditions?
    • It's not possible to express things like (A || B) && (C || D)
    • Maybe an expression tree with some basic boolean arithmetic would be better and simpler to use, we just need to add AND and OR conditions that take an array of conditions as parameter, maybe a NOT as well in the future
  • Do we need to store some timestamp in there to use with relative time locks?
    • In core, we can't lookup the time with just the ledger number
    • Also, you probably don't want to use lastModifiedLedgerSeq either as relative time locks are probably based on creation time, not last modified (and last modified gets changed by AuthorizeClaimableBalanceOp)

CreateClaimableBalanceOp

  • Did you mean to say max(1, condition.size()-1) * baseReserve for reserve (not min)?

AuthorizeClaimableBalanceOp

  • Why authorize is a TrustLineFlags? This seems to imply that you cannot set multiple flags at the same time and that the operation can work with any flag (which it probably doesn't).
  • Not a big fan of this logic parallel to trustline management especially for more generic use cases (outside of asset issuance), as it makes it very hard for an issuer to know if it should authorize a claimable balance entry that has conditions (as it was not the party that crafted conditions).
    • It also puts the burden on issuers to track balance entries instead of whoever is using them.
    • Why not simply allow people to claim a balance entry, and if the trustline needs to be created, create it with a balance. If the asset is "auth required", it will be frozen by default. Unfreezing accounts should not be something that special for issuers.

ClaimClaimableBalanceOp

  • Semantics around authorize are weird.
    • If we keep authorize, I'd rather have an explicit enum than baking assumptions like "less than" (or any other hard coded merge strategy for trustline flags) on trust line flags that is hard to define in a generic way (so basically, don't use TrustLineFlags here). With this proposal, I am not sure what we'd do with CAP18's new flag or future flags.

@jonjove
Copy link
Contributor

jonjove commented Jan 23, 2020

ClaimPredicate

  • I proposed these predicates because they are simple and cover a variety of use cases. I am happy to do fewer, but it’s really only three kinds of predicates: unconditional, absolute time, and relative time.
  • I am indifferent between inequality constraints and pairs. Regardless, I think we should switch to a boolean expression tree which avoids this issue entirely (see below).

ClaimCondition

  • I don’t think destination should be optional. I can imagine a future in which we add a hash-preimage predicate and a new operation to use such a predicate. But in the absence of required destination accounts, this would allow violations analogous to those described in “ClaimableBalanceEntry claimants are accounts”. If, in the future, we decide this was a bad decision then we will always be able to change the destination type from AccountID to a new type ClaimableBalanceDestination which would overlap with AccountID for compatibility reasons but would also add NO_DESTINATION.
  • Weight was limited to 255 to match the behavior of signer weights. Regardless, I think we should switch to a boolean expression tree which avoids this issue entirely (see below).

ClaimableBalanceEntry

  • I agree, a vector is a much better solution.
  • I agree, boolean expression trees are a much better approach. I originally was trying to match the behavior of signers as much as possible, but boolean expression trees are more expressive and easier to reason about. This will require adding CLAIM_PREDICATE_AND and CLAIM_PREDICATE_OR.
  • This is handled by never storing *_RELATIVE_TIME in the actual ledger, see Semantics for CreateClaimableBalanceOp behavior step 7.

CreateClaimableBalanceOp

  • Good catch, I definitely meant to write max

AuthorizeClaimableBalanceOp

  • You are right, authorize should be a uint32.
  • I think it would be a perfectly reasonable stance for an issuer to refuse to pre-authorize any ClaimableBalanceEntry that the issuer did not create. A ClaimableBalanceEntry does not need to have the authorize flag set in order to be claimed, so an issuer could entirely ignore the existence of that flag while still allowing holders of the issued asset to use ClaimableBalanceEntry. I have renamed this flag preauthorize to hopefully avoid confusion.
    • This burden is entirely opt-in. If the issuer elects to not use the authorize flag, there is nothing to track. For this reason, existing issuers do not have a compatibility issue.
    • I considered this option, but I chose not to pursue this path because it violates the existing invariant that the balance of an unauthorized trust line will never increase. It also leads to some unintuitive failure modes: if you don’t have a trust line then the operation could succeed, but if you created the trust line first then the operation would fail. Furthermore, it means that certain undesirable things could happen: imagine a ClaimableBalanceEntry that can be claimed by account A before time T or by account B after time T; under the current proposal if A is not authorized then only B will be able to claim, whereas your proposal would allow A to claim even though he cannot actually use the funds.
  • An additional thought on this topic: one of the annoying details of my proposal was that the authorize flag applied to all possible claimants uniformly. Utilizing the vector approach discussed above, I have changed it to a flag-per-claimant.

ClaimClaimableBalanceOp

  • I don’t think my choice of the phrase “less than” was ideal. What I meant was, given the TrustLineFlags that we currently have (including CAP-0018) there is a strict order on the possible authorization levels 0 < AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG < AUTHORIZED_FLAG
    so “less than” was meant to reflect this order. Having said this, I think the only acceptable flag today should be AUTHORIZED_FLAG which has the simple semantics of set AUTHORIZED_FLAG and clear AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG if it is set.

@MonsieurNicolas
Copy link
Contributor

Great updates.

xdr cleanup

As xdr doesn't allow to extend enums, we should give relative time predicates a name that gives a hint that those predicates don't actually exist in the ledger and are only used in operations.

CreateClaimableBalanceOp

"amount is non-positive": do you mean amount <= 0 (NB: I prefer explicit condition)? I think amount == 0 can be useful as a way to pre-authorize trustlines but not actually give tokens away.

Step 4: need to be explicit on what you mean that the account is "authorized". I suspect you need AUTHORIZE_FLAG and that AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG would not be allowed in this case.

Condition on destination

It seems fine to restrict as you proposed.

I think that either ClaimCondition or Claimant should be an union, so that if we want to remove the destination condition in the future (or replace it by something else), we have a simple way to extend the protocol. Right now we'd have to hack around the AccountID somehow.

Authorization

We should not use uint32 for preauthorize flags and instead use a typedef, and define the set of flags actually valid for that type with the definition of the type.
It looks like we don't enforce which flags are allowed in operations like PreauthorizeClaimableBalanceOp, so we should probably do that too.

ClaimClaimableBalanceOp step 11

  • did you mean if claimants[i].preauthorize & AUTHORIZED_FLAG != 0 for the condition?
  • I think you're saying that if the condition is met, we should set AUTHORIZED_FLAG and clear AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG on the trustline. Might be clearer to prefix things like tl.flags and have tl defined in step 7 (and step 10) with "Skip to step 11 if sourceAccount has a trust line tl for asset")

You should explain in the "design rationale" the choices being made here:

  • I can see why you want to automatically authorize a trustline that was not authorized before.
  • I do not understand why you could not pre-authorize a trust line with the AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG flag (basically, allowing issuers of secured assets to use this feature and not be in the business of creating the account)
  • I do not understand why you would want to automatically change a trustline's flags from AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG into AUTHORIZED_FLAG (or the other way around, if we were allowing AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG for preauth). If an issuer wants to use AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG they do not want to have accounts with AUTHORIZED_FLAG set outside of "sandwiches" as described in https://github.com/stellar/stellar-protocol/blob/master/core/cap-0018.md#how-can-this-new-flag-be-used
    so either check against both (basically: gating is done when CreateClaimableBalanceOp is called) or make ClaimClaimableBalanceOp error out if the tl flags do not have AUTHORIZED_FLAG (requiring the issuer to "unlock" the claimer); changing the trustline seems arbitrary.

@jonjove
Copy link
Contributor

jonjove commented Jan 29, 2020

Thanks for providing more feedback!

CreateClaimableBalanceOp

  • I hadn’t considered the possibility that one might want to pre-authorize without sending tokens. Interesting point, I don’t see any reason we shouldn’t allow that. Changed to explicit statement amount < 0.
  • Changed to explicitly require AUTHORIZED_FLAG

Condition on destination

  • I had considered making it a union but seem to have forgotten to actually do it, thanks for noticing this. Made Claimant a union.

Authorization

  • Good idea, definitely helpful for clarity. Introduced typedef uint32 PreauthorizeFlags with comment detailing which flags are permitted (only AUTHORIZED_FLAG).
  • Flag validity is already checked for PreauthorizeClaimableBalanceOp. It’s a validity check, so it appears before “The behavior of …”

ClaimClaimableBalanceOp step 11

  • Good catch, that is definitely what I meant. Fixed. Same typo appears in step 12, fixed there as well.
  • Yes that’s what I’m saying. I agree it is definitely not really clear, writing it as a bitwise operation. Described it in words as well.

@MonsieurNicolas
Copy link
Contributor

I wrote some thoughts related to extending the proposal for utxo support (I think also replace deterministic accounts, a question I was asking earlier). See https://gist.github.com/MonsieurNicolas/25e6bd235151a197be84a0712555082e @jonjove

@MonsieurNicolas
Copy link
Contributor

Here is another round of feedback.

XDR

ClaimClaimableBalanceOp is using the hardcoded Hash type, should it instead use ClaimableBalanceID type? (if we decide to split those types later, we can, but it seems to be the safest thing to do for now)

Should CreateClaimableBalanceResult return the ID of the claimable balance that was created? Even though IDs can be derived from the transaction it makes it a lot easier to debug.

Prepared Trust Line

The semantics in the doc are written in a fairly confusing way. Right now to understand what it is, the reader has to derive it from what happens in the various operations and/or from the rationale (the fact that it's mutually exclusive with a trust line is a key property that is right now only mentioned in the "rationale").
We should start by defining what a "prepared trust line" is. I am not sure "prepared trust line" is a good name, "prepared" seems to imply that it's ready. Name should imply that it can be used for creating a trustline, so maybe something like "pending trust line" is closer to what it is?
If we have the right definition for this, the definitions for the operations should just fall into place.

AllowTrustOp

Need to describe what "analogous" really is. I would expect revoking to delete the "prepared trust line"? I guess, if you want to separate "issuer" from the account sponsoring trust lines, you don't want the issuer to receive the base reserve in this situation, so you need an accountID that specifies who can delete the prepared trust line (and you need an explicit operation to delete those things).

CreatePreparedTrustLineOp

I think we should have separate "success" codes so that we can distinguish if the (pending) trust line already existed or not as users may do something different based on this.
If the "prepared trust line" already exist, I am not sure this behavior is worth the complexity (we should also deal with base reserve decrease). If it already exist, I would rather just return success. If somebody wants to change the reserve they should just re-create the pending trust line.

CreateClaimableBalanceOp

Please add the error code for each of the invalid cases.
Should Step 2 "deduct the base reserve" be moved right before "step 6"? It reads as if the balance is changed even in case of failure.
The second CLAIM_PREDICATE_BEFORE_RELATIVE_TIME should read CLAIM_PREDICATE_AFTER_RELATIVE_TIME.
Why is reserve not the amount that was used as reserve? I would have expected it to just be claimants.size() * baseReserve.

ClaimClaimableBalanceOp

Need a section in "rationale" that explains why sending back the reserve to "createdBy" makes sense. In particular, it looks like "createdBy" exists in ClaimableBalanceEntry just to support this (so there is a significant cost to this property).

Threshold should be "medium" as it changes the balances associated with the account (and claiming something can be as bad as sending from a regulatory standpoint).

Should it be possible to increase the amount of a ClaimableBalanceEntry?

I disagree with what is written here. We should give the guarantee that a ClaimableBalanceEntry is immutable, it makes reasoning about them a lot simpler. If the amount changes, pre-signed transactions that depend on them would potentially become invalid.

@jonjove
Copy link
Contributor

jonjove commented Mar 5, 2020

@MonsieurNicolas Let’s discuss how we think prepared trust lines (or whatever we decide to call them) should work.

Prepared trust lines in this proposal

In this proposal, I was working with the following definition of a prepared trust line: A prepared trust line is a ledger entry with the following properties
(1) It is not a sub-entry of any account
(2) It can be created by any account for any account and any asset
(3) It can only be removed by conversion into a trust line
(4) Creation is “at least idempotent” in the sense that creation succeeds even if

  • A trust line for the account and asset already exists, in which case nothing happens
  • A prepared trust line for the account and asset already exists, in which case the reserve is increased if necessary

Property 1

I don’t think property (1) is controversial, so I will not provide any analysis of it.

Property 2

Property (2) is not, to me, a strict requirement although other people may disagree. One advantage of including this property is that it makes it possible to use prepared trust lines without requiring Medium threshold on the issuer account (allow trust only requires Low).

Property 3

Property (3) has important implications. A prepared trust line can have authorization flags set by the issuer. There are only two ways to change the authorization flags on a trust line: the issuer can change them with AllowTrustOp or the owner of the trust line can clear all flags by removing the trust line with ChangeTrustOp. If accounts other than the issuer and target of the prepared trust line are able to remove the prepared trust line, then they can clear all flags.

So what could go wrong? It is easy to see that if any account can remove the prepared trust line, then it is possible for an attacker to remove any prepared trust line at any time; this would render the prepared trust lines nearly useless. If only the account that created the prepared trust line can remove it, then there is a a more restricted attack in which an attacker learns that a prepared trust line will be created by some other account so the attacker creates the prepared trust line first. When the issuer authorizes the prepared trust line, the attacker removes and re-creates the prepared trust line in a single transaction. This clears the flags while extending the attack.

Property 4

Property (4) is in many ways a consequence of property (3). We can’t permit accounts to remove the prepared trust line, so how do you increase the reserve should you want to? You simply create it again.

I want to address this remark specifically:

If somebody wants to change the reserve they should just re-create the pending trust line.

Even if there were no attacks associated with allowing pending trust lines to be removed, this does not provide a good user-experience because it would clear the flags.

There are other benefits to this approach. It allows issuers to bundle creating a prepared trust line and allow trust into a single transaction without concern over whether creating the prepared trust line will fail due to (for example) a race with the target account in which it creates the actual trust line first.

A different model for prepared trust lines

If we change property (2) above to “It can only be created by the issuer for any account”, this produces a considerably different model.

The new definition is: A prepared trust line is a ledger entry with the following properties
(1’) It is not a sub-entry of any account
(2’) It can only be created by the issuer for any account
(3’) It can only be removed by the issuer or by conversion into a trust line
(4’) Creation succeeds even if a trust line already exists

Property 2’

Property (2’) is much more restrictive than property (2) above, but still captures the most important use case in which the issuer wants to prepare a trust line into a certain authorization state for an account without interacting with that account.

Property 3’

Property (3’) is less restrictive than property (3) above, because all of the potential attacks have been removed. As we noted, the authorization of a trust line can already be changed by the issuer so there is no reason that an issuer should not be able to remove a prepared trust line (there will need to be some constraints around AUTH_REVOCABLE). This makes the asset issuance protocol more effective, because the issuer will be able to reclaim not just the funds from the claimable balance entry but also the reserve from the prepared trust line.

Property 4’

Property (4’) is weaker than property (4) above, because only the issuer can create a prepared trust line so there is no risk of racing with the creation of a prepared trust line by another account.

It is fine for the issuer to remove a prepared trust line with flags set in order to increase the reserve because the issuer can set the flags again afterwards. The only downside of this simplification is that the issuer might not be able to re-create a prepared trust line if AUTH_REVOCABLE is set (as mentioned in Property 3’) so in that case they will not be able to increase the reserve. This might be tolerable since it is such an edge case anyway.

@tomquisel
Copy link
Contributor

To sum up our conversation today, our take is that:

  1. Gateways who are not issuers are an important use case for CAP-23.
  2. We also care about individuals being able to fund trustlines for other individuals. This comes up any time a wallet user or payment app or airdrop wants to send an asset to a user with too little XLM to get their own trustline.

@jonjove
Copy link
Contributor

jonjove commented Aug 5, 2020

Implemented in stellar/stellar-core#2591

@jonjove jonjove closed this as completed Aug 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CAP Represents an issue that requires a CAP. SEP Represents an issue that requires a SEP.
Projects
None yet
Development

No branches or pull requests

7 participants