Skip to content

Commit 1a1edf0

Browse files
authored
Merge pull request #217 from semiotic-ai/gusinacio/documentation
docs!: create docs and readme.
2 parents 4b83a3a + 2a2117b commit 1a1edf0

File tree

26 files changed

+558
-264
lines changed

26 files changed

+558
-264
lines changed

README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,71 @@
11
# Timeline Aggregation Protocol (TAP)
2+
3+
## Overview
4+
5+
The TAP (Timeline Aggregation Protocol) facilitates a series of payments from a
6+
sender to a receiver (TAP Receipts), who aggregates these payments into a single
7+
payment (a Receipt Aggregate Voucher, or RAV). This aggregate payment can then be
8+
verified on-chain by a payment verifier, reducing the number of transactions and
9+
simplifying the payment process.
10+
11+
## Key Components
12+
13+
- **Sender:** Initiates the payment.
14+
- **Receiver:** Receives the payment.
15+
- **Signers:** Multiple signers authorized by the sender to sign receipts.
16+
- **State Channel:** A one-way channel opened by the sender with the receiver
17+
for sending receipts.
18+
- **Receipt:** A record of payment sent by the sender to the receiver.
19+
- **ReceiptAggregateVoucher (RAV):** A signed message containing the aggregate
20+
value of the receipts.
21+
- **tap_aggregator:** A service managed by the sender that aggregates receipts
22+
on the receiver's request into a signed RAV.
23+
- **EscrowAccount:** An account created in the blockchain to hold funds for
24+
the sender-receiver pair.
25+
26+
## Security Measures
27+
28+
- The protocol uses asymmetric cryptography (ECDSA secp256k1) to sign and
29+
verify messages, ensuring the integrity of receipts and RAVs.
30+
31+
## Process
32+
33+
1. **Opening a State Channel:** A state channel is opened via a blockchain
34+
contract, creating an EscrowAccount for the sender-receiver pair.
35+
2. **Sending Receipts:** The sender sends receipts to the receiver through the
36+
state channel.
37+
3. **Storing Receipts:** The receiver stores the receipts and tracks the
38+
aggregate payment.
39+
4. **Creating a RAV Request:** A RAV request consists of a list of receipts and,
40+
optionally, the previous RAV.
41+
5. **Signing the RAV:** The receiver sends the RAV request to the tap_aggregator,
42+
which signs it into a new RAV.
43+
6. **Tracking Aggregate Value:** The receiver tracks the aggregate value and
44+
new receipts since the last RAV.
45+
7. **Requesting a New RAV:** The receiver sends new receipts and the last RAV
46+
to the tap_aggregator for a new RAV.
47+
8. **Closing the State Channel:** When the allocation period ends, the receiver
48+
can send the last RAV to the blockchain and receive payment from the EscrowAccount.
49+
50+
## Performance Considerations
51+
52+
- The primary performance limitations are the time required to verify receipts
53+
and network limitations for sending requests to the tap_aggregator.
54+
55+
## Use Cases
56+
57+
- The TAP protocol is suitable for systems that need unidirectional, parallel
58+
micro-payments that are too expensive to redeem individually on-chain. By
59+
aggregating operations off-chain and redeeming them in one transaction, costs
60+
are drastically reduced.
61+
62+
## Compatibility
63+
64+
- The current implementation is for EVM-compatible blockchains, with most of the
65+
system being off-chain.
66+
67+
## Contributing
68+
69+
Contributions are welcome! Please submit a pull request or open an issue to
70+
discuss potential changes.
71+
Also, make sure to follow the [Contributing Guide](https://github.com/semiotic-ai/timeline-aggregation-protocol/blob/main/CONTRIBUTING.md).

tap_core/src/error.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,73 @@ use ethers_core::types::SignatureError;
1111
use std::result::Result as StdResult;
1212
use thiserror::Error as ThisError;
1313

14+
/// Error type for the TAP protocol
1415
#[derive(ThisError, Debug)]
1516
pub enum Error {
17+
/// Error when trying to aggregate receipts and the result overflows
1618
#[error("Aggregating receipt results in overflow")]
1719
AggregateOverflow,
18-
#[error("Failed to encode to EIP712 hash:\n{source_error_message}")]
19-
EIP712EncodeError { source_error_message: String },
20-
#[error(
21-
"Unexpected check: \"{check_string}\". Only checks provided in initial checklist are valid"
22-
)]
23-
InvalidCheckError { check_string: String },
24-
#[error("The requested action is invalid for current receipt state: {state}")]
25-
InvalidStateForRequestedAction { state: String },
20+
/// Error when Rust fails to get the current system time
2621
#[error("Failed to get current system time: {source_error_message} ")]
2722
InvalidSystemTime { source_error_message: String },
23+
/// `ethers` wallet error
2824
#[error(transparent)]
2925
WalletError(#[from] WalletError),
26+
/// Error when signature verification fails
3027
#[error(transparent)]
3128
SignatureError(#[from] SignatureError),
32-
#[error("Recovered sender address invalid {address}")]
33-
InvalidRecoveredSigner { address: Address },
29+
30+
/// Error when the received RAV does not match the expected RAV
3431
#[error("Received RAV does not match expexted RAV")]
3532
InvalidReceivedRAV {
3633
received_rav: ReceiptAggregateVoucher,
3734
expected_rav: ReceiptAggregateVoucher,
3835
},
36+
/// Generic error from the adapter
3937
#[error("Error from adapter.\n Caused by: {source_error}")]
4038
AdapterError { source_error: anyhow::Error },
39+
/// Error when no valid receipts are found for a RAV request
4140
#[error("Failed to produce rav request, no valid receipts")]
4241
NoValidReceiptsForRAVRequest,
42+
43+
/// Error when the previous RAV allocation id does not match the allocation id from the new receipt
4344
#[error("Previous RAV allocation id ({prev_id}) doesn't match the allocation id from the new receipt ({new_id}).")]
4445
RavAllocationIdMismatch { prev_id: String, new_id: String },
46+
47+
/// Error when all receipts do not have the same allocation id
48+
///
49+
/// Used in tap_aggregator
4550
#[error("All receipts should have the same allocation id, but they don't")]
4651
RavAllocationIdNotUniform,
52+
/// Error when the receipt signature is duplicated.
53+
///
54+
/// Used in tap_aggregator
4755
#[error("Duplicate receipt signature: {0}")]
4856
DuplicateReceiptSignature(String),
4957
#[error(
5058
"Receipt timestamp ({receipt_ts}) is less or equal than previous rav timestamp ({rav_ts})"
5159
)]
5260
ReceiptTimestampLowerThanRav { rav_ts: u64, receipt_ts: u64 },
61+
62+
/// Error when the min timestamp is greater than the max timestamp
63+
/// Used by [`crate::manager::Manager::create_rav_request()`]
5364
#[error("Timestamp range error: min_timestamp_ns: {min_timestamp_ns}, max_timestamp_ns: {max_timestamp_ns}. Adjust timestamp buffer.")]
5465
TimestampRangeError {
5566
min_timestamp_ns: u64,
5667
max_timestamp_ns: u64,
5768
},
5869

70+
/// Error on the receipt side
5971
#[error("Receipt error: {0}")]
6072
ReceiptError(#[from] ReceiptError),
6173

74+
/// Error when the recovered signer address is invalid
75+
/// Used by [`crate::manager::adapters::EscrowHandler`]
76+
#[error("Recovered sender address invalid {address}")]
77+
InvalidRecoveredSigner { address: Address },
78+
79+
/// Indicates a failure while verifying the signer
80+
/// Used by [`crate::manager::adapters::EscrowHandler`]
6281
#[error("Failed to check the signer: {0}")]
6382
FailedToVerifySigner(String),
6483
}

tap_core/src/lib.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Copyright 2023-, Semiotic AI, Inc.
22
// SPDX-License-Identifier: Apache-2.0
3-
4-
//! The Timeline Aggregation Protocol (TAP) is a micro-trust
5-
//! state channel payment solution allowing one-way payments
6-
//! from a payment sender to be aggregated then cheaply
7-
//! verified on-chain by a payment receiver.
3+
#![doc = include_str!("../../README.md")]
4+
//! ## Getting started
5+
//!
6+
//! To get started with the TAP protocol, take a look on the [`manager`] module
7+
//! to see how to manage the state channel and implement the needed adapters.
88
99
use std::time::{SystemTime, UNIX_EPOCH};
1010

@@ -17,7 +17,8 @@ pub mod rav;
1717
pub mod receipt;
1818
pub mod signed_message;
1919

20-
pub use error::{Error, Result};
20+
pub use error::Error;
21+
use error::Result;
2122

2223
fn get_current_timestamp_u64_ns() -> Result<u64> {
2324
Ok(SystemTime::now()
@@ -28,6 +29,21 @@ fn get_current_timestamp_u64_ns() -> Result<u64> {
2829
.as_nanos() as u64)
2930
}
3031

32+
/// The EIP712 domain separator builder for the TAP protocol.
33+
///
34+
/// This is the current domain separator that is used for the [EIP712](https://eips.ethereum.org/EIPS/eip-712) signature scheme.
35+
///
36+
///
37+
/// It's used to validate the signature of the `ReceiptAggregateVoucher` and `Receipt` structs.
38+
///
39+
/// You can take a look on deployed [TAPVerfiers](https://github.com/semiotic-ai/timeline-aggregation-protocol-contracts/blob/4dc87fc616680c924b99dbaf285bdd449c777261/src/TAPVerifier.sol)
40+
/// contracts [here](https://github.com/semiotic-ai/timeline-aggregation-protocol-contracts/blob/4dc87fc616680c924b99dbaf285bdd449c777261/addresses.json)
41+
///
42+
/// The domain separator is defined as:
43+
/// - `name`: "TAP"
44+
/// - `version`: "1"
45+
/// - `chain_id`: The chain ID of the chain where the domain separator is deployed.
46+
/// - `verifying_contract`: The address of the contract that is verifying the signature.
3147
pub fn tap_eip712_domain(
3248
chain_id: u64,
3349
verifying_contract_address: alloy_primitives::Address,

tap_core/src/manager/adapters/escrow.rs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,62 +7,41 @@ use async_trait::async_trait;
77

88
use crate::{
99
rav::SignedRAV,
10-
receipt::{AwaitingReserve, ReceiptError, ReceiptResult, ReceiptWithState},
10+
receipt::{state::AwaitingReserve, ReceiptError, ReceiptResult, ReceiptWithState},
1111
Error,
1212
};
1313

14-
/// `EscrowAdapter` defines a trait for adapters to handle escrow related operations.
15-
///
16-
/// This trait is designed to be implemented by users of this library who want to
17-
/// customize the management of local accounting for available escrow. The error handling is also
18-
/// customizable by defining an `AdapterError` type, which must implement both `Error`
19-
/// and `Debug` from the standard library.
20-
///
21-
/// # Usage
22-
///
23-
/// The `get_available_escrow` method should be used to retrieve the local accounting
24-
/// amount of available escrow for a specified sender. Any errors during this operation
25-
/// should be captured and returned in the `AdapterError` format.
26-
///
27-
/// The `subtract_escrow` method is used to deduct a specified value from the local accounting
28-
/// of available escrow of a specified sender. Any errors during this operation should be captured
29-
/// and returned as an `AdapterError`.
30-
///
31-
/// This trait is utilized by [crate::tap_manager], which relies on these
32-
/// operations for managing escrow.
14+
/// Manages the escrow operations
3315
///
3416
/// # Example
3517
///
36-
/// For example code see [crate::adapters::escrow_adapter_mock]
18+
/// For example code see [crate::manager::context::memory::EscrowStorage]
3719
3820
#[async_trait]
3921
pub trait EscrowHandler: Send + Sync {
4022
/// Defines the user-specified error type.
4123
///
42-
/// This error type should implement the `Error` and `Debug` traits from the standard library.
24+
/// This error type should implement the `Error` and `Debug` traits from
25+
/// the standard library.
4326
/// Errors of this type are returned to the user when an operation fails.
4427
type AdapterError: std::error::Error + std::fmt::Debug + Send + Sync + 'static;
4528

4629
/// Retrieves the local accounting amount of available escrow for a specified sender.
47-
///
48-
/// This method should be implemented to fetch the local accounting amount of available escrow for a
49-
/// specified sender from your system. Any errors that occur during this process should
50-
/// be captured and returned as an `AdapterError`.
5130
async fn get_available_escrow(&self, sender_id: Address) -> Result<u128, Self::AdapterError>;
5231

5332
/// Deducts a specified value from the local accounting of available escrow for a specified sender.
54-
///
55-
/// This method should be implemented to deduct a specified value from the local accounting of
56-
/// available escrow of a specified sender in your system. Any errors that occur during this
57-
/// process should be captured and returned as an `AdapterError`.
5833
async fn subtract_escrow(
5934
&self,
6035
sender_id: Address,
6136
value: u128,
6237
) -> Result<(), Self::AdapterError>;
6338

39+
/// Verifies the signer of the receipt
40+
///
41+
/// Used by [`Self::check_rav_signature`] to verify the signer of the receipt
6442
async fn verify_signer(&self, signer_address: Address) -> Result<bool, Self::AdapterError>;
6543

44+
/// Checks and reserves escrow for the received receipt
6645
async fn check_and_reserve_escrow(
6746
&self,
6847
received_receipt: &ReceiptWithState<AwaitingReserve>,
@@ -87,6 +66,7 @@ pub trait EscrowHandler: Send + Sync {
8766
Ok(())
8867
}
8968

69+
/// Checks the signature of the RAV
9070
async fn check_rav_signature(
9171
&self,
9272
signed_rav: &SignedRAV,

tap_core/src/manager/adapters/mod.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
// Copyright 2023-, Semiotic AI, Inc.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
//! The adapters module provides interfaces that allow flexibility in storing and verifying TAP components.
4+
//! Context adapters for the TAP manager.
55
//!
6-
//! Each adapter should be defined by the user of the library based on their specific storage and verification requirements. This modular design
7-
//! allows for easy integration with various storage solutions and verification procedures, thereby making the library adaptable to a wide range
8-
//! of use cases.
9-
//!
10-
//! The following adapters are defined:
11-
//! - `escrow_adapter`: An interface for checking and updating escrow availability.
12-
//! - `rav_storage_adapter`: An interface for storing and retrieving/replacing RAVs.
13-
//! - `receipt_checks_adapter`: An interface for verifying TAP receipts.
14-
//! - `receipt_storage_adapter`: An interface for storing, retrieving, updating, and removing TAP receipts.
15-
//!
16-
//! In addition, this module also includes mock implementations of each adapter for testing and example purposes.
6+
//! Each adapter should be defined by the user of the library based on their
7+
//! specific storage and verification requirements. This modular design
8+
//! allows for easy integration with various storage solutions and verification
9+
//! procedures, thereby making the library adaptable to a wide range of use cases.
1710
1811
mod escrow;
1912
mod rav;

tap_core/src/manager/adapters/rav.rs

Lines changed: 11 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,73 +5,46 @@ use async_trait::async_trait;
55

66
use crate::rav::SignedRAV;
77

8-
/// `RAVStore` defines a trait for write storage adapters to handle `SignedRAV` data.
9-
///
10-
/// This trait is designed to be implemented by users of this library who want to
11-
/// customize the write storage behavior of `SignedRAV` data. The error handling is also
12-
/// customizable by defining an `AdapterError` type, which must implement both `Error`
13-
/// and `Debug` from the standard library.
14-
///
15-
/// # Usage
16-
///
17-
/// The `update_last_rav` method should be used to update the last validated `SignedRAV`
18-
/// in the storage managed by the adapter. Errors during this operation should be
19-
/// captured and returned in the `AdapterError` format.
20-
///
21-
/// This trait is utilized by [crate::tap_manager], which relies on these
22-
/// operations for working with `SignedRAV` data.
8+
/// Stores the latest RAV in the storage.
239
///
2410
/// # Example
2511
///
26-
/// For example code see [crate::adapters::rav_storage_adapter_mock]
12+
/// For example code see [crate::manager::context::memory::RAVStorage]
2713
2814
#[async_trait]
2915
pub trait RAVStore {
3016
/// Defines the user-specified error type.
3117
///
32-
/// This error type should implement the `Error` and `Debug` traits from the standard library.
18+
/// This error type should implement the `Error` and `Debug` traits from
19+
/// the standard library.
3320
/// Errors of this type are returned to the user when an operation fails.
3421
type AdapterError: std::error::Error + std::fmt::Debug + Send + Sync + 'static;
3522

3623
/// Updates the storage with the latest validated `SignedRAV`.
3724
///
38-
/// This method should be implemented to store the most recent validated `SignedRAV` into your chosen storage system.
39-
/// Any errors that occur during this process should be captured and returned as an `AdapterError`.
25+
/// This method should be implemented to store the most recent validated
26+
/// `SignedRAV` into your chosen storage system. Any errors that occur
27+
/// during this process should be captured and returned as an `AdapterError`.
4028
async fn update_last_rav(&self, rav: SignedRAV) -> Result<(), Self::AdapterError>;
4129
}
4230

43-
/// `RAVRead` defines a trait for read storage adapters to handle `SignedRAV` data.
44-
///
45-
/// This trait is designed to be implemented by users of this library who want to
46-
/// customize the read storage behavior of `SignedRAV` data. The error handling is also
47-
/// customizable by defining an `AdapterError` type, which must implement both `Error`
48-
/// and `Debug` from the standard library.
49-
///
50-
/// # Usage
51-
///
52-
/// The `last_rav` method is designed to fetch the latest `SignedRAV` from the storage.
53-
/// If there is no `SignedRAV` available, it should return `None`. Any errors during
54-
/// this operation should be captured and returned as an `AdapterError`.
55-
///
56-
/// This trait is utilized by [crate::tap_manager], which relies on these
57-
/// operations for working with `SignedRAV` data.
31+
/// Reads the RAV from storage
5832
///
5933
/// # Example
6034
///
61-
/// For example code see [crate::adapters::rav_storage_adapter_mock]
35+
/// For example code see [crate::manager::context::memory::RAVStorage]
6236
6337
#[async_trait]
6438
pub trait RAVRead {
6539
/// Defines the user-specified error type.
6640
///
67-
/// This error type should implement the `Error` and `Debug` traits from the standard library.
41+
/// This error type should implement the `Error` and `Debug` traits from
42+
/// the standard library.
6843
/// Errors of this type are returned to the user when an operation fails.
6944
type AdapterError: std::error::Error + std::fmt::Debug + Send + Sync + 'static;
7045

7146
/// Retrieves the latest `SignedRAV` from the storage.
7247
///
73-
/// This method should be implemented to fetch the latest `SignedRAV` from your storage system.
7448
/// If no `SignedRAV` is available, this method should return `None`.
75-
/// Any errors that occur during this process should be captured and returned as an `AdapterError`.
7649
async fn last_rav(&self) -> Result<Option<SignedRAV>, Self::AdapterError>;
7750
}

0 commit comments

Comments
 (0)