# CAP-0035: Asset Clawback ## Preamble ```text CAP: 0035 Title: Asset Clawback Working Group: Owner: Tomer Weller <@tomerweller> Authors: Dan Doney (Securrency, Inc.), Tomer Weller <@tomerweller>, Leigh McCulloch <@leighmcculloch>, Siddharth Suresh <@sisuresh> Consulted: Nicolas Barry <@MonsieurNicolas>, Jon Jove <@jonjove>, Eric Saunders <@ire-and-curses> Status: Final Created: 2020-12-14 Discussion: https://groups.google.com/g/stellar-dev/c/hPhkXhrl5-Y/m/ZF6eJcqKAgAJ Protocol version: 17 ``` ## Simple Summary This proposal provides the Issuer with a means to clawback (and reissue if desired) assets in order to support regulatory requirements. This function can be used to: 1) recover assets that have been fraudulently obtained 2) respond to regulatory actions, if required 3) enable identity proofed persons to recover an enabled asset in the event of loss of key custody or theft. The proposal does not involve shared custody of the person’s account and does not affect custody of bearer assets in the persons account. ## Working Group This protocol change was initially authored by Dan Doney and Tomer Weller. The working group include other authors and the consulted persons include key individuals familiar with the implementation of the core protocol and maintainers of Horizon and its SDKs. ## Motivation In order to meet securities regulatory requirements in many jurisdictions globally, the issuer (or designated transfer agent) must be able to demonstrate the ability to revoke assets in the event of a mistaken or fraudulent transaction or other regulatory action regarding a specific person or asset wide. To receive approval, the Issuer must demonstrate the ability to perform this action with or without the permission of the affected person. Unlike approaches that involve multiple signatures on the person’s wallet (brokerage clawback), this approach does not compromise the custody of other assets in the person’s wallet. Additionally, this approach is an improvement over an approach that invalidates the trustline. While trustline invalidation freezes assets, tokens (asset shares) remain in circulation compromising accounting models. The approach has other benefits to owners of the affected asset including the ability to recover assets if wallet custody is lost including the important business continuity mitigations in the loss of control of custodial or omnibus account. Ex: https://www.ccn.com/190m-gone-how-canada-biggest-bitcoin-exchange-lost-it/ ### Goals Alignment This CAP is aligned with the following Stellar Network Goals: - The Stellar Network should be secure and reliable. - The Stellar Network should enable cross-border payments, i.e. payments via exchange of assets, throughout the globe, enabling users to make payments between assets in a manner that is fast, cheap, and highly usable. ## Abstract This proposal introduces new operations `ClawbackOp`, `ClawbackClaimableBalanceOp`, and `SetTrustLineFlagsOp`, a new account flag `AUTH_CLAWBACK_ENABLED_FLAG`, a new trustline flag `TRUSTLINE_CLAWBACK_ENABLED_FLAG`, and a new claimable balance flag `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG`. The `AUTH_CLAWBACK_ENABLED_FLAG` flag on the issuing account must be set when a trustline is created to authorize a `ClawbackOp` operation submitted by the issuer account. A claimable balance inherits its clawback enabled status from the account creating the claimable balance. A `ClawbackClaimableBalanceOp` operation is valid for claimable balances created by accounts whose trustline for the asset has clawback enabled, and for claimable balances created by an issuer account when the issuer account has clawback enabled. The `ClawbackOp` and `ClawbackClaimableBalanceOp` operations result in the removal of the specified assets issued from the network. The `ClawbackOp` and `ClawbackClaimableBalanceOp` operations only apply to assets issued by the source account. Assets that can be clawed back are easily distinguished from traditional blockchain assets (bearer instruments) so that asset owners are aware of rights. The `ClawbackOp` may result in revocation of some or all of the specified assets from the designated account based on the amount provided in the operation. The `SetTrustLineFlagsOp` allows the user to set and clear specific trustline flags. This operation can be used to unset `TRUSTLINE_CLAWBACK_ENABLED_FLAG`. ## Specification ### XDR changes This patch of XDR changes is based on the XDR files in tag/commit `v15.1.0` (`90b2780584c6390207bf09291212d606896ce9f8`) of [stellar-core]. ```diff mddiffcheck.base=v15.1.0 diff --git a/src/xdr/Stellar-ledger-entries.x b/src/xdr/Stellar-ledger-entries.x index 8d7463915..26ff33d43 100644 --- a/src/xdr/Stellar-ledger-entries.x +++ b/src/xdr/Stellar-ledger-entries.x @@ -28,6 +28,17 @@ enum AssetType ASSET_TYPE_CREDIT_ALPHANUM12 = 2 }; +union AssetCode switch (AssetType type) +{ +case ASSET_TYPE_CREDIT_ALPHANUM4: + AssetCode4 assetCode4; + +case ASSET_TYPE_CREDIT_ALPHANUM12: + AssetCode12 assetCode12; + + // add other asset types here in the future +}; + union Asset switch (AssetType type) { case ASSET_TYPE_NATIVE: // Not credit @@ -99,11 +110,16 @@ enum AccountFlags // otherwise, authorization cannot be revoked AUTH_REVOCABLE_FLAG = 0x2, // Once set, causes all AUTH_* flags to be read-only - AUTH_IMMUTABLE_FLAG = 0x4 + AUTH_IMMUTABLE_FLAG = 0x4, + // Trustlines are created with clawback enabled set to "true", + // and claimable balances created from those trustlines are created + // with clawback enabled set to "true" + AUTH_CLAWBACK_ENABLED_FLAG = 0x8 }; // mask for all valid flags const MASK_ACCOUNT_FLAGS = 0x7; +const MASK_ACCOUNT_FLAGS_V16 = 0xF; // maximum number of signers const MAX_SIGNERS = 20; @@ -187,12 +203,16 @@ enum TrustLineFlags AUTHORIZED_FLAG = 1, // issuer has authorized account to maintain and reduce liabilities for its // credit - AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG = 2 + AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG = 2, + // issuer has specified that it may clawback its credit, and that claimable + // balances created with its credit may also be clawed back + TRUSTLINE_CLAWBACK_ENABLED_FLAG = 4 }; // mask for all trustline flags const MASK_TRUSTLINE_FLAGS = 1; const MASK_TRUSTLINE_FLAGS_V13 = 3; +const MASK_TRUSTLINE_FLAGS_V16 = 7; struct TrustLineEntry { @@ -337,6 +357,27 @@ case CLAIMABLE_BALANCE_ID_TYPE_V0: Hash v0; }; +enum ClaimableBalanceFlags +{ + // If set, the issuer account of the asset held by the claimable balance may + // clawback the claimable balance + CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG = 0x1 +}; + +const MASK_CLAIMABLE_BALANCE_FLAGS = 0x1; + +struct ClaimableBalanceEntryExtensionV1 +{ + union switch (int v) + { + case 0: + void; + } + ext; + + uint32 flags; // see ClaimableBalanceFlags +}; + struct ClaimableBalanceEntry { // Unique identifier for this ClaimableBalanceEntry @@ -356,6 +397,8 @@ struct ClaimableBalanceEntry { case 0: void; + case 1: + ClaimableBalanceEntryExtensionV1 v1; } ext; }; diff --git a/src/xdr/Stellar-transaction.x b/src/xdr/Stellar-transaction.x index 7f08d7579..3c2b1f0be 100644 --- a/src/xdr/Stellar-transaction.x +++ b/src/xdr/Stellar-transaction.x @@ -46,7 +46,10 @@ enum OperationType CLAIM_CLAIMABLE_BALANCE = 15, BEGIN_SPONSORING_FUTURE_RESERVES = 16, END_SPONSORING_FUTURE_RESERVES = 17, - REVOKE_SPONSORSHIP = 18 + REVOKE_SPONSORSHIP = 18, + CLAWBACK = 19, + CLAWBACK_CLAIMABLE_BALANCE = 20, + SET_TRUST_LINE_FLAGS = 21 }; /* CreateAccount @@ -236,20 +239,9 @@ struct ChangeTrustOp struct AllowTrustOp { AccountID trustor; - union switch (AssetType type) - { - // ASSET_TYPE_NATIVE is not allowed - case ASSET_TYPE_CREDIT_ALPHANUM4: - AssetCode4 assetCode4; - - case ASSET_TYPE_CREDIT_ALPHANUM12: - AssetCode12 assetCode12; + AssetCode asset; - // add other asset types here in the future - } - asset; - - // 0, or any bitwise combination of TrustLineFlags + // 0, or any bitwise combination of the AUTHORIZED_* flags of TrustLineFlags uint32 authorize; }; @@ -376,6 +368,48 @@ case REVOKE_SPONSORSHIP_SIGNER: signer; }; +/* Claws back an amount of an asset from an account + + Threshold: med + + Result: ClawbackResult +*/ +struct ClawbackOp +{ + Asset asset; + MuxedAccount from; + int64 amount; +}; + +/* Claws back a claimable balance + + Threshold: med + + Result: ClawbackClaimableBalanceResult +*/ +struct ClawbackClaimableBalanceOp +{ + ClaimableBalanceID balanceID; +}; + +/* SetTrustLineFlagsOp + + Updates the flags of an existing trust line. + This is called by the issuer of the related asset. + + Threshold: low + + Result: SetTrustLineFlagsResult +*/ +struct SetTrustLineFlagsOp +{ + AccountID trustor; + Asset asset; + + uint32 clearFlags; // which flags to clear + uint32 setFlags; // which flags to set +}; + /* An operation is the lowest unit of work that a transaction does */ struct Operation { @@ -424,6 +458,12 @@ struct Operation void; case REVOKE_SPONSORSHIP: RevokeSponsorshipOp revokeSponsorshipOp; + case CLAWBACK: + ClawbackOp clawbackOp; + case CLAWBACK_CLAIMABLE_BALANCE: + ClawbackClaimableBalanceOp clawbackClaimableBalanceOp; + case SET_TRUST_LINE_FLAGS: + SetTrustLineFlagsOp setTrustLineFlagsOp; } body; }; @@ -868,7 +908,8 @@ enum SetOptionsResultCode SET_OPTIONS_UNKNOWN_FLAG = -6, // can't set an unknown flag SET_OPTIONS_THRESHOLD_OUT_OF_RANGE = -7, // bad value for weight/threshold SET_OPTIONS_BAD_SIGNER = -8, // signer cannot be masterkey - SET_OPTIONS_INVALID_HOME_DOMAIN = -9 // malformed home domain + SET_OPTIONS_INVALID_HOME_DOMAIN = -9, // malformed home domain + SET_OPTIONS_AUTH_REVOCABLE_REQUIRED = -10 // auth revocable is required for clawback }; union SetOptionsResult switch (SetOptionsResultCode code) @@ -1120,6 +1161,71 @@ default: void; }; +/******* Clawback Result ********/ + +enum ClawbackResultCode +{ + // codes considered as "success" for the operation + CLAWBACK_SUCCESS = 0, + + // codes considered as "failure" for the operation + CLAWBACK_MALFORMED = -1, + CLAWBACK_NOT_CLAWBACK_ENABLED = -2, + CLAWBACK_NO_TRUST = -3, + CLAWBACK_UNDERFUNDED = -4 +}; + +union ClawbackResult switch (ClawbackResultCode code) +{ +case CLAWBACK_SUCCESS: + void; +default: + void; +}; + +/******* ClawbackClaimableBalance Result ********/ + +enum ClawbackClaimableBalanceResultCode +{ + // codes considered as "success" for the operation + CLAWBACK_CLAIMABLE_BALANCE_SUCCESS = 0, + + // codes considered as "failure" for the operation + CLAWBACK_CLAIMABLE_BALANCE_DOES_NOT_EXIST = -1, + CLAWBACK_CLAIMABLE_BALANCE_NOT_ISSUER = -2, + CLAWBACK_CLAIMABLE_BALANCE_NOT_CLAWBACK_ENABLED = -3 +}; + +union ClawbackClaimableBalanceResult switch (ClawbackClaimableBalanceResultCode code) +{ +case CLAWBACK_CLAIMABLE_BALANCE_SUCCESS: + void; +default: + void; +}; + +/******* SetTrustLineFlags Result ********/ + +enum SetTrustLineFlagsResultCode +{ + // codes considered as "success" for the operation + SET_TRUST_LINE_FLAGS_SUCCESS = 0, + + // codes considered as "failure" for the operation + SET_TRUST_LINE_FLAGS_MALFORMED = -1, + SET_TRUST_LINE_FLAGS_NO_TRUST_LINE = -2, + SET_TRUST_LINE_FLAGS_CANT_REVOKE = -3, + SET_TRUST_LINE_FLAGS_INVALID_STATE = -4 +}; + +union SetTrustLineFlagsResult switch (SetTrustLineFlagsResultCode code) +{ +case SET_TRUST_LINE_FLAGS_SUCCESS: + void; +default: + void; +}; + /* High level Operation Result */ enum OperationResultCode { @@ -1176,6 +1282,12 @@ case opINNER: EndSponsoringFutureReservesResult endSponsoringFutureReservesResult; case REVOKE_SPONSORSHIP: RevokeSponsorshipResult revokeSponsorshipResult; + case CLAWBACK: + ClawbackResult clawbackResult; + case CLAWBACK_CLAIMABLE_BALANCE: + ClawbackClaimableBalanceResult clawbackClaimableBalanceResult; + case SET_TRUST_LINE_FLAGS: + SetTrustLineFlagsResult setTrustLineFlagsResult; } tr; default: ``` ### Semantics Clawback operates similar to auth revocation in that it takes an amount of the asset out of active circulation by preventing the account from using it on the network. Auth revocation freezes the full balance of an asset in an account, but clawback provides fine grain control and allows the issuer to take out of the account and destroy a specific amount of the asset. In order to execute a clawback of an amount in an account, an issuer account must have its `AUTH_CLAWBACK_ENABLED_FLAG` flag set when the account holding the asset created its trustline. The issuer submits a `ClawbackOp` operation specifying the `from` account containing the asset to be clawed back. This operation does not require the affected account’s signature. The transaction results in a change in balance to the recipient’s account. The amount of the asset clawed back is burned and is not sent to any other address. The issuer may reissue the asset to the same account or to another account if the intent of the clawback is to move the asset to another account. If an issuer wishes to set `AUTH_CLAWBACK_ENABLED_FLAG`, it must also have `AUTH_REVOCABLE_FLAG` set. In order to execute a clawback of a claimable balance, the claimable balance must have been created by an account that has clawback enabled on its trustline. In order to execute a clawback of a claimable balance created by an issuer account, the claimable balance must have been created when clawback was enabled on the issuer account. #### Account This proposal introduces a new flag to accounts, `AUTH_CLAWBACK_ENABLED_FLAG`. When the flag is set, trustlines created to the account inherit the flag and the balances within those trustlines may be clawed back by the issuer. An account may set or unset the flag using the existing `SetOptionsOp` operation, unless the `AUTH_IMMUTABLE_FLAG` flag is set, in the same way that existing `AUTH_*` flags may be set or unset unless the immutable flag is set. #### Trustline This proposal introduces a new flag to trustlines, `TRUSTLINE_CLAWBACK_ENABLED_FLAG`, that is set at the time the trustline is created if the issuer account of the asset of the trustline has its `AUTH_CLAWBACK_ENABLED_FLAG` flag set. If the new flag is set it indicates that the balance held by the trustline can be clawed back by the issuer using the `ClawbackOp`, and that any claimable balance created by the account will also be clawback enabled. #### Claimable Balance This proposal introduces the first flag to claimable balances, `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG`. The `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` flag is set at the time the claimable balance is created if the account creating the claimable balance has `TRUSTLINE_CLAWBACK_ENABLED_FLAG` set on the trustline of the asset of the claimable balance. If an issuer account creates a claimable balance for an asset it issues, the `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` flag is set at the time the claimable balance is created if the issuer account creating the claimable balance has `AUTH_CLAWBACK_ENABLED` set. If the new flag is set it indicates that the balance held by the claimable balance can be clawed back by the issuer using the `ClawbackClaimableBalanceOp`. #### Allow Trust Operation This proposal introduces no changes to the `AllowTrustOp` operation XDR, but the operation will not accept the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` as a valid flag that it will operate. The definition of what flags the operation supports will be limited to `AUTHORIZED_*` flags. When applying new flags to accounts the operation will not change the `TRUSTLINE_CLAWBACK_ENABLED_FLAG`. If an `AllowTrustOp` operation is submitted with the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` set, the operation will fail with the existing result code `ALLOW_TRUST_MALFORMED`. #### Set Options Operation This proposal introduces a new result code to the `SetOptionsOp` operation XDR, which will be returned if `AUTH_REVOCABLE_FLAG` flag is not set whenever the `AUTH_CLAWBACK_ENABLED_FLAG` flag is set. This introduces a failing result in these cases: 1. Setting only `AUTH_CLAWBACK_ENABLED_FLAG` without `AUTH_REVOCABLE_FLAG` already set will result in `SET_OPTIONS_AUTH_REVOCABLE_REQUIRED`. 2. Clearing `AUTH_REVOCABLE_FLAG` while `AUTH_CLAWBACK_ENABLED_FLAG` is set will result in `SET_OPTIONS_AUTH_REVOCABLE_REQUIRED`. #### Clawback Operation This proposal introduces the `ClawbackOp` operation. The `ClawbackOp` operation reduces the balance of the asset in the account by the specified amount of the specific `asset` from the `from` account, returning it to the issuer account, burning it. Similar to other operations the clawback operation will fail if the account balance is less than the amount specified when accounting for selling liabilities. If clawback is required of asset amounts locked up with selling liabilities then the issuer may use the `AllowTrustOp` operation to revoke authorization of the trustline, which will cancel any existing ledger entries creating selling liabilities, such as offers, and issue the `ClawbackOp` in the same transaction. If the issuer wishes to allow the `from` account to continue utilizing the asset it can include another `AllowTrustOp` after the `ClawbackOp` to authorize the account once again. The clawback operation requires a medium threshold signature to authorize the operation. `CLAWBACK_MALFORMED` will be returned for `ClawbackOp` during validation under the following conditions: - `asset` is native. - `asset` value is invalid. - `asset.issuer` != source account - `amount` is < 1. - `from` == source account Possible return values for the `ClawbackOp` during application are: - `CLAWBACK_SUCCESS` if the clawback is successful. - `CLAWBACK_NOT_CLAWBACK_ENABLED` if the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` is not set. - `CLAWBACK_NO_TRUST` if the `from` account does not have a trustline for `asset`. - `CLAWBACK_UNDERFUNDED` if the `from` account does not have sufficient available balance of `asset` after accounting for selling liabilities. #### Clawback Claimable Balance Operation This proposal introduces the `ClawbackClaimableBalanceOp` operation. The `ClawbackClaimableBalanceOp` operation destroys a claimable balance, returning the asset to the issuer account, burning it. The operation will only succeed if the claimable balance has its `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` set. The operation source account must be the issuer account of the asset held in the claimable balance. The operation requires a medium threshold signature to authorize the operation. The operation introduces no new or unique behavior to how sponsored reserves function. When the operation applies, removing the claimable balance ledger entry, the reserve held in sponsorship will be freed for the sponsor, in the same way it is freed when any sponsored ledger entry is removed. `ClawbackClaimableBalanceOp` is always valid. Possible return values for the `ClawbackClaimableBalanceOp` during application are: - `CLAWBACK_CLAIMABLE_BALANCE_SUCCESS` if the clawback is successful. - `CLAWBACK_CLAIMABLE_BALANCE_DOES_NOT_EXIST` if the claimable balance does not exist. - `CLAWBACK_CLAIMABLE_BALANCE_NOT_ISSUER` if the source account is the not the issuer of the `asset`. - `CLAWBACK_CLAIMABLE_BALANCE_NOT_CLAWBACK_ENABLED` if the `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` is not set. #### Set TrustLine Flags Operation This proposal introduces the `SetTrustLineFlagsOp` operation. The operation works like the `AllowTrustOp`, except it uses set and clear parameters to set/clear specific trustline flags. This will allow an issuer to clear the `TRUSTLINE_CLAWBACK_ENABLED_FLAG`. An important detail to note here is that `SetTrustLineFlagsOp` will mimic the changes to `AllowTrustOp` specified in [CAP-0029](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0029.md). The operation requires a low threshold signature to authorize the operation. `SET_TRUST_LINE_FLAGS_MALFORMED` will be returned for `SetTrustLineFlagsOp` during validation under the following conditions: - Both `AUTHORIZED_FLAG` and `AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG` are set on `setFlags`. - `asset` is invalid. - `asset` is `ASSET_TYPE_NATIVE`. - `setFlags` and `clearFlags` are modifying the same flags. - `setFlags` or `clearFlags` are modifying unsupported flags. - `setFlags` has the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` set. - `trustor` == source account - `asset.issuer` != source account Possible return values for the `SetTrustLineFlagsOp` during application are: - `SET_TRUST_LINE_FLAGS_SUCCESS` if the operation is successful. - `SET_TRUST_LINE_FLAGS_NO_TRUST_LINE` if the trustline doesn't exist. - `SET_TRUST_LINE_FLAGS_CANT_REVOKE` if `AUTH_REVOCABLE_FLAG` is not set on the issuer, but the authorization is downgraded (`AUTHORIZED_FLAG` -> `AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG`, `AUTHORIZED_FLAG` -> 0, or `AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG` -> 0). - `SET_TRUST_LINE_FLAGS_INVALID_STATE` if the final state of the trustline flag has both `AUTHORIZED_FLAG` and `AUTHORIZED_TO_MAINTAIN_LIABILITIES_FLAG` set. ## Design Rationale In the event of regulatory action, erroneous transaction, or loss of custody, the issuer may conduct a clawback transaction if the appropriate flags are set. In the event of loss of custody, the affected party would need to demonstrate they are the rightful owner of the account (usually through reproofing KYC credentials or otherwise authenticating). On obtaining this proof, the issuer could execute a clawback from the lost account followed by a subsequent payment to a separate account under control of the affected party. Needless to say, executing a reallocation is a significant responsibility and in many cases should be reserved for licensed entities (like a transfer agent) holding the issuer credentials and aware of responsibilities under the law of the jurisdiction of the affected party and asset. ### Flags The account `AUTH_CLAWBACK_ENABLED_FLAG` flag allows the issuer to indicate that it has control over the use of the asset on the network. By including the flag in account flags, account owners may review the revocability of an asset issued by the issuer and have the choice to avoid this type of asset if they object to the implied trust in the issuer. The account `AUTH_REVOCABLE_FLAG` flag must also be set because for clawback to succeed in all cases that an account holds an asset, the issuer must be able to revoke authorization to release any offers creating selling liabilities with the asset. If an issuer enables clawback but not `AUTH_REVOCABLE_FLAG` it will likely be oversight. By setting the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` flag on the trustline, account owners have confidence that the clawback feature may not be enabled if it was not enabled when they created their trustline. By setting the `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` flag on the claimable balance based on the state of the trustline of the account creating the claimable balance, account owners have confidence that the clawback feature may not be enabled for claimable balances they create if it was not enabled when they created their trustline. ### Threshold The clawback operations require a medium threshold signature because they are changing the balance of accounts and changing the states of claimable balances and is more aligned with impact of a payment operation than an allow trust operation. `SetTrustLineFlagsOp` requires a low threshold signature because `AllowTrustOp`, the other operation that allows one to modify trustline flags, requires a low threshold as well. ### Claimable Balances Claimable balances are immutable and so any functionality to clawback a claimable balance is all or nothing. The clawback feature of claimable balances is proposed with a flag so that it is explicit when a claimable balance can be clawed back. The flag state is inherited from the trustline of the account creating the claimable balance to ensure that the balance controlled by the account holder does not change clawback enabled status when moving between account and claimable balances. A separate operation is specified to ensure that clawback is transparent and highly visible in comparison to routine claiming of a claimable balance and to allow issuers that use claimable balances routinely to distinguish between claimable balances they can routinely claim and claimable balances they may clawback. ### Claimable Balances Created by an Issuer An issuer account has no trustline to itself for assets it issues, therefore setting the `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` flag based on the state of a trustline is not possible in this case. By setting the `CLAIMABLE_BALANCE_CLAWBACK_ENABLED_FLAG` flag on the claimable balance based on the state of the issuer account flags when the issuer account creates a claimable balance, the issuer account retains control to specify if claimable balances it creates are clawed back. This is intuitive, but not overly flexible. Issuer accounts that need to create claimable balances with clawback disabled, but need to have clawback enabled for new trustlines, can create claimable balances via a second account that it allows to have a trustline that is clawback disabled. ### Allow Trust Operation The `AllowTrustOp` is disallowed from operating on the new `TRUSTLINE_CLAWBACK_ENABLED_FLAG` trustline flag because this operation doesn't have a parameter to set/clear flags. It requires the user to be aware of existing flags, which is an operational burden. A new operation, `SetTrustLineFlagsOp`, is proposed in this cap to make trustline flag modification simpler. Additionally the `AllowTrustOp` operation is semantically intended to change authorization and clawback is outside it's scope. The `AllowTrustOp` is deprecated for `SetTrustLineFlagsOp`. ### Set TrustLine Flags Operation The `SetTrustLineFlagsOp` will make it easier for issuers to modify trustline flags. In the context of clawback, an issuer can clear the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` from a trustline without knowledge of the current state of the other flags. This is not possible with `AllowTrustOp` because it sets the trustline flags to the value passed in by `AllowTrustOp`. It is also not possible to add the existing flag to the `AllowTrustOp` operation without breaking existing users of that operation since they will not be expecting to include the current state of the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` in the flags field. Clearing the `TRUSTLINE_CLAWBACK_ENABLED_FLAG` allows the issuer to create a clawback enabled asset, with a subset of trustlines that are not subject to clawback. The ability to clear flag will also allow an issuer to disable clawback on an asset entirely by removing `AUTH_CLAWBACK_ENABLED_FLAG` on its own account and clearing `TRUSTLINE_CLAWBACK_ENABLED_FLAG` from all existing trustlines to that asset. ### Asset instead of AssetCode Both `SetTrustLineFlagsOp` and `ClawbackOp` use an `Asset` as a parameter instead of an `AssetCode` to defer the decision of who all future authorizers of the operation can be. The `Asset` includes the issuer account, where-as use of `AssetCode` would assume the source account is always the issuer account. In this proposal, only the issuer may authorize the operation. This decision makes it possible in a future proposal to expand the accounts that may be allowed to issue the operation. ## Protocol Upgrade Transition ### Backwards Incompatibilities The change does not have an affect on previous assets, accounts, or transaction structure. It should not cause a breaking change in existing implementations. Pre-authorized, pre-signed, or pre-planned transactions that create accounts, and create claimable balances, using assets that become clawback enabled could fail if those transactions did not include the issuer account as a claimant. The `ClawbackOp` operation introduced is reversible meaning that their use if reversed has no impact on existing pre-signed or pre-authorized transactions involving the asset and the account that the clawback operates on. The `ClawbackClaimableBalanceOp` operation is not reversible meaning that after their use there is no way to recreate the destroyed claimable balance with the same identifier. Pre-signed or pre-authorized transactions that claim the claimable balance will have encoded its identifier. Authors of contracts or systems utilizing pre-signed or pre-authorized transactions can identify that assets may be clawed back by inspecting the flags of the account that will create the claimable balance and the the flags of the issuer to understand if the issuer could enable clawback on new accounts. ### Resource Utilization No substantial changes to resource utilization. ## Test Cases None yet. ## Implementation https://github.com/stellar/stellar-core/pull/2881 https://github.com/stellar/stellar-core/pull/2893 https://github.com/stellar/stellar-core/pull/2900 https://github.com/stellar/stellar-core/pull/2918 [stellar-core]: https://github.com/stellar/stellar-core