Skip to content

Latest commit

 

History

History
463 lines (419 loc) · 33.6 KB

bsip-0072.md

File metadata and controls

463 lines (419 loc) · 33.6 KB
BSIP: 72
Title: Tanks and Taps: A General Solution for Smart Contract Asset Handling
Authors: Nathan Hourt <nat.hourt@gmail.com>
Status: Accepted
Type: Protocol
Created: 2019-08-27
Updated: 2020-03-16
Discussion: https://github.com/bitshares/bsips/issues/178

Abstract

This BSIP proposes the addition of novel, generally-applicable asset handling functionality to BitShares. These additions will support the development of a wide range of financial decentralized applications (dapps), advancing BitShares as an alternative platform to existing Turing Complete Smart Contract Platforms (TCSCPs) for dapp development. Although the changes will not add Turing Completeness to BitShares, and TCSCPs will continue to offer more flexible capabilities, the proposed infrastructure will offer a simple, ready-to-use interface to dapp developers which will facilitate more rapid development and a reduced time to market compared with generic Turing Complete platforms, which require dapps to define their own asset management logic. Furthermore, dapps utilizing the proposed functionality will share a consistent, easy-to-visualize asset handling model which will become increasingly familiar to users of dapps based on BitShares, giving them confidence when using BitShares dapps that they understand how their assets are being handled and what options are available to themselves or others at the lowest level.

Context and Motivation

One of the main promises of blockchain technology is the processing and execution of "smart contracts," a formalized agreement between parties where the terms are evaluated and enforced automatically rather than relying on trusted intermediaries. Initially, there was Bitcoin, which offers a simple smart contract definition language allowing the transfer of digital tokens between cryptographic keys. Subsequently, the industry has created multiple Turing Complete Smart Contracting Platforms (TCSCPs), such as Ethereum and EOS, in order to provide more advanced smart contract definition languages which can specify any programmable algorithm as a smart contract.

BitShares was created as a financial services smart contracting platform, providing high-performance decentralized financial contracts including an asset exchange, stable-valued assets, recurring payments, and an advanced multi-signature named account system. This curated selection of contracts is developed and supported by a highly competent team of developers who are committed to the quality, security, and correctness of the supported smart contracts. These assurances of contract quality give BitShares an advantage over TCSCPs, where contracts are user-contributed with no expectation of testing or correctness standards; however, to date, neither the more flexible Turing Complete model nor the quality-assured Curated model have clearly succeeded, either in terms of developer support or user adoption.

This proposal is to implement within BitShares a general framework for smart contract asset handling, capable of supporting a great many decentralized applications (dapps) and real world smart contracts. The benefit of such a uniform asset handling framework, as opposed to the TCSCP approach of generally supporting any and all potential asset management designs, is twofold. Firstly, it provides, across all BitShares dapps, a simple and consistent representation of user funds, making it easy for users to understand and reason about the status of assets within the contract, and what options exist for moving assets through the contract. Secondly, specifying a particular structure for asset handling gives developers a clear path for implementing their dapp's asset management, reducing their task from the creation of a novel asset handling architecture for their specific dapp, to merely expressing their dapp's asset movement possibilities within an existing, battle-tested framework.

With this asset handling infrastructure implemented, BitShares would enjoy significant advantages over TCSCPs for dapp development. Much of the complexity of designing and implementing dapps which handle user funds lies in the creation of secure mechanisms for holding funds within the contract, and the represention of these mechanisms to the user in a comprehensible fashion. By providing a simple and consistent framework for asset handling, BitShares offers developers a simpler and faster implementation path by providing sturdy and supported infrastructure for asset handling which provides users a familiar and consistent representation of the status of contract funds.

Rationale

The proposed asset handling framework is a series of asset depositories called "tanks," which have one or more withdrawal mechanisms called "taps." Tanks are simple database objects which track a balance of asset contained within them. A tank has one or more taps on it, which allow withdrawing asset from the tank. Taps are locked such that only specific authorities can open them, and may have restrictions on when or why they can be opened or how much asset can flow through them. Taps are connected to other asset depositories, such as another tank, or an account, and when opened, the asset that flows through them are deposited there. More asset may be added to a tank at any time.

All tanks will be required to have at least one tap which is capable of draining the entire tank immediately. This tap can be thought of as an emergency release valve, and will typically have an authority requiring a supermajority approval of all contract parties. This tap will typically not be connected to any destination until and unless it is used. Its purpose is to handle scenarios where real-world conditions have gone outside the bounds of scenarios planned for under contract (for example, a contract party dies or is otherwise rendered incapable of completing the contract as negotiated), and it becomes necessary to renegotiate the contract mid-flight, potentially rewriting rules for how contract funds can be handled. In such emergent scenarios, it is imperative that the contract platform have a contingency that allows contract parties to reallocate funds based upon renegotiated terms, since the prior-negotiated rules of fund allocation may no longer be usable. In most cases, if the emergency tap is used, it will be connected to a new tank with newly negotiated taps immediately before it is opened, and all funds will be drained to the new tank.

Taps are somewhat more intricate than tanks, as they define the authorities, limitations, and requirements for opening them. First, a tap specifies an authority required to open it. Next, it specifies requirements to open it, such as a requirement for a written reason for the withdrawal, or an approval from a second authority. Finally, it specifies limitations as to how much asset can flow through it once opened.

The power of this model lies in its simplicity. It mimics how money moves in real-world contracts: a balance is locked up for a purpose in advance, when exactly how that balance will be spent is not yet known. As expenditures arise, they are paid out of the balance by an authorized party. Only certain kinds of expenditures can be paid from the balance, and in some cases, a justification or review is required. Eventually, the balance may need to be topped up to support further expenditures. It is anticipated that this model will be general enough to support many smart contract use cases.

A further advantage of this model is that it is easy to visualize, both the current state of contract funds, and the effects a transaction under consideration will have. This is crucial, as it allows the development of intuitive GUIs which represent the status of contract funds to users in a readily accessible fashion, giving them confidence that they understand how their money is being handled and how they can interact with it under terms of contract.

Specifications

The Tanks and Taps protocol is designed around several fundamental types, including tank_object, tap, tap_requirement, tank_attachment, and connection. A tank_object is an object which contains a volume of asset. A tap is an object attached to a tank_object which is capable of releasing asset from the tank. A tap_requirement is a static_variant of various requirement types which can be attached to a tap to impose limits and requirements on when and why a tap can be opened, and how much asset can flow through it. A tank_attachment is a static_variant which may contain one of several structures to be stored on the tank to provide additional functionality for the tank or taps. Finally, a connection is a static_variant of various types which specify what shall be done with asset that has flowed through a tap. A tank_object has one or more taps; a tap may contain zero or more tap_requirements and is optionally connected to a destination where all released funds will go. A tap must be connected to a destination before it can be opened, and the destination must allow the incoming connection in order for the tap to open and flow successfully.

When a tap is opened, the amount of asset to release must be known. A tap can be opened in one of two modes: to release a fixed amount of asset, or to release the maximum amount of asset available. In the former case, the amount to release is set in the transaction that opens the tap. In the latter case, the amount to release is limited by the tap_requirements and the amount of asset remaining in the tank, and the actual amount released is equal to the lower of the two limits.

A tap_requirement is attached to a tap and locks the tap until certain conditions are met. tap_requirements contain several parameters which are defined when the requirement is created, and may require arguments to be passed in the transaction when unlocking or opening the tap. Some tap_requirements are stateful; requirement state is stored by the tank_object. Initially, the following tap_requirement types are specified:

  • immediate_flow_limit Specifies a fixed maximum amount of asset that may flow through the tap in a given opening
  • cumulative_flow_limit Specifies a maximum amount of asset that may flow through the tap before it locks permanently (works in conjunction with an asset_flow_meter)
  • periodic_flow_limit [Stateful] Specifies a maximum amount of asset that may flow through the tap before it locks until a predefined time period elapses (works in conjunction with an asset_flow_meter)
  • time_lock Specifies time periods during which the tap is locked
  • minimum_tank_level Specifies a minimum amount in the tank, such that the tap cannot drain the tank past that minimum
  • review_requirement [Stateful] Specifies a reviewer authority which must approve requests to unlock the tap
  • documentation_requirement Requires documentation of the reason for opening the tap, such as a cost justification, without requiring review of this documentation
  • delay_requirement [Stateful] Requires a delay before tap unlocks, with optional veto authority which can prevent tap from unlocking even after the delay expires
  • hash_preimage_requirement Requires a byte sequence which hashes to a predefined digest to unlock the tap
  • ticket_requirement [Stateful] Requires a ticket (see code specification below) signed by a predefined key granting permission to release a limited volume of funds
  • exchange_requirement [Stateful] Checks an asset_flow_meter (see tank attachments below) and applies an exchange rate to calculate the maximum flow limit

A tank_attachment is attached to a tank and provides additional functionality for the tank or associated taps. Attachments may be created to perform actions when certain events occur on the tank, track statistics, restrict what kinds of actions can be taken on the tank or who can take them, authorize updates to tank components, etc. Attachments can receive asset, but cannot store it, thus attachments which receive asset must specify a connection to a further destination for funds it receives. Tank attachments cannot directly move asset into or out of a tank; only taps can take asset out of a tank, and only a connection can put asset into a tank. Tank attachments may be stateful, and their state will be stored by the hosting tank_object. Initially, the following tank attachments are specified:

  • asset_flow_meter [Stateful] An attachment which can receive funds, and tracks the amount of asset that has flowed through it, then releases the asset to a predefined connection
  • tap_opener An attachment which, when it receives asset, queues a predetermined tap to be opened automatically after the current flow stops
  • attachment_connect_authority An attachment which allows a specified authority to update the connection a specified attachment on the same tank releases asset to

A connection provides a common interface for moving asset within Tanks and Taps structures. At a data level, a connection is small and simple, storing only the ID of the object receiving the asset; however, the connection logic will record the source of the deposit and the path the asset takes as it moves, and this information may be used when processing the deposit to trigger events, log statistics, or detect errors. Initially, the following connection types are specified:

  • An account ID, to which the asset will be deposited as a balance
  • A tank ID, to add asset to the tank balance
  • A tank attachment ID, to send asset through a tank attachment which can receive funds

Deposit Path Restrictions A tank and its attachments can always receive asset from that same tank or its own attachments; however, it is necessary to restrict deposits from remote sources (other tanks or accounts) so that they are processed as intended and cannot be misdirected by a misconfigured transaction or contract. These restrictions are specified with the authorized_connections_type, which is present on all tanks and attachments which receive asset. The authorized_connections_type specifies for a receiver of asset what remote sources are recognized to send asset to it. It may also allow funds from all sources. Funds coming from an unauthorized source will be rejected and the transaction sending them will fail.

Tank Lifecycle Once created, a tank can remain in existence indefinitely and can be filled and emptied many times. It is preferred, however, that unused tanks be destroyed. There are two mechanisms by which a tank is destroyed: first is by a destructor tap, and second is by the tank_destroy operation. A destructor tap is a kind of tap which can destroy the tank after the tank is emptied, if configured to do so by the tap_open operation. Any tap can be created as a destructor tap, but the emergency tap must be a destructor tap. This is expected to be the most common method of destroying a tank, as it can be done within normal usage of the tank. Alternatively, a tank can be destroyed by using the tank_destroy operation; however, this operation requires the emergency tap authority and is therefore unlikely to be frequently used in practice.

To incentivize the destruction of tanks that are no longer being used, a deposit of core asset is required to create a new tank. This deposit is held for the lifetime of the tank, and is released when the tank is destroyed. The deposit is returned directly to the account which pays the fee for the operation that destroys the tank; it is not sent through a tap.

Restricted Assets Some assets specify account whitelists or blacklists, to restrict which accounts may transact in that asset. It is desired that these assets be able to utilize the Tanks and Taps infrastructure without opening the possibility of using Tanks and Taps to circumvent the restrictions on asset ownership; therefore, a restricted asset check will be enforced in three instances. First, when asset is released through a connection to an account balance, a restriction check will be performed on that account. Second, every time a tap is opened, the account which paid the fee on the transaction causing the tap to be opened is checked for authorization to use the released asset. Third, when a connection receives asset from an account, that account checked for authorization to handle the asset. If any of these authorization checks fails, the transaction is rejected as invalid. With these checks in place, restricted assets can be used in conjunction with the Tanks and Taps architecture without compromising the efficacy of the asset restrictions.

Pseudocode definitions of these types are provided below:

attachment_id_type {
    /// ID of the tank hosting the attachment
    tank_id_type tank_id;
    /// ID of the attachment on the tank
    uint16 attachment_id;
}
type connection = static_variant<tank_id_type, account_id_type, attachment_id_type>;

struct all_sources{};
type authorized_connections_type = static_variant<flat_set<connection>, all_sources>;

struct unlimited_flow{};
type tap_flow_limit = static_variant<share_type, unlimited_flow>;

asset_flow_meter {
    state_type {
        /// The amount of asset that has flowed through the meter
        share_type metered_amount;
    }
    /// The type of asset which can flow through this meter
    asset_id_type asset_type;
    /// The connection where the metered asset is released to
    connection destination;
    /// What remote sources, if any, can deposit to this meter
    authorized_connections_type remote_sources;
    /// The authority which may reset the meter; if null, only the emergency tap authority is accepted
    optional<authority> reset_authority;
}
tap_opener {
    /// Index of the tap to open (must be on the same tank as the opener)
    uint16 tap_index;
    /// The amount to release
    tap_flow_limit release_amount;
    /// The connection that asset is released to after flowing through the opener
    connection destination;
    /// What remote sources, if any, can deposit to this opener
    authorized_connections_type remote_sources;
}
attachment_connect_authority {
    /// Authority that may reconnect an attachment
    authority connect_authority;
    /// Attachment which may be reconnected
    attachment_id_type attachment_id;
}

type tank_attachment = static_variant<asset_flow_meter, tap_opener,
                                      attachment_connect_authority>;

immediate_flow_limit { share_type limit; }
cumulative_flow_limit {
    struct state_type {
        /// The amount of asset released so far
        share_type amount_released;
    };
    share_type limit;
}
periodic_flow_limit {
    state_type {
        /// Sequence number of the period during which the last withdrawal took place
        uint32 period_num = 0;
        /// The amount released during the period
        share_type amount_released;
    }
    /// Duration of periods in seconds
    uint32 period_duration_sec;
    /// Maximum cumulative amount to release in a given period
    share_type limit;
}
time_lock {
    /// If true, the tap is initially locked
    bool start_locked;
    /// At each of these times, the tap will switch between locked and unlocked --
    /// must all be in the future
    vector<time_point_sec> lock_unlock_times;
}
minimum_tank_level {
    /// Minimum tank balance; tap cannot drain tank below this balance
    share_type minimum_level;
}
review_requirement {
    /// This type describes a request for withdrawal waiting for review or
    /// for redemption
    request_type {
        /// Amount requested for release -- reset if reviewer denies request
        optional<tap_flow_limit> request_amount;
        /// Optional comment about request, max 150 chars -- reset if reviewer
        /// denies request
        optional<string> request_comment;
        /// Starts false, set to true if request is approved, and back to false after
        /// a release of funds
        bool approved;
    }
    state_type {
        /// Number of requests made so far; used to assign request IDs
        uint16 request_counter;
        /// Map of request ID to request
        flat_map<uint16, request_type> pending_requests;
    }
    /// Authority which approves or denies requests
    authority reviewer;
    /// Maximum allowed number of pending requests; zero means no limit
    index_type request_limit;
}
documentation_requirement {
    /* no fields; if this requirement is present, evaluator requires a nonempty
     * documentation argument exist, but does no further verification upon it
     */
}
delay_requirement {
    /// This type describes a request for withdrawal waiting for its delay to pass
    request_type {
        /// When the request matures and can be consumed
        optional<time_point_sec> delay_period_end;
        /// Amount requested
        optional<tap_flow_limit> request_amount;
        /// Optional comment about request; max 150 chars
        optional<string> request_comment;
    }
    state_type {
        /// Number of requests made so far; used to assign request IDs
        uint16 request_counter;
        /// Map of request ID to request
        flat_map<uint16, request_type> pending_requests;
    }
    /// Authority which can veto request during review period; if veto occurs,
    /// reset state values
    optional<authority> veto_authority;
    /// Period in seconds after unlock request until tap unlocks; when tap opens,
    /// all state values are reset
    uint32 delay_period_sec;
    /// Maximum allowed number of outstanding requests; zero means no limit
    uint16 request_limit;
}
hash_preimage_requirement {
    type hash_type = static_variant<sha256, ripemd160, hash160>;
    /// Specified hash value
    hash_type hash;
    /// Size of the preimage in bytes; a preimage of a different size will be rejected
    /// If null, a matching preimage of any size will be accepted
    optional<uint16> preimage_size;
}
ticket_requirement {
    /// The type of the ticket that must be signed to unlock the tap
    struct ticket_type {
        /// ID of the tank containing the tap this ticket is for
        tank_id_type tank_id;
        /// Index of the tap this ticket is for
        uint16 tap_index;
        /// Maximum asset release authorized by this ticket
        tap_flow_limit max_withdrawal;
        /// Must be equal to tickets_consumed to be valid
        uint16 ticket_number;
    }
    state_type {
        /// Number of tickets that have been used to authorize a release of funds
        uint16 tickets_consumed;
    }
    /// Key that must sign tickets to validate them
    public_key_type ticket_signer;
}
exchange_requirement {
   /// The maximum release amount will be:
   /// meter_reading / tick_amount * release_per_tick - amount_released
    state_type {
        /// The amount of asset released so far
        share_type amount_released;
    }
    /// The ID of the meter to check
    tank_attachment_id_type meter_id;
    /// The amount to release per tick of the meter
    share_type release_per_tick;
    /// Amount of metered asset per tick
    share_type tick_amount;
    /// Authority which can reset the amount released; if null, only the
    /// emergency tap authority is authorized
    optional<authority> reset_authority;
}

type tap_requirement = static_variant<immediate_flow_limit, cumulative_flow_limit,
                                      periodic_flow_limit, time_lock, minimum_tank_level,
                                      review_requirement, documentation_requirement,
                                      delay_requirement, hash_preimage_requirement,
                                      ticket_requirement, exchange_requirement>;

tap {
    /// The connected connection, if present
    optional<connection> connected_connection;
    /// The authority to open the tap; if null, anyone can open the tap if they can
    /// satisfy the requirements
    optional<authority> open_authority;
    /// The authority to connect and disconnect the tap. If unset, tap must be connected
    /// on creation, and the connection cannot be later modified -- emergency tap must
    /// specify a connect_authority
    optional<authority> connect_authority;
    /// Requirements for opening this tap and releasing asset
    vector<tap_requirement> requirements;
    /// If true, this tap can be used to destroy the tank when it empties
    bool destructor_tap;
}

tank_object {
    /// Amount of asset contained in the tank
    asset contained_asset;
    /// Taps on this tank. ID 0 must be present, and must not have any tap_requirements
    flat_map<uint16, tap> taps;
    /// Counter of taps added; used to assign tap IDs
    uint16 tap_counter;
    /// Attachments on this tank
    flat_map<uint16, tank_attachment> attachments;
    /// Counter of attachments added; used to assign attachment IDs
    uint16 attachment_counter;
    /// What remote sources, if any, can deposit to this tank
    authorized_connections_type remote_sources;
    /// Amount of the deposit paid to create the tank (deposit is always core asset)
    share_type deposit_amount;
}

This proposal additionally seeks to add eight operation types to the protocol:

  • tank_create Creates a new tank, specifying taps, tap requirements, and sink connections
  • tank_update Updates a tank, adding or removing taps (including requirements and sinks)
  • tank_delete Deletes a tank (fails if the tank contains asset)
  • tank_query Pass arguments to tap requirements or tank attachments to perform actions or comply with requirements
  • tap_open Release funds through a tap, passing arguments as necessary to satisfy tap requirements
  • tap_connect Connect a tap to a destination
  • account_fund_connection Move asset from an account to a connection (such as a tank)
  • connection_fund_account Virtual operation, generated when a connection deposits asset into an account balance

Pseudocode definitions of these operations are provided below:

tank_create {
    /// Account that pays fee and deposit
    account_id_type fee_payer;
    /// Deposit of core asset paid to create the tank
    share_type deposit_amount;
    /// Type of asset the tank will contain
    asset_id_type tank_asset;
    /// Taps on the tank -- index 0 must be present and must have no tap_requirements
    vector<tap> taps;
    /// Attachments on the tank
    vector<tank_attachment> attachments;
    /// Sources that are authorized to deposit to the tank
    authorized_connections_type authorized_sources;
}
tank_update {
    /// Account that pays fee
    account_id_type fee_payer;
    /// Authority to update tank: must match tank->taps[0].open_authority
    authority update_authority;
    /// ID of tank to update
    tank_id_type tank_to_update;
    /// Change in deposit amount on tank; credited or debited to fee payer
    share_type deposit_delta;
    
    /// IDs of taps to remove
    flat_set<uint16> taps_to_remove;
    /// Map of ID-to-new-value for taps to replace
    /// Note that state data for all requirements of replaced taps will be deleted
    flat_map<uint16, tap> taps_to_replace;
    /// New taps to add
    vector<tap> taps_to_add;

    /// IDs of attachments to remove
    flat_set<uint16> attachments to remove;
    /// Map of ID-to-new-value for attachments to replace
    /// Note that state data for replaced attachments will be deleted
    flat_map<uint16, tank_attachment> attachments_to_replace;
    /// New attachments to add
    vector<tank_attachment> attachments to add;

    /// Set this field to replace the tank's deposit source authorizations
    optional<authorized_connections_type> new_authorized_sources;
}
tank_delete {
    /// Account that pays fee
    account_id_type fee_payer;
    /// Amount of deposit reclaimed for deleting tank
    share_type deposit_amount;
    /// Authority to delete tank: must match tank->taps[0].open_authority
    authority delete_authority;
    /// ID of tank to delete; tank must be empty of asset to destroy
    tank_id_type tank_to_delete;
}
tank_query {
    /// Account that pays the fee
    account_id_type fee_payer;
    /// Authorities required to perform the queries
    flat_set<authority> required_authorities;
    
    /// ID of the tank to be queried
    tank_id_type tank_id;
    /// Contents of the queries to run (format is implementation-defined)
    vector<tank_query_type> queries;
}
tap_open {
    /// Account that pays the fee
    account_id_type fee_payer;
    /// Authorities required to satisfy the tap's requirements/open authority
    flat_set<authority> required_authorities;
    /// Any queries which should be run prior to opening the tap
    /// (format is implementation-defined)
    vector<tank_query_type> queries;
    
    /// ID of the tank with the tap to be opened
    tank_id_type tank_id;
    /// Index of the tap to open
    uint16 tap_index;
    /// Amount to release from the tap
    tap_flow_limit release_amount;
    /// Total number of taps opened by this transaction, i.e. due to tap_openers
    uint16 taps_to_open;
    /// If emptying tank via a destructor tap, the deposit is returned to fee_payer
    /// Specify amount of deposit here to enable tank destruction
    optional<share_type> claimed_deposit;
}
tap_connect {
    /// Account that pays the fee
    account_id_type fee_payer;
    /// Authority to connect the tap: must match
    /// tank_id->taps[tap_index].connect_authority
    authority connect_authority;
    /// ID of the tank holding the tap to be opened
    tank_id_type tank_id;
    /// Index of the tap to be connected
    uint16 tap_index;
    /// Connection to connect the tap to; if null, tap will be disconnected
    optional<connection> new_connection;
    /// Clear the tap connect authority after connecting the tap; if true,
    /// new_connection must be specified
    bool clear_connect_authority;
}
account_fund_connection {
    /// Account that provides funds, and pays fee; must be authorized to handle asset
    account_id_type funding_account;
    /// Destination for the funds
    connection funding_destination;
    /// Amount that the account is moving through the connection
    asset funding_amount;
}
connection_fund_account {
    /// Account receiving funds
    account_id_type recipient;
    /// Amount the recipient received
    asset amount_received;
    /// The path of connections the asset took to arrive at the account, including the origin
    vector<tnt::connection> asset_path;
}

Additionally, these new committee parameters will be defined:

  • max_deposit_path_length The maximum number of connections in a deposit path
  • max_taps_to_open The maximum number of taps a single transaction can open
  • tank_deposit_amount The amount of BTS required for a tank deposit Further parameters may be defined to control the amounts of tank deposits based on the details of the tank.

Tank Queries and Arguments

Many of the tap requirements and tank attachments support modes of user interaction which may or may not result in the immediate movement of asset. Those interactions which do cause movement of asset are performed using the tap_open operation, and those which do not are performed using the tank_query operation. Both of these operations will accept arguments specifying what actions should be taken on which requirements/attachments.

Initially, the following tank attachment queries will be supported:

  • asset_flow_meter
    • Reset the meter to zero (No arguments)
  • attachment_connect_authority
    • Reconnect the specified attachment (Accepts a connection argument)

The following tap requirement queries will be supported:

  • review_requirement
    • Create a request to open the tap (Accepts a request_type argument and an optional string reason)
    • Resolve a request to open the tap (Accepts a request ID, a boolean decision, and an optional string reason)
    • Cancel a request (Accepts a request ID and an optional string reason)
    • Consume an approved request and open the tap (Accepts a request ID)
  • documentation_requirement
    • Document the reason for the release of asset (Accepts a string reason)
  • delay_requirement
    • Create a request to open the tap (Accepts a request_type argument)
    • Veto a request to open the tap (Accepts a request ID and an optional string reason)
    • Cancel a request (Accepts a request ID and an optional string reason)
    • Consume a matured request and open the tap (Accepts a request ID)
  • hash_preimage_requirement
    • Reveal the hash preimage and open the tap (Accepts a data buffer)
  • ticket_requirement
    • Redeem a ticket and open the tap (Accepts a ticket_type argument)
  • exchange_requirement
    • Reset the amount released (No arguments; meter is required to be at zero when processing)

Please note that while this specification attempts to provide a sufficient level of technical detail to convey the essence of Tanks and Taps, some detail has been elided for brevity, and the final implementation may diverge from the specification in order to improve the correctness, stability, efficiency, maintainability, or functionality of the Tanks and Taps framework.

Discussion and Summary for Shareholders

The proposed modifications to the BitShares protocol will add eight new operation types, one new database object, and several new committee-controlled chain parameters. These modifications add new features, and do not modify or restrict any existing features, and therefore all currently supported use cases should be unaffected. In return, however, the new features will provide a powerful platform for financial dapp and smart contract development, and this platform can be augmented to become even more powerful in the future, requiring only minimal changes to support additional use cases. The proposed changes, in conjunction with future updates, will make BitShares increasingly suitable as a financial dapp platform, notably offering dapp developers simplified development and a reduced time to market as compared with Turing Complete Smart Contract Platform alternatives which offer greater flexibility at the price of increased complexity.

Copyright

This document is created for the betterment of humanity and is hereby placed into the public domain.