From 3f7d912d2b0b9874b68a8b0730dd212304cb9d29 Mon Sep 17 00:00:00 2001
From: 0xrusowsky <0xrusowsky@proton.me>
Date: Tue, 21 Apr 2026 12:19:58 +0200
Subject: [PATCH 1/5] chore: align with actual precompile impls
---
src/interfaces/IFeeAMM.sol | 7 +++---
src/interfaces/IFeeManager.sol | 32 +++++++++++++++++++++---
src/interfaces/INonce.sol | 9 +++++++
src/interfaces/ISignatureVerifier.sol | 2 ++
src/interfaces/IStablecoinDEX.sol | 14 +++++------
src/interfaces/ITIP20.sol | 22 ++++++++++------
src/interfaces/ITIP20Factory.sol | 5 ++++
src/interfaces/ITIP20RewardsRegistry.sol | 2 ++
src/interfaces/ITIP20RolesAuth.sol | 5 ++++
src/interfaces/IValidatorConfig.sol | 22 ++++++++++++++++
src/interfaces/IValidatorConfigV2.sol | 3 +++
11 files changed, 101 insertions(+), 22 deletions(-)
diff --git a/src/interfaces/IFeeAMM.sol b/src/interfaces/IFeeAMM.sol
index 2658ef6..73b3bb5 100644
--- a/src/interfaces/IFeeAMM.sol
+++ b/src/interfaces/IFeeAMM.sol
@@ -2,14 +2,13 @@
pragma solidity >=0.8.13 <0.9.0;
interface IFeeAMM {
+ error DivisionByZero();
error IdenticalAddresses();
+ error InvalidAmount();
+ error InvalidSwapCalculation();
error InvalidToken();
error InsufficientLiquidity();
error InsufficientReserves();
- error InvalidAmount();
- error DivisionByZero();
- error InvalidSwapCalculation();
- error InvalidCurrency();
event Burn(
address indexed sender,
diff --git a/src/interfaces/IFeeManager.sol b/src/interfaces/IFeeManager.sol
index 531cfc3..49bf99d 100644
--- a/src/interfaces/IFeeManager.sol
+++ b/src/interfaces/IFeeManager.sol
@@ -4,19 +4,45 @@ pragma solidity >=0.8.13 <0.9.0;
import {IFeeAMM} from "./IFeeAMM.sol";
interface IFeeManager is IFeeAMM {
+ error CannotChangeWithinBlock();
+ error InsufficientFeeTokenBalance();
+
event UserTokenSet(address indexed user, address indexed token);
event ValidatorTokenSet(address indexed validator, address indexed token);
event FeesDistributed(address indexed validator, address indexed token, uint256 amount);
+ /// @notice Transfers a validator's accumulated fee balance to their address and zeroes the
+ /// ledger. No-ops when the balance is zero.
+ /// @param validator The validator to pay out.
+ /// @param token The fee token to distribute.
function distributeFees(address validator, address token) external;
+ /// @notice Returns the accumulated fee balance for a validator in a given token.
+ /// @param validator The validator address.
+ /// @param token The fee token address.
+ /// @return The amount of fees accumulated and pending distribution.
function collectedFees(address validator, address token) external view returns (uint256);
+ /// @notice Sets the caller's preferred fee token for paying transaction fees.
+ /// Must be a USD-denominated TIP-20 registered in TIP20Factory.
+ /// @param token The USD-denominated TIP-20 token address.
function setUserToken(address token) external;
+ /// @notice Sets the caller's preferred fee token for receiving transaction fees.
+ /// Must be a USD-denominated TIP-20 registered in TIP20Factory.
+ /// Reverts with `CannotChangeWithinBlock` if the caller is the current block's beneficiary.
+ /// @param token The USD-denominated TIP-20 token address.
function setValidatorToken(address token) external;
- function userTokens(address) external view returns (address);
-
- function validatorTokens(address) external view returns (address);
+ /// @notice Returns the raw stored fee token preference for a user.
+ /// Returns the zero address if no preference has been set.
+ /// @param user The user address.
+ /// @return The token address stored for the user, or zero if unset.
+ function userTokens(address user) external view returns (address);
+
+ /// @notice Returns the raw stored fee token preference for a validator.
+ /// Returns the zero address if no preference has been set.
+ /// @param validator The validator address.
+ /// @return The token address stored for the validator, or zero if unset.
+ function validatorTokens(address validator) external view returns (address);
}
diff --git a/src/interfaces/INonce.sol b/src/interfaces/INonce.sol
index 45da5d3..b2537c0 100644
--- a/src/interfaces/INonce.sol
+++ b/src/interfaces/INonce.sol
@@ -23,6 +23,15 @@ interface INonce {
/// @notice Thrown when a nonce value would overflow
error NonceOverflow();
+ /// @notice Thrown when an expiring nonce has already been used
+ error ExpiringNonceReplay();
+
+ /// @notice Thrown when the expiring nonce set is full and cannot accept more entries
+ error ExpiringNonceSetFull();
+
+ /// @notice Thrown when the expiry timestamp for an expiring nonce is invalid
+ error InvalidExpiringNonceExpiry();
+
/// @notice Get the current nonce for a specific account and nonce key
/// @param account The account address
/// @param nonceKey The nonce key (must be > 0, protocol nonce key 0 not supported)
diff --git a/src/interfaces/ISignatureVerifier.sol b/src/interfaces/ISignatureVerifier.sol
index 56df01e..b8a3afb 100644
--- a/src/interfaces/ISignatureVerifier.sol
+++ b/src/interfaces/ISignatureVerifier.sol
@@ -5,7 +5,9 @@ pragma solidity >=0.8.13 <0.9.0;
/// @notice Interface for the TIP-1020 Signature Verification Precompile
/// @dev Deployed at 0x5165300000000000000000000000000000000000
interface ISignatureVerifier {
+ /// @notice Thrown when the signature bytes are not in the expected encoding format
error InvalidFormat();
+ /// @notice Thrown when the signature verification fails
error InvalidSignature();
/// @notice Recovers the signer of a Tempo signature (secp256k1, P256, WebAuthn).
diff --git a/src/interfaces/IStablecoinDEX.sol b/src/interfaces/IStablecoinDEX.sol
index e1a72f7..b4fdd31 100644
--- a/src/interfaces/IStablecoinDEX.sol
+++ b/src/interfaces/IStablecoinDEX.sol
@@ -75,19 +75,19 @@ interface IStablecoinDEX {
);
event PairCreated(bytes32 indexed key, address indexed base, address indexed quote);
- function MAX_PRICE() external view returns (uint32);
+ function MAX_PRICE() external pure returns (uint32);
- function MAX_TICK() external view returns (int16);
+ function MAX_TICK() external pure returns (int16);
- function MIN_PRICE() external view returns (uint32);
+ function MIN_PRICE() external pure returns (uint32);
- function MIN_TICK() external view returns (int16);
+ function MIN_TICK() external pure returns (int16);
- function TICK_SPACING() external view returns (int16);
+ function TICK_SPACING() external pure returns (int16);
- function PRICE_SCALE() external view returns (uint32);
+ function PRICE_SCALE() external pure returns (uint32);
- function MIN_ORDER_AMOUNT() external view returns (uint128);
+ function MIN_ORDER_AMOUNT() external pure returns (uint128);
function nextOrderId() external view returns (uint128);
diff --git a/src/interfaces/ITIP20.sol b/src/interfaces/ITIP20.sol
index 86adc07..34f21b1 100644
--- a/src/interfaces/ITIP20.sol
+++ b/src/interfaces/ITIP20.sol
@@ -12,18 +12,23 @@ interface ITIP20 {
/// @notice Error when an account has insufficient balance for the requested operation.
error InsufficientBalance(uint256 currentBalance, uint256 expectedBalance, address);
+ /// @notice Error when an invalid token amount is provided.
error InvalidAmount();
/// @notice Error when an invalid currency identifier is provided.
error InvalidCurrency();
+ /// @notice Error when an invalid quote token is provided.
error InvalidQuoteToken();
- error InvalidBaseToken();
+ /// @notice Error when an invalid token address is provided.
error InvalidToken();
+ /// @notice Error when an invalid transfer policy identifier is provided.
error InvalidTransferPolicyId();
/// @notice Error when attempting to transfer to an invalid recipient address.
error InvalidRecipient();
+ /// @notice Error when an invalid supply cap value is provided.
error InvalidSupplyCap();
+ /// @notice Error when there is no opted-in supply for the operation.
error NoOptedInSupply();
/// @notice Error when a transfer is blocked by the current transfer policy.
@@ -31,7 +36,14 @@ interface ITIP20 {
/// @notice Error when attempting to burn from a protected address.
error ProtectedAddress();
+ /// @notice Error when minting would exceed the supply cap.
error SupplyCapExceeded();
+ /// @notice Error when the transaction payload is invalid.
+ error InvalidPayload();
+ /// @notice Error when the caller lacks authorization for the requested action.
+ error Unauthorized();
+ /// @notice Error when that precompile instance has not been initialized yet.
+ error Uninitialized();
/// @notice Emitted when an allowance is set between owner and spender.
/// @param owner The address that owns the tokens.
@@ -183,8 +195,6 @@ interface ITIP20 {
function symbol() external view returns (string memory);
- function systemTransferFrom(address from, address to, uint256 amount) external returns (bool);
-
/// @notice Returns the total token supply.
/// @return The total amount of tokens in circulation.
function totalSupply() external view returns (uint256);
@@ -195,10 +205,6 @@ interface ITIP20 {
/// @return success True if the transfer was successful.
function transfer(address to, uint256 amount) external returns (bool);
- function transferFeePostTx(address to, uint256 refund, uint256 actualUsed) external;
-
- function transferFeePreTx(address from, uint256 amount) external;
-
/// @notice Transfers tokens from one address to another using allowance.
/// @param from The address to transfer tokens from.
/// @param to The address to transfer tokens to.
@@ -236,7 +242,7 @@ interface ITIP20 {
/// @dev Returns the total pending claimable reward amount, including stored balance and newly accrued rewards.
/// @param account The address to query pending rewards for.
/// @return The total pending claimable reward amount.
- function getPendingRewards(address account) external view returns (uint256);
+ function getPendingRewards(address account) external view returns (uint128);
// EIP-2612 Permit (TIP-1004)
diff --git a/src/interfaces/ITIP20Factory.sol b/src/interfaces/ITIP20Factory.sol
index d1c24ea..b77189a 100644
--- a/src/interfaces/ITIP20Factory.sol
+++ b/src/interfaces/ITIP20Factory.sol
@@ -6,8 +6,13 @@ import {ITIP20} from "./ITIP20.sol";
/// @title The interface for TIP-20 token factory
/// @notice Factory contract for creating and deploying TIP-20 compliant tokens
interface ITIP20Factory {
+ /// @notice Thrown when the computed token address falls within the reserved address range
error AddressReserved();
+ /// @notice Thrown when the computed token address is not in the reserved address range
+ error AddressNotReserved();
+ /// @notice Thrown when the provided quote token address is invalid
error InvalidQuoteToken();
+ /// @notice Thrown when a token at the computed address already exists
error TokenAlreadyExists(address tokenAddress);
/// @notice Emitted when a new TIP-20 token is created
diff --git a/src/interfaces/ITIP20RewardsRegistry.sol b/src/interfaces/ITIP20RewardsRegistry.sol
index 9dd08d5..874b261 100644
--- a/src/interfaces/ITIP20RewardsRegistry.sol
+++ b/src/interfaces/ITIP20RewardsRegistry.sol
@@ -4,7 +4,9 @@ pragma solidity >=0.8.13 <0.9.0;
/// @title Interface for TIP20RewardsRegistry
/// @notice Registry contract for all TIP20 reward streams
interface ITIP20RewardsRegistry {
+ /// @notice Thrown when attempting to modify streams that have already been finalized
error StreamsAlreadyFinalized();
+ /// @notice Thrown when the caller lacks authorization for the requested action
error Unauthorized();
/// @notice Add a token to the registry for a given stream end time.
diff --git a/src/interfaces/ITIP20RolesAuth.sol b/src/interfaces/ITIP20RolesAuth.sol
index 66d6466..aabe4c6 100644
--- a/src/interfaces/ITIP20RolesAuth.sol
+++ b/src/interfaces/ITIP20RolesAuth.sol
@@ -2,11 +2,16 @@
pragma solidity >=0.8.13 <0.9.0;
interface ITIP20RolesAuth {
+ /// @notice Thrown when the caller lacks the required role for the requested action
error Unauthorized();
event RoleMembershipUpdated(bytes32 indexed role, address indexed account, address indexed sender, bool hasRole);
event RoleAdminUpdated(bytes32 indexed role, bytes32 indexed newAdminRole, address indexed sender);
+ function hasRole(address account, bytes32 role) external view returns (bool);
+
+ function getRoleAdmin(bytes32 role) external view returns (bytes32);
+
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
diff --git a/src/interfaces/IValidatorConfig.sol b/src/interfaces/IValidatorConfig.sol
index 977ee9a..0166299 100644
--- a/src/interfaces/IValidatorConfig.sol
+++ b/src/interfaces/IValidatorConfig.sol
@@ -47,6 +47,28 @@ interface IValidatorConfig {
string outboundAddress;
}
+ /// @notice Get the total number of validators
+ /// @return The number of validators
+ function validatorCount() external view returns (uint64);
+
+ /// @notice Get validator info by address
+ /// @param validatorAddress The validator's address
+ /// @return publicKey The validator's communication public key
+ /// @return active Whether the validator is active
+ /// @return index The validator's index
+ /// @return addr The validator's address
+ /// @return inboundAddress The validator's inbound address
+ /// @return outboundAddress The validator's outbound address
+ function validators(address validatorAddress)
+ external
+ view
+ returns (bytes32 publicKey, bool active, uint64 index, address addr, string memory inboundAddress, string memory outboundAddress);
+
+ /// @notice Get validator address at a given array index
+ /// @param index The index in the validators array
+ /// @return The validator's address
+ function validatorsArray(uint256 index) external view returns (address);
+
/// @notice Get the complete set of validators
/// @return validators Array of all validators with their information
function getValidators() external view returns (Validator[] memory validators);
diff --git a/src/interfaces/IValidatorConfigV2.sol b/src/interfaces/IValidatorConfigV2.sol
index 18f03ec..35028b9 100644
--- a/src/interfaces/IValidatorConfigV2.sol
+++ b/src/interfaces/IValidatorConfigV2.sol
@@ -75,6 +75,9 @@ interface IValidatorConfigV2 {
/// @notice Thrown when the Ed25519 signature verification fails
error InvalidSignature();
+ /// @notice Thrown when the signature bytes are not in the expected format
+ error InvalidSignatureFormat();
+
/// @notice Thrown when V2 is not yet initialized (writes blocked before init)
error NotInitialized();
From a5469c784c120b762f217c58897c469919442d90 Mon Sep 17 00:00:00 2001
From: 0xrusowsky <0xrusowsky@proton.me>
Date: Tue, 21 Apr 2026 12:30:49 +0200
Subject: [PATCH 2/5] fix: delete `ITIP20RewardsRegistry`
---
src/interfaces/ITIP20Factory.sol | 5 -----
src/interfaces/ITIP20RewardsRegistry.sol | 26 ------------------------
2 files changed, 31 deletions(-)
delete mode 100644 src/interfaces/ITIP20RewardsRegistry.sol
diff --git a/src/interfaces/ITIP20Factory.sol b/src/interfaces/ITIP20Factory.sol
index b77189a..d1c24ea 100644
--- a/src/interfaces/ITIP20Factory.sol
+++ b/src/interfaces/ITIP20Factory.sol
@@ -6,13 +6,8 @@ import {ITIP20} from "./ITIP20.sol";
/// @title The interface for TIP-20 token factory
/// @notice Factory contract for creating and deploying TIP-20 compliant tokens
interface ITIP20Factory {
- /// @notice Thrown when the computed token address falls within the reserved address range
error AddressReserved();
- /// @notice Thrown when the computed token address is not in the reserved address range
- error AddressNotReserved();
- /// @notice Thrown when the provided quote token address is invalid
error InvalidQuoteToken();
- /// @notice Thrown when a token at the computed address already exists
error TokenAlreadyExists(address tokenAddress);
/// @notice Emitted when a new TIP-20 token is created
diff --git a/src/interfaces/ITIP20RewardsRegistry.sol b/src/interfaces/ITIP20RewardsRegistry.sol
deleted file mode 100644
index 874b261..0000000
--- a/src/interfaces/ITIP20RewardsRegistry.sol
+++ /dev/null
@@ -1,26 +0,0 @@
-// SPDX-License-Identifier: MIT OR Apache-2.0
-pragma solidity >=0.8.13 <0.9.0;
-
-/// @title Interface for TIP20RewardsRegistry
-/// @notice Registry contract for all TIP20 reward streams
-interface ITIP20RewardsRegistry {
- /// @notice Thrown when attempting to modify streams that have already been finalized
- error StreamsAlreadyFinalized();
- /// @notice Thrown when the caller lacks authorization for the requested action
- error Unauthorized();
-
- /// @notice Add a token to the registry for a given stream end time.
- function addStream(uint128 endTime) external;
-
- /// @notice Finalize streams for all tokens ending at the current timestamp.
- function finalizeStreams() external;
-
- function lastUpdatedTimestamp() external view returns (uint128);
-
- /// @notice Remove a stream before it ends (for cancellation).
- function removeStream(uint128 endTime) external;
-
- function streamIndex(bytes32) external view returns (uint256);
-
- function streamsEndingAt(uint128, uint256) external view returns (address);
-}
From 2e4acdc428c3f8d10fc3d5671759778efbfe4e38 Mon Sep 17 00:00:00 2001
From: 0xrusowsky <0xrusowsky@proton.me>
Date: Tue, 21 Apr 2026 12:34:25 +0200
Subject: [PATCH 3/5] fix: compilation
---
README.md | 1 -
src/StdPrecompiles.sol | 3 ---
2 files changed, 4 deletions(-)
diff --git a/README.md b/README.md
index 4123e30..f1138d5 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,6 @@ src
│ ├── IStablecoinDEX.sol: Stablecoin DEX | Docs | Implementation
│ ├── ITempoStreamChannel.sol: Streaming payment channel escrow (concept) | Implementation
│ ├── ITIP20Factory.sol: TIP-20: Factory Contract | Docs | Implementation
-│ ├── ITIP20RewardsRegistry.sol: TIP-20: Reward Distribution | Docs | Implementation
│ ├── ITIP20RolesAuth.sol: TIP-20: Roles & Permissions | Docs | Implementation
│ ├── ITIP20.sol: TIP-20: Core Token Standard | Docs | Implementation
│ ├── ITIP403Registry.sol: TIP-403: Policy Registry System | Docs | Implementation
diff --git a/src/StdPrecompiles.sol b/src/StdPrecompiles.sol
index 513b6c5..344f88f 100644
--- a/src/StdPrecompiles.sol
+++ b/src/StdPrecompiles.sol
@@ -7,7 +7,6 @@ import {IFeeManager} from "./interfaces/IFeeManager.sol";
import {ISignatureVerifier} from "./interfaces/ISignatureVerifier.sol";
import {ITIP403Registry} from "./interfaces/ITIP403Registry.sol";
import {ITIP20Factory} from "./interfaces/ITIP20Factory.sol";
-import {ITIP20RewardsRegistry} from "./interfaces/ITIP20RewardsRegistry.sol";
import {IStablecoinDEX} from "./interfaces/IStablecoinDEX.sol";
import {IValidatorConfig} from "./interfaces/IValidatorConfig.sol";
import {IValidatorConfigV2} from "./interfaces/IValidatorConfigV2.sol";
@@ -32,8 +31,6 @@ library StdPrecompiles {
IFeeManager internal constant TIP_FEE_MANAGER = IFeeManager(TIP_FEE_MANAGER_ADDRESS);
ITIP403Registry internal constant TIP403_REGISTRY = ITIP403Registry(TIP403_REGISTRY_ADDRESS);
ITIP20Factory internal constant TIP20_FACTORY = ITIP20Factory(TIP20_FACTORY_ADDRESS);
- ITIP20RewardsRegistry internal constant TIP20_REWARDS_REGISTRY =
- ITIP20RewardsRegistry(TIP20_REWARDS_REGISTRY_ADDRESS);
IStablecoinDEX internal constant STABLECOIN_DEX = IStablecoinDEX(STABLECOIN_DEX_ADDRESS);
INonce internal constant NONCE_PRECOMPILE = INonce(NONCE_ADDRESS);
IValidatorConfig internal constant VALIDATOR_CONFIG = IValidatorConfig(VALIDATOR_CONFIG_ADDRESS);
From 7f2fd5ad7c2427341163ec901665cb6ab0d2a963 Mon Sep 17 00:00:00 2001
From: 0xrusowsky <0xrusowsky@proton.me>
Date: Tue, 21 Apr 2026 12:35:08 +0200
Subject: [PATCH 4/5] style: fmt
---
src/interfaces/IValidatorConfig.sol | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/interfaces/IValidatorConfig.sol b/src/interfaces/IValidatorConfig.sol
index 0166299..9d86017 100644
--- a/src/interfaces/IValidatorConfig.sol
+++ b/src/interfaces/IValidatorConfig.sol
@@ -62,7 +62,14 @@ interface IValidatorConfig {
function validators(address validatorAddress)
external
view
- returns (bytes32 publicKey, bool active, uint64 index, address addr, string memory inboundAddress, string memory outboundAddress);
+ returns (
+ bytes32 publicKey,
+ bool active,
+ uint64 index,
+ address addr,
+ string memory inboundAddress,
+ string memory outboundAddress
+ );
/// @notice Get validator address at a given array index
/// @param index The index in the validators array
From 3372f284c7524805eb3c26f7b0dbe94b5ec06b8b Mon Sep 17 00:00:00 2001
From: 0xrusowsky <0xrusowsky@proton.me>
Date: Tue, 21 Apr 2026 12:44:54 +0200
Subject: [PATCH 5/5] fix: missing error
---
src/interfaces/ITIP20Factory.sol | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/interfaces/ITIP20Factory.sol b/src/interfaces/ITIP20Factory.sol
index d1c24ea..9e69962 100644
--- a/src/interfaces/ITIP20Factory.sol
+++ b/src/interfaces/ITIP20Factory.sol
@@ -7,6 +7,7 @@ import {ITIP20} from "./ITIP20.sol";
/// @notice Factory contract for creating and deploying TIP-20 compliant tokens
interface ITIP20Factory {
error AddressReserved();
+ error AddressNotReserved();
error InvalidQuoteToken();
error TokenAlreadyExists(address tokenAddress);