Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/contracts/src/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod nonce;
pub mod signature_verifier;
pub mod stablecoin_dex;
pub mod tip20;
pub mod tip20_channel_escrow;
pub mod tip20_factory;
pub mod tip403_registry;
pub mod tip_fee_manager;
Expand All @@ -20,6 +21,7 @@ pub use signature_verifier::*;
pub use stablecoin_dex::*;
pub use tip_fee_manager::*;
pub use tip20::*;
pub use tip20_channel_escrow::*;
pub use tip20_factory::*;
pub use tip403_registry::*;
pub use validator_config::*;
Expand Down
235 changes: 235 additions & 0 deletions crates/contracts/src/precompiles/tip20_channel_escrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
pub use ITIP20ChannelEscrow::{
ITIP20ChannelEscrowErrors as TIP20ChannelEscrowError,
ITIP20ChannelEscrowEvents as TIP20ChannelEscrowEvent,
};
use alloy_primitives::{Address, address};

pub const TIP20_CHANNEL_ESCROW_ADDRESS: Address =
address!("0x4D50500000000000000000000000000000000000");

crate::sol! {
#[derive(Debug, PartialEq, Eq)]
#[sol(abi)]
#[allow(clippy::too_many_arguments)]
interface ITIP20ChannelEscrow {
struct ChannelDescriptor {
address payer;
address payee;
address operator;
address token;
bytes32 salt;
address authorizedSigner;
bytes32 openTxHash;
}

struct ChannelState {
uint96 settled;
uint96 deposit;
uint32 closeData;
}

struct Channel {
ChannelDescriptor descriptor;
ChannelState state;
}

function CLOSE_GRACE_PERIOD() external view returns (uint64);
function VOUCHER_TYPEHASH() external view returns (bytes32);

function open(
address payee,
address operator,
address token,
uint96 deposit,
bytes32 salt,
address authorizedSigner
)
external
returns (bytes32 channelId);

function settle(
ChannelDescriptor calldata descriptor,
uint96 cumulativeAmount,
bytes calldata signature
)
external;

function topUp(
ChannelDescriptor calldata descriptor,
uint96 additionalDeposit
)
external;

function close(
ChannelDescriptor calldata descriptor,
uint96 cumulativeAmount,
uint96 captureAmount,
bytes calldata signature
)
external;

function requestClose(ChannelDescriptor calldata descriptor) external;

function withdraw(ChannelDescriptor calldata descriptor) external;

function getChannel(ChannelDescriptor calldata descriptor)
external
view
returns (Channel memory);

function getChannelState(bytes32 channelId) external view returns (ChannelState memory);

function getChannelStatesBatch(bytes32[] calldata channelIds)
external
view
returns (ChannelState[] memory);

function computeChannelId(
address payer,
address payee,
address operator,
address token,
bytes32 salt,
address authorizedSigner,
bytes32 openTxHash
)
external
view
returns (bytes32);

function getVoucherDigest(bytes32 channelId, uint96 cumulativeAmount)
external
view
returns (bytes32);

function domainSeparator() external view returns (bytes32);

event ChannelOpened(
bytes32 indexed channelId,
address indexed payer,
address indexed payee,
address operator,
address token,
address authorizedSigner,
bytes32 salt,
bytes32 openTxHash,
uint96 deposit
);

event Settled(
bytes32 indexed channelId,
address indexed payer,
address indexed payee,
uint96 cumulativeAmount,
uint96 deltaPaid,
uint96 newSettled
);

event TopUp(
bytes32 indexed channelId,
address indexed payer,
address indexed payee,
uint96 additionalDeposit,
uint96 newDeposit
);

event CloseRequested(
bytes32 indexed channelId,
address indexed payer,
address indexed payee,
uint256 closeGraceEnd
);

event ChannelClosed(
bytes32 indexed channelId,
address indexed payer,
address indexed payee,
uint96 settledToPayee,
uint96 refundedToPayer
);

event CloseRequestCancelled(
bytes32 indexed channelId,
address indexed payer,
address indexed payee
);

error ChannelAlreadyExists();
error ChannelNotFound();
error NotPayer();
error NotPayee();
error NotPayeeOrOperator();
error InvalidPayee();
error InvalidToken();
error ZeroDeposit();
error InvalidSignature();
error AmountExceedsDeposit();
error AmountNotIncreasing();
error CaptureAmountInvalid();
error CloseNotReady();
error DepositOverflow();
error TransferFailed();
}
}

impl TIP20ChannelEscrowError {
pub const fn channel_already_exists() -> Self {
Self::ChannelAlreadyExists(ITIP20ChannelEscrow::ChannelAlreadyExists {})
}

pub const fn channel_not_found() -> Self {
Self::ChannelNotFound(ITIP20ChannelEscrow::ChannelNotFound {})
}

pub const fn not_payer() -> Self {
Self::NotPayer(ITIP20ChannelEscrow::NotPayer {})
}

pub const fn not_payee() -> Self {
Self::NotPayee(ITIP20ChannelEscrow::NotPayee {})
}

pub const fn not_payee_or_operator() -> Self {
Self::NotPayeeOrOperator(ITIP20ChannelEscrow::NotPayeeOrOperator {})
}

pub const fn invalid_payee() -> Self {
Self::InvalidPayee(ITIP20ChannelEscrow::InvalidPayee {})
}

pub const fn invalid_token() -> Self {
Self::InvalidToken(ITIP20ChannelEscrow::InvalidToken {})
}

pub const fn zero_deposit() -> Self {
Self::ZeroDeposit(ITIP20ChannelEscrow::ZeroDeposit {})
}

pub const fn invalid_signature() -> Self {
Self::InvalidSignature(ITIP20ChannelEscrow::InvalidSignature {})
}

pub const fn amount_exceeds_deposit() -> Self {
Self::AmountExceedsDeposit(ITIP20ChannelEscrow::AmountExceedsDeposit {})
}

pub const fn amount_not_increasing() -> Self {
Self::AmountNotIncreasing(ITIP20ChannelEscrow::AmountNotIncreasing {})
}

pub const fn capture_amount_invalid() -> Self {
Self::CaptureAmountInvalid(ITIP20ChannelEscrow::CaptureAmountInvalid {})
}

pub const fn close_not_ready() -> Self {
Self::CloseNotReady(ITIP20ChannelEscrow::CloseNotReady {})
}

pub const fn deposit_overflow() -> Self {
Self::DepositOverflow(ITIP20ChannelEscrow::DepositOverflow {})
}

pub const fn transfer_failed() -> Self {
Self::TransferFailed(ITIP20ChannelEscrow::TransferFailed {})
}
}
6 changes: 5 additions & 1 deletion crates/evm/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ use reth_revm::{
use std::collections::{HashMap, HashSet};
use tempo_chainspec::{TempoChainSpec, hardfork::TempoHardforks};
use tempo_contracts::precompiles::{
ADDRESS_REGISTRY_ADDRESS, SIGNATURE_VERIFIER_ADDRESS, VALIDATOR_CONFIG_V2_ADDRESS,
ADDRESS_REGISTRY_ADDRESS, SIGNATURE_VERIFIER_ADDRESS, TIP20_CHANNEL_ESCROW_ADDRESS,
VALIDATOR_CONFIG_V2_ADDRESS,
};
use tempo_primitives::{
SubBlock, SubBlockMetadata, TempoReceipt, TempoTxEnvelope, TempoTxType,
Expand Down Expand Up @@ -444,6 +445,9 @@ where
self.deploy_precompile_at_boundary(SIGNATURE_VERIFIER_ADDRESS)?;
self.deploy_precompile_at_boundary(ADDRESS_REGISTRY_ADDRESS)?;
}
if self.inner.spec.is_t5_active_at_timestamp(timestamp) {
self.deploy_precompile_at_boundary(TIP20_CHANNEL_ESCROW_ADDRESS)?;
}

Ok(())
}
Expand Down
12 changes: 10 additions & 2 deletions crates/precompiles/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use revm::{
};
use tempo_contracts::precompiles::{
AccountKeychainError, AddrRegistryError, FeeManagerError, NonceError, RolesAuthError,
SignatureVerifierError, StablecoinDEXError, TIP20FactoryError, TIP403RegistryError,
TIPFeeAMMError, UnknownFunctionSelector, ValidatorConfigError, ValidatorConfigV2Error,
SignatureVerifierError, StablecoinDEXError, TIP20ChannelEscrowError, TIP20FactoryError,
TIP403RegistryError, TIPFeeAMMError, UnknownFunctionSelector, ValidatorConfigError,
ValidatorConfigV2Error,
};

/// Top-level error type for all Tempo precompile operations
Expand All @@ -42,6 +43,10 @@ pub enum TempoPrecompileError {
#[error("TIP20 factory error: {0:?}")]
TIP20Factory(TIP20FactoryError),

/// Error from TIP-20 channel escrow
#[error("TIP20 channel escrow error: {0:?}")]
TIP20ChannelEscrowError(TIP20ChannelEscrowError),

/// Error from roles auth
#[error("Roles auth error: {0:?}")]
RolesAuthError(RolesAuthError),
Expand Down Expand Up @@ -137,6 +142,7 @@ impl TempoPrecompileError {
Self::OutOfGas | Self::Fatal(_) | Self::Panic(_) => true,
Self::StablecoinDEX(_)
| Self::TIP20(_)
| Self::TIP20ChannelEscrowError(_)
| Self::NonceError(_)
| Self::TIP20Factory(_)
| Self::RolesAuthError(_)
Expand Down Expand Up @@ -177,6 +183,7 @@ impl TempoPrecompileError {
Self::StablecoinDEX(e) => e.abi_encode().into(),
Self::TIP20(e) => e.abi_encode().into(),
Self::TIP20Factory(e) => e.abi_encode().into(),
Self::TIP20ChannelEscrowError(e) => e.abi_encode().into(),
Self::RolesAuthError(e) => e.abi_encode().into(),
Self::AddrRegistryError(e) => e.abi_encode().into(),
Self::TIP403RegistryError(e) => e.abi_encode().into(),
Expand Down Expand Up @@ -251,6 +258,7 @@ pub fn error_decoder_registry() -> TempoPrecompileErrorRegistry {
add_errors_to_registry(&mut registry, TempoPrecompileError::StablecoinDEX);
add_errors_to_registry(&mut registry, TempoPrecompileError::TIP20);
add_errors_to_registry(&mut registry, TempoPrecompileError::TIP20Factory);
add_errors_to_registry(&mut registry, TempoPrecompileError::TIP20ChannelEscrowError);
add_errors_to_registry(&mut registry, TempoPrecompileError::RolesAuthError);
add_errors_to_registry(&mut registry, TempoPrecompileError::AddrRegistryError);
add_errors_to_registry(&mut registry, TempoPrecompileError::TIP403RegistryError);
Expand Down
Loading