0068 XLS-68d: Sponsored Fees and Reserves #196
mvadari
started this conversation in
Standard Proposals
Replies: 2 comments 5 replies
-
Out of curiosity, wouldn't it be better if account x could submit a signed transaction on behalf account y so account y would bear the txn cost. |
Beta Was this translation helpful? Give feedback.
2 replies
-
Does the sponsored account itself not require 10XRP for account reserves? If 10XRP is not required, then the new Account Reserve Calculation should subtract 1 acctReserve if the AccountRoot has |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Sponsored Fees and Reserves
Abstract
As the blockchain industry grows, many projects want to be able to build on the blockchain, but abstract away the complexities of using the blockchain - users don't need to submit transactions or deal with transaction fees themselves, they can just pay the platform to handle all that complexity (though, of course, the users still control their own keys).
Some projects also want to onboard users more easily, allowing users to create accounts without needing to pay for their own account reserve or needing to gift accounts free XRP to cover the reserve (this could get rather expensive if it is exploited).
In order to handle these sorts of use-cases, this proposal adds a process for users to maintain control over their keys and account, but to have another account (e.g. a platform) submit the transaction and pay the transaction fee and/or reserves on their behalf. This proposal supports both account and object reserves.
Similar features on other chains are often called "sponsored transactions", "meta-transactions", or "relays".
1. Overview
Accounts can include signatures from sponsors in their transactions that will allow the sponsors to pay the transaction fee for the transaction, and/or the reserve for any accounts/objects created in the transaction.
We propose modifying one ledger object and creating one new transaction type:
AccountRoot
ledger objectSponsorTransfer
transaction typeThe common fields for all ledger objects and all transactions will also be modified.
In addition, there will be a modification to the
account_objects
RPC method, and a new RPC method calledaccount_sponsoring
.This feature will require an amendment, tentatively titled
featureSponsor
.1.1. Terminology
1.2. The Sponsorship Flow
In this scenario, the sponsor, Spencer, wants to pay the transaction fee and/or reserve for the sponsee Alice's transaction.
1.3. Recouping a Sponsored Object Reserve
In this scenario, the sponsor, Spencer, would like to re-obtain the reserve that is currently trapped due to his sponsorship of Alice's object.
Spencer can submit a
SponsorTransfer
transaction, which allows him to pass the onus of the reserve back to Alice, or pass it onto another sponsor.1.4. Recouping a Sponsored Account Reserve
In this scenario, the sponsor, Spencer, would like to retrieve his reserve from sponsoring Alice's account.
There are two ways in which he could do this:
AccountDelete
transaction, which will send all remaining funds in the account back to Spencer.SponsorTransfer
transaction to either remove sponsorship or transfer it to the new provider.2. On-Ledger Objects: Common Fields
2.1. Fields
As a reference, here are the fields that all ledger objects currently have:
LedgerIndex
string
Hash256
LedgerEntryType
string
UInt16
Flags
number
UInt16
We propose this additional field:
SponsorAccount
string
AccountID
2.1.1.
SponsorAccount
The
SponsorAccount
is the sponsor that is paying the reserve for this ledger object.3. On-Ledger Object:
AccountRoot
3.1. Fields
As a reference, here are the fields that the
AccountRoot
ledger object currently has.Account
string
AccountID
AccountTxnID
string
Hash256
AMMID
string
Hash256
Balance
string
Amount
BurnedNFTokens
number
UInt32
Domain
string
Blob
EmailHash
string
Hash128
FirstNFTokenSequence
number
UInt32
LedgerEntryType
string
UInt16
0x0061
, mapped to the stringAccountRoot
, indicates that this is anAccountRoot
object.MessageKey
string
Blob
MintedNFTokens
number
UInt32
NFTokenMinter
string
AccountID
OwnerCount
number
UInt32
PreviousTxnID
string
Hash256
PreviousTxnLgrSeq
number
UInt32
RegularKey
string
AccountID
Sequence
number
UInt32
TicketCount
number
UInt32
TickSize
number
UInt8
TransferRate
number
UInt32
WalletLocator
string
Hash256
WalletSize
number
UInt32
We propose these additional fields:
SponsorAccount
string
AccountID
SponsoredOwnerCount
number
UInt32
SponsoringOwnerCount
number
UInt32
SponsoringAccountCount
number
UInt32
3.1.1.
SponsorAccount
The
SponsorAccount
field is already added in the ledger common fields (see section 2.1.1), but it has some additional rules associated with it on theAccountRoot
object.This field is included if the account was created with a sponsor paying its account reserve. If this sponsored account is deleted, the destination of the
AccountDelete
transaction must equalSponsorAccount
, so that the sponsor can recoup their fees.Note: The
Destination
field ofAccountDelete
will still work as-is if the account is not sponsored, where it can be set to any account.3.1.2.
SponsoredOwnerCount
This is the number of objects the account owns that are being sponsored by a sponsor.
3.1.3.
SponsoringOwnerCount
This is the number of objects the account is sponsoring the reserve for.
3.1.4.
SponsoringAccountCount
This is the number of accounts that the account is sponsoring the reserve for.
3.2. Account Reserve Calculation
The existing reserve calculation is:
The total account reserve should now be calculated as:
4. Transactions: Common Fields
4.1. Fields
As a reference, here are the fields that all transactions currently have.
We propose these modifications:
Sponsor
object
STObject
4.1.1.
Sponsor
The
Sponsor
inner object contains all of the information for the sponsorship happening in the transaction.The fields contained in this object are:
Account
string
AccountID
Flags
number
UInt16
SigningPubKey
string
STBlob
Signature
string
STBlob
Signers
array
STArray
4.1.1.1.
Account
The
Sponsor.Account
field represents the sponsor.This field will be a signing field (it will be included in transaction signatures).
4.1.1.2.
Flags
The
Flags
field allows the user to specify which sponsorship type(s) they wish to participate in. At least one flag must be specified if theSponsor
field is included in a transaction.There are two flag values that are supported:
0x00000001
:tfSponsorFee
, sponsoring (paying for) the fee of the transaction.0x00000002
:tfSponsorReserve
, sponsoring the reserve for any objects created in the transaction.This field will be a signing field (it will be included in transaction signatures).
4.1.1.3.
SigningPubKey
andSignature
These fields are included if the sponsor is signing with a single signature (as opposed to multi-sign). This field contains a signature of the transaction from the sponsor, to indicate their approval of this transaction. All signing fields must be included in the signature, including
Sponsor.Account
andSponsor.Flags
.Either
Signature
orSigners
must be included in the final transaction.There will be no additional transaction fee required for the use of the
Signature
field.Signature
will not be a signing field (it will not be included in transaction signatures, though it will still be included in the stored transaction).4.1.1.4.
Signers
This field contains an array of signatures of the transaction from the sponsor,'s signers to indicate their approval of this transaction. All signing fields must be included, including
Sponsor.Account
andSponsor.Flags
.Either
Signature
orSigners
must be included in the final transaction.If the$(\#signatures+1)*base\textunderscore fee$ .
Signers
field is necessary, then the total fee of the transaction will be increased, due to the extra signatures that need to be processed. This is similar to the additional fees for multisigning. The minimum fee will beThe total fee calculation for signatures will now be$( 1+\# tx.Signers + \# tx.Sponsor.Signers) * base\textunderscore fee$ .
This field will not be a signing field (it will not be included in transaction signatures, though it will still be included in the stored transaction).
4.2. Failure Conditions
4.2.1. General Failures
Sponsor.Signature
is invalidSponsor.Signers
is invalid (the signer list isn't on the account, quorum isn't reached, or signature(s) are invalid)4.2.2. Fee Sponsorship Failures
4.2.3. Reserve Sponsorship Failures
tecINSUFFICIENT_RESERVE
)4.3. State Changes
4.3.1. Fee Sponsorship State Changes
The fee will be deducted from the sponsor instead of the sponsee. That's it.
4.3.2. Reserve Sponsorship State Changes
Any account/object that is created as a part of the transaction will have a
Sponsor
field.The sponsor's
SponsoringOwnerCount
field will be incremented by the number of objects that are sponsored as a part of the transaction, and theSponsoringAccountCount
field will be incremented by the number of new accounts that are sponsored as a part of the transaction.The sponsee's
SponsoredOwnerCount
field will be incremented by the number of objects that are sponsored as a part of the transaction.The
SponsoredOwnerCount
,SponsoringOwnerCount
, andSponsoringAccountCount
fields will be decremented when those objects/accounts are deleted.4.4. Transactions that cannot be sponsored
All transactions (other than pseudo-transactions) may use the
tfSponsorFee
flag, since they all have a fee.However, some transactions will not support the
tfSponsorReserve
flag.Batch
(from XLS-56d)Batch
to support that flag. The sub-transactions should usetfSponsorReserve
instead.EnableAmendment
,SetFee
, andUNLModify
)Also, many transactions, such as
AccountSet
, will have no change in output when using thetfSponsorReserve
flag, if they do not create any new objects or accounts.5. Transaction:
SponsorTransfer
This transaction transfers a sponsor relationship for a particular ledger object's object reserve. The sponsor relationship can either be passed on to a new sponsor, or dissolved entirely (with the sponsee taking on the reserve). Either the sponsor or sponsee may submit this transaction at any point in time.
5.1. Fields
TransactionType
string
UInt16
Account
string
AccountID
LedgerIndex
string
UInt256
Sponsor
object
STObject
5.1.1.
LedgerIndex
This field should be included if this transaction is dealing with sponsored object, rather than on a sponsored account. This field indicates which object the relationship is changing for.
If it is not included, then it refers to the account sending the transaction.
5.1.2.
Sponsor
The
Sponsor
field is already added in the ledger common fields (see section 4.1.1), but it has some additional rules associated with it on theSponsorTransfer
transaction.In this case, if
Sponsor
is included with thetfSponsorReserve
flag, then the reserve sponsorship for the provided object will be transferred to theSponsor.Account
instead of passing back to the ledger object's owner.If there is no
Sponsor
field, or if thetfSponsorReserve
flag is not included, then the burden of the reserve will be passed back to the ledger object's owner (the former sponsee).5.2. Ending the Sponsorship for a Sponsored Ledger Object
A sponsored ledger object will have the
Sponsor
field attached to it. Ending the sponsor relationship for a sponsored ledger object requires theLedgerIndex
parameter, to specify which ledger object.Two accounts are allowed to submit a
SponsorTransfer
relationship to end the sponsor relationship for a sponsored ledger object: either the sponsor for that object or the owner of that object (the sponsee).5.3. Migrating a Sponsorship to a New Account
A sponsorship can be migrated to a new account by including the
Sponsor
field with thetfSponsorReserve
flag. This can be done for either a sponsored account or a sponsored ledger object.Two accounts are allowed to submit a
SponsorTransfer
relationship to migrate the sponsor relationship: the sponsor or the sponsee.The sponsor will likely only rarely want to do this (such as if they are transferring accounts), but the sponsee may want to migrate if they change providers.
5.4. Failure Conditions
5.5. State Changes
Sponsor
field on the object is changed or deleted.SponsoringOwnerCount
/SponsoringAccountCount
decremented by one.SponsoringOwnerCount
/SponsoringAccountCount
incremented by one.SponsoredOwnerCount
will be decremented by one.6. RPC:
account_objects
6.1. Fields
The
account_objects
RPC method already exists on the XRPL. As a reference, here are the fields thataccount_objects
currently accepts:account
string
deletion_blockers_only
boolean
ledger_hash
string
ledger_index
number
orstring
limit
number
marker
any
type
string
We propose this additional field:
sponsored
boolean
6.2.
sponsored
If this field is excluded, all objects, sponsored or not, will be included. If
sponsored == True
, only sponsored objects will be included. Ifsponsored == False
, only non-sponsored objects will be included.7. RPC:
account_sponsoring
The
account_sponsoring
RPC method is used to fetch a list of objects that an account is sponsoring; namely, a list of objects where theSponsorAccount
is the given account. It has a very similar API to theaccount_objects
method.account
string
deletion_blockers_only
boolean
true
, the response only includes objects that would block this account from being deleted. The default isfalse
.ledger_hash
string
ledger_index
number
orstring
limit
number
marker
any
type
string
offer
andescrow
.8. Security
8.1. Security Axioms
Both the sponsee and the sponsor must agree to enter into a sponsor relationship. The sponsee must be okay with the sponsor handling the reserve, and the sponsor must be willing to take on that reserve. A signature from both parties ensures that this is the case.
A sponsor will never be stuck sponsoring an sponsee's account or object it doesn't want to support anymore, because it can submit a
SponsorTransfer
transaction at any point.The sponsor's signature must always include the
Account
andSequence
fields, to prevent signature replay attacks (where the sponsor's signature can be reused to sponsor an object or account that they did not want to sponsor).When sponsoring transaction fees, the sponsor must approve of the
Fee
value of the transaction, since that is the amount that they will be paying.When sponsoring reserves, the sponsor's signature must include any aspects of the transaction that involve a potential account/object reserve. This would include the
Destination
field of aPayment
transaction (and whether it is a new account) and theTicketSequence
field of aTicketCreate
transaction (since that dictates how manyTicket
objects are created, each of which results in one object reserve).A sponsee cannot take advantage of the generosity of their sponsor, since the sponsor must sign every transaction it wants to sponsor the ledger objects for. A sponsee also must not be able to change the sponsorship type that the sponsor is willing to engage in, as this could lock up to 500 of the sponsor's XRP (in the case of 250 tickets being created in one
TicketCreate
transaction).An axiom that is out of scope: the sponsee will not have any control over a sponsorship transfer. This is akin to a loanee having no control over a bank selling their mortgage to some other company, or a lender selling debt to a debt collection agency.
8.2. Signatures
Since a fee sponsorship must approve of the
Fee
field, and a reserve sponsorship must approve of a broad set of transaction fields, the sponsor must always sign the whole transaction. This also avoids needing to have different sponsorship processes for different sponsorship types. This includes the non-signature parts of theSponsor
object (Sponsor.Account
andSponsor.Flags
). The same is true for the sponsee's transaction signature; the sponsee must approve of the sponsor and sponsorship type.A sponsor's
Signature
cannot be replayed or attached to a different transaction, since the whole transaction (including theAccount
andSequence
values) must be signed.9. Invariants
An invariant is a statement, usually an equation, that must always be true for every valid ledger state on the XRPL. Invariant checks serve as a last line of defense against bugs; the
tecINVARIANT_FAILED
error is thrown if an invariant is violated (which ideally should never happen).9.1. Tracking Owner Counts
A transaction that creates a ledger object either increments an account's
OwnerCount
by 1 or increments two separate accounts'SponsoringOwnerCount
andSponsoredOwnerCount
by 1. The opposite happens when a ledger object is deleted.The equivalent also should happen with
SponsoringAccountCount
.9.2. Balancing
SponsoredOwnerCount
andSponsoringOwnerCount
In other words, the sum of all accounts'
SponsoredOwnerCount
s must be equal to the sum of all accounts'SponsoringOwnerCount
s. This ensures that every sponsored object is logged as being sponsored and also has a sponsor.10. Example Flows
Each example will show what the transaction will look like before and after both the sponsor and sponsee sign the transaction.
The unsigned transaction must be autofilled before it is passed to the sponsor to sign. Tooling can be updated to handle combining the sponsor and sponsee signatures, similar to helper functions that already exist for multisigning.
10.1. Fee Sponsorship
10.1.1. The Unsigned Transaction
10.1.2. The Signed Transaction
10.2. Account Sponsorship
The only way an account can be created is via a
Payment
transaction. So the sponsor relationship must be initiated on thePayment
transaction.10.2.1. The Unsigned Transaction
10.2.2. The Signed Transaction
10.3. Object Sponsorship
10.3.1. The Unsigned Transaction
10.3.2. The Signed Transaction
Appendix
Appendix A: FAQ
A.1: Does the sponsee receive any XRP for the reserve?
No, there is no XRP transfer in a sponsorship relationship - the XRP stays in the sponsor's account. The burden of the reserve for that object/account is just transferred to the sponsor.
A.2: What happens if you try to delete your account and you have sponsored objects?
If the account itself is sponsored, then it can be deleted, but the destination of the
AccountDelete
transaction (in other words, where the leftover XRP goes) must be the sponsor's account. This ensures that the sponsor gets their reserve back, and the sponsee cannot run away with those funds.If the sponsee still has sponsored objects, those objects will follow the same rules of deletion blockers. Whether or not they are sponsored is irrelevant.
If a sponsored object is deleted (either due to normal object deletion processes or, in the case of objects that aren't deletion blockers, because the owner account is deleted), the sponsor's reserve becomes available again.
A.3: What if a sponsor that is sponsoring a few objects wants to delete their account?
An account cannot be deleted if it is sponsoring any existing accounts or objects. They will need to either delete those objects (by asking the owner to do so) or use the
SponsorTransfer
transaction to relinquish control of them.A.4: Does a sponsor have any powers over an object they pay the reserve for? I.e. can they delete the object?
No. If a sponsor no longer wants to support an object, they can always use the
SponsorTransfer
transaction instead.A.5: What if a sponsee refuses to delete their account when a sponsor wants to stop supporting their account?
The sponsor will have the standard problem of trying to get ahold of a debtor to make them pay. They may be able to use
SponsorTransfer
transaction to put the onus on the sponsee, though the sponsee would need to have enough XRP in their account to cover the reserve.A.6: What happens if the sponsor tries to
SponsorTransfer
but the sponsee doesn't have enough funds to cover the reserve?If the sponsor really needs to get out of the sponsor relationship ASAP without recouping the value of the reserve, they can pay the sponsee the amount of XRP they need to cover the reserve. These steps can be executed atomically via a Batch transaction, to ensure that the sponsee can't do something else with the funds before the
SponsorTransfer
transaction is validated.A.7: Would sponsored accounts carry a lower reserve?
No, they would still carry a reserve of 10 XRP at current levels.
A.8: Can an existing unsponsored ledger object/account be sponsored?
Yes, with the
SponsorTransfer
transaction.A.9: Can a sponsored account be a sponsor for other accounts/objects?
No.
A.10: Can a sponsored account hold unsponsored objects, or objects sponsored by a different sponsor?
Yes, and yes.
A.11: What if I want different sponsors to sponsor the transaction fee vs. the reserve for the same transaction?
That will not be supported by this proposal. If you have a need for this, please provide example use-cases.
A.12: Won't it be difficult to add two signatures to a transaction?
This is something that good tooling can solve. It could work similarly to how multisigning is supported in various tools.
A.13. Why not instead do [insert some other design]?
See Appendix B for the alternate designs that were considered and why this one was preferred. If you have another one in mind, please describe it in the comments and we can discuss.
A.14: How is this account sponsorship model different from/better than XLS-23d, Lite Accounts?
A.15: How will this work for objects like trustlines, where multiple accounts might be holding reserves for it?
The answer to this question is still being explored. One possible solution is to add a second field,
Sponsor2
, to handle the other reserve.A.16: How does this proposal work in conjunction with XLS-49d? What signer list(s) have the power to sponsor fees or reserves?
Currently, only the global signer list is supported. Another$2^{16}$ , since the $2^{32}$ , so there is room in the design for additional values that do not correlate to a specific transaction type.
SignerListID
value could be added to support sponsorship. Transaction values can only go up toTransactionType
field is aUInt16
, but theSignerListID
field goes up toAppendix B: Alternate Designs
B.1: Add a
Sponsor
to the accountThis design involved updating
AccountSet
to allow users to add aSponsor
to their account (with a signature from the sponsor as well). The sponsor would then sponsor every object from that account while the field was active, and either the sponsor or the account could remove the sponsorship at any time.This was a previous version of the spec, but it made more sense for the relationship to be specific to a transaction/transactions, to prevent abuse (the sponsor should decide what objects they want to support and what objects they don't want to support).
The current design also supports having different sponsors for different objects, which allows users to use a broad set of services and platforms, instead of being locked into one.
B.2: A Wrapper Transaction
There would be a wrapper transaction (tentatively named
Relay
), similar toBatch
in XLS-56d, that the sponsor would sign. It would contain a sub-transaction from the sponsee.It would look something like this:
TransactionType
string
UInt16
Account
string
STAccount
Fee
string
STAmount
Transaction
object
STTx
This was a part of a previous version of the spec (inspired by Stellar's sandwich transaction design for their implementation of sponsored reserves), but the existing design felt cleaner. From an implementation perspective, it's easier to have the fee payer as a part of the existing transaction rather than as a part of a wrapper transaction, since that info needs to somehow get passed down the stack. Also, while the wrapper transaction paradigm will be used in XLS-56d, they should be used sparingly in designs - only when necessary - as their flow is rather complicated in the
rippled
code.In addition, the signing process becomes complicated (as discovered in the process of developing XLS-56d). You have to somehow prevent the sponsor from submitting the as-is signed transaction to the network, without including it in the wrapper transaction.
B.3: A Create-Accept-Cancel Flow
The rough idea of this design was to have a new set of transactions (e.g.
SponsorCreate
/SponsorAccept
/SponsorCancel
/SponsorFinish
) where a sponsor could take on the reserve for an existing object.This design was never seriously considered, as it felt too complicated and introduced several new transactions. It also doesn't support adding a sponsor to the object at object creation time, which is a much smoother UX and never requires the owner/sponsee to hold enough XRP for the reserve.
Beta Was this translation helpful? Give feedback.
All reactions