Skip to content

Latest commit

 

History

History
189 lines (155 loc) · 6.06 KB

cap-0016.md

File metadata and controls

189 lines (155 loc) · 6.06 KB

Preamble

CAP: 0016
Title: Cosigned assets: NopOp and COAUTHORIZED_FLAG
Authors: David Mazières
Status: Rejected (In favor of CAP-0018)
Created: 2018-01-24
Discussion: https://github.com/stellar/stellar-protocol/issues/146
Protocol version: TBD

Motivation

A number of Stellar asset issuers need greater control over assets than simply authorizing particular accounts to hold the asset. As a result, we are seeing people build solutions in which the asset issuer is actually a co-signer on asset holders' accounts. This solution has several drawbacks. In particular, the asset owner cannot unilaterally withdraw XLM or other assets from his or her account, and it is very hard to trade one such restricted asset for another (as both issuers would need to be cosigners on the account, giving one issuer permission to authorize transactions on the other's asset).

This proposal is a first cut at attempting to address the problem through minimal stellar-core changes.

Co-signer authorized trust lines

To accommodate asset issuers with restrictions, we propose adding another mode for trustlines of AUTH_REQUIRED assets, called "cosigner authorized," that lies somewhere between being not authorized and fully authorized. The idea is to allow issuers to require asset holders to request co-signing of transactions involving the asset without being cosigners on asset holders' accounts.

enum TrustLineFlags
{
    // issuer has authorized account to perform transactions with its credit
    AUTHORIZED_FLAG = 1,
    // issuer allows transactions that are co-signed by issuer low threshold
    COAUTHORIZED_FLAG = 2
};

There are now three modes for the trustline of an AUTH_REQUIRED asset, based on TrustLineEntry::flags:

  • If (flags & 3) == 0, the source account is not authorized. Any PAYMENT, PATH_PAYMENT, MANAGE_OFFER, or CREATE_PASSIVE_OFFER, with the source account causes the whole transaction to fail, with only two exceptions:

    • A PATH_PAYMENT is allowed to contain the asset in path, so long as it does not apear in sendAsset or destAsset, and

    • A MANAGE_OFFER is allowed if it sets amount to 0 (to delete the offer).

    In addition, any operation with a different (even authorized) source account will fail if it attempts to send the asset to an account with (flags & 3) == 0. Finally, existing orders on the order book belonging to the account with (flags & 3) == 0 are immediately invalid and cannot be filled. This behavior should be close or identical to the status quo.

  • If (flags & 3) == COAUTHORIZED_FLAG for an account, then the account has certain additional permissions compared to when those bits are 0. Specifically:

    • The account's offers in the order book continue to be valid, and can be filled at any time.

    • The account can use MANAGE_OFFER to reduce the amount of an offer involving the asset (including canceling the offer with and amount of 0), but not to increase the offer.

    • The account can receive (but not send) payments and path payments in the asset, up to the limit of the trustline.

    However, any other operation on the asset requires that the transaction be co-signed by the asset issuer at low threshold. Moreover, if the account increases the limit on the trustline and the transaction is not cosigned by the issuer, then the COAUTHORIZED_FLAG is cleared so (flags & 3) goes back to 0.

  • If (flags & 3) == AUTHORIZED_FLAG, then the account can perform arbitrary transactions on the asset, including sending payments to accounts with COAUTHORIZED_FLAG.

Operation changes

Implementing cosigned assets requires changes to two operations. Because an asset issuer's signature may be out of place on a transaction requiring asset issuer coauthorization, we add a NopOp operation that requires a signature from an arbitrary source account. Such an operation will be useful in other contexts, too, as currently pre-authorized transactions sometimes require ugly hacks like having an account send one Stroup to itself. Second, we have to modify ALLOW_TRUST to enable issuers to set the new COAUTHORIZED_FLAG.

NO_OPERATION (NopOp)

The NO_OPERATION operation does nothing, but requires a valid signature from the operation's source account. Since the default source account is the source of the transaction, this will always succeed at low threshold if the operation's sourceAccount is NULL. However, it can be used to require a low threshold signature from an asset issuer.

enum NopOp {
    LOW_THRESHOLD = 0,
    MED_THRESHOLD = 1,
    HIGH_THRESHOLD = 2
};

enum NopResult {
    NOP_SUCCESS = 0,
    NOP_BAD_THRESHOLD = -1,  // the operation was an invalid value
};

enum OperationType
{
    ...
    BUMP_SEQUENCE = 11,
    NO_OPERATION = 12
};

struct Operation
{
    union switch (OperationType type)
    {
    case NO_OPERATION:
        NopOp nopOp;
    }
    body;
};

union OperationResult switch (OperationResultCode code)
{
case opINNER:
    union switch (OperationType type)
    {
        ...
    case NO_OPERATION:
        NopResult nopResult;
    }
    tr;
default:
    void;
};

NopOp is not strictly necessary, as a redundant ALLOW_TRUST can be used instead, but having NopOp is cleaner and has other applications to pre-authorized transactions.

ALLOW_TRUST flags

Only one small change is required to AllowTrustOp. We change the authorize field from a bool to a uint32. This provides binary compatibility with clients that do not know about the COAUTHORIZED_FLAG (since AUTHORIZED_FLAG == TRUE in XDR), but having a uint32 provides the additional option of setting it to COAUTHORIZED_FLAG.

struct AllowTrustOp
{
    AccountID trustor;
    union switch (AssetType type)
    {
    // ASSET_TYPE_NATIVE is not allowed
    case ASSET_TYPE_CREDIT_ALPHANUM4:
        opaque assetCode4[4];

    case ASSET_TYPE_CREDIT_ALPHANUM12:
        opaque assetCode12[12];

        // add other asset types here in the future
    }
    asset;

    // 0, AUTHORIZED_FLAG, or COAUTHORIZED_FLAG
    uint32 authorize;
};