Last active
February 19, 2026 08:59
-
-
Save 0xSachinK/dc24a4f1d23d0527c546639188800f8f to your computer and use it in GitHub Desktop.
ZKP2P V1 vs V2: Escrow & Orchestrator contract diffs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- contracts/Escrow.sol 2026-02-19 13:55:27 | |
| +++ contracts/EscrowV2.sol 2026-02-19 15:51:47 | |
| @@ -1,5 +1,7 @@ | |
| //SPDX-License-Identifier: MIT | |
| +pragma solidity ^0.8.18; | |
| + | |
| import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | |
| import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
| import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | |
| @@ -7,6 +9,7 @@ | |
| import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; | |
| import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; | |
| import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; | |
| +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; | |
| import { AddressArrayUtils } from "./external/AddressArrayUtils.sol"; | |
| import { Bytes32ArrayUtils } from "./external/Bytes32ArrayUtils.sol"; | |
| @@ -14,16 +17,19 @@ | |
| import { Uint256ArrayUtils } from "./external/Uint256ArrayUtils.sol"; | |
| import { IEscrow } from "./interfaces/IEscrow.sol"; | |
| +import { IEscrowV2 } from "./interfaces/IEscrowV2.sol"; | |
| +import { IRateManager } from "./interfaces/IRateManager.sol"; | |
| import { IOrchestrator } from "./interfaces/IOrchestrator.sol"; | |
| +import { IOrchestratorRegistry } from "./interfaces/IOrchestratorRegistry.sol"; | |
| +import { IOracleAdapter } from "./interfaces/IOracleAdapter.sol"; | |
| import { IPaymentVerifier } from "./interfaces/IPaymentVerifier.sol"; | |
| import { IPaymentVerifierRegistry } from "./interfaces/IPaymentVerifierRegistry.sol"; | |
| -pragma solidity ^0.8.18; | |
| /** | |
| - * @title Escrow | |
| + * @title EscrowV2 | |
| * @notice Escrows deposits and manages deposit lifecycle. | |
| */ | |
| -contract Escrow is Ownable, Pausable, ReentrancyGuard, IEscrow { | |
| +contract EscrowV2 is Ownable, Pausable, ReentrancyGuard, IEscrowV2 { | |
| using AddressArrayUtils for address[]; | |
| using Bytes32ArrayUtils for bytes32[]; | |
| @@ -35,13 +41,14 @@ | |
| /* ============ Constants ============ */ | |
| uint256 internal constant PRECISE_UNIT = 1e18; | |
| + uint256 internal constant BPS = 10_000; | |
| uint256 internal constant MAX_DUST_THRESHOLD = 1e6; // 1 USDC | |
| uint256 internal constant MAX_TOTAL_INTENT_EXPIRATION_PERIOD = 86400 * 5; // 5 days | |
| uint256 internal constant PRUNE_ALL_EXPIRED_INTENTS = type(uint256).max; | |
| /* ============ State Variables ============ */ | |
| - IOrchestrator public orchestrator; // Address of the orchestrator contract | |
| + IOrchestratorRegistry public orchestratorRegistry; // Registry of authorized orchestrator contracts | |
| IPaymentVerifierRegistry public paymentVerifierRegistry; // Address of the payment verifier registry contract | |
| uint256 immutable public chainId; // chainId of the chain the escrow is deployed on | |
| @@ -63,6 +70,7 @@ | |
| // Example: Deposit 1 => Venmo => USD: 1e18 | |
| // => Revolut => USD: 1e18, EUR: 1.2e18, SGD: 1.5e18 | |
| mapping(uint256 => mapping(bytes32 => mapping(bytes32 => uint256))) internal depositCurrencyMinRate; | |
| + mapping(uint256 => mapping(bytes32 => mapping(bytes32 => OracleRateConfig))) internal depositOracleRateConfig; | |
| mapping(uint256 => mapping(bytes32 => bytes32[])) internal depositCurrencies; // Handy mapping to get all currencies for a deposit and verifier | |
| // Do not need to track if a currency is active; if it's min rate is 0 then it's not active | |
| // Track if a currency code has ever been listed for this deposit+paymentMethod (avoid contains scans and duplicates in depositCurrencies) | |
| @@ -71,6 +79,8 @@ | |
| mapping(uint256 => Deposit) internal deposits; // Mapping of depositIds to deposit structs | |
| mapping(uint256 => bytes32[]) internal depositIntentHashes; // Mapping of depositId to array of intentHashes | |
| mapping(uint256 => mapping(bytes32 => Intent)) internal depositIntents; // Mapping of depositId to intentHash to intent | |
| + mapping(bytes32 => address) internal intentOrchestrator; // Intent hash to owning orchestrator | |
| + mapping(uint256 => RateManagerConfig) internal depositRateManagerConfig; // Per-deposit delegated rate manager config | |
| uint256 public depositCounter; // Counter for depositIds | |
| @@ -98,7 +108,9 @@ | |
| * @notice Modifier to restrict access to orchestrator-only functions | |
| */ | |
| modifier onlyOrchestrator() { | |
| - if (msg.sender != address(orchestrator)) revert UnauthorizedCaller(msg.sender, address(orchestrator)); | |
| + if (!orchestratorRegistry.isOrchestrator(msg.sender)) { | |
| + revert UnauthorizedCaller(msg.sender, address(orchestratorRegistry)); | |
| + } | |
| _; | |
| } | |
| @@ -106,6 +118,7 @@ | |
| constructor( | |
| address _owner, | |
| uint256 _chainId, | |
| + address _orchestratorRegistry, | |
| address _paymentVerifierRegistry, | |
| address _dustRecipient, | |
| uint256 _dustThreshold, | |
| @@ -115,6 +128,7 @@ | |
| Ownable() | |
| { | |
| chainId = _chainId; | |
| + orchestratorRegistry = IOrchestratorRegistry(_orchestratorRegistry); | |
| paymentVerifierRegistry = IPaymentVerifierRegistry(_paymentVerifierRegistry); | |
| dustRecipient = _dustRecipient; | |
| dustThreshold = _dustThreshold; | |
| @@ -308,15 +322,12 @@ | |
| /* ============ Deposit Owner OR Delegate Only (External Functions) ============ */ | |
| /** | |
| - * @notice Only callable by the depositor/delegate for a deposit. Allows depositor/delegate to update the min conversion rate for a | |
| - * currency for a payment verifier provided the currency was previously listed (otherwise use addCurrenciesToDepositPaymentMethod). | |
| - * Since intent's store the conversion rate at the time of intent, changing the min conversion rate will not affect any intents that | |
| - * have already been signaled. | |
| - * | |
| - * @param _depositId The deposit ID | |
| - * @param _paymentMethod The payment method to update the min conversion rate for | |
| - * @param _fiatCurrency The fiat currency code to update the min conversion rate for | |
| - * @param _newMinConversionRate The new min conversion rate. Must be greater than 0. | |
| + * @notice Sets the fixed floor for a listed (paymentMethod, currency) tuple. | |
| + * @dev `_newMinConversionRate` may be zero to disable fixed-rate floor while keeping oracle floor active. | |
| + * @param _depositId The deposit ID. | |
| + * @param _paymentMethod The payment method key. | |
| + * @param _fiatCurrency The fiat currency key. | |
| + * @param _newMinConversionRate New fixed floor in precise units (0 allowed). | |
| */ | |
| function setCurrencyMinRate( | |
| uint256 _depositId, | |
| @@ -332,14 +343,148 @@ | |
| if (!depositCurrencyListed[_depositId][_paymentMethod][_fiatCurrency]) { | |
| revert CurrencyNotSupported(_paymentMethod, _fiatCurrency); | |
| } | |
| - if (_newMinConversionRate == 0) revert ZeroConversionRate(); | |
| depositCurrencyMinRate[_depositId][_paymentMethod][_fiatCurrency] = _newMinConversionRate; | |
| emit DepositMinConversionRateUpdated(_depositId, _paymentMethod, _fiatCurrency, _newMinConversionRate); | |
| + } | |
| + | |
| + /** | |
| + * @notice Sets oracle spread configuration for a listed (paymentMethod, currency) tuple. | |
| + * @dev Caller must be the deposit depositor or delegate. | |
| + * @param _depositId The deposit ID. | |
| + * @param _paymentMethod The payment method key. | |
| + * @param _currencyCode The fiat currency key. | |
| + * @param _config Oracle spread configuration. | |
| + */ | |
| + function setOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode, | |
| + OracleRateConfig calldata _config | |
| + ) | |
| + external | |
| + whenNotPaused | |
| + onlyDepositorOrDelegate(_depositId) | |
| + { | |
| + _setOracleRateConfig(_depositId, _paymentMethod, _currencyCode, _config); | |
| + } | |
| + | |
| + /** | |
| + * @notice Batch sets oracle spread configuration for multiple tuples on one deposit. | |
| + * @dev For each payment-method index, `_currencyCodes[i].length` must match `_configs[i].length`. | |
| + * @param _depositId Deposit ID. | |
| + * @param _paymentMethods Payment method keys. | |
| + * @param _currencyCodes Currency keys grouped by payment method index. | |
| + * @param _configs Oracle configs grouped by payment method index. | |
| + */ | |
| + function setOracleRateConfigBatch( | |
| + uint256 _depositId, | |
| + bytes32[] calldata _paymentMethods, | |
| + bytes32[][] calldata _currencyCodes, | |
| + OracleRateConfig[][] calldata _configs | |
| + ) | |
| + external | |
| + whenNotPaused | |
| + onlyDepositorOrDelegate(_depositId) | |
| + { | |
| + if (_paymentMethods.length != _currencyCodes.length) { | |
| + revert ArrayLengthMismatch(_paymentMethods.length, _currencyCodes.length); | |
| + } | |
| + if (_paymentMethods.length != _configs.length) { | |
| + revert ArrayLengthMismatch(_paymentMethods.length, _configs.length); | |
| + } | |
| + | |
| + for (uint256 i = 0; i < _paymentMethods.length; i++) { | |
| + if (_currencyCodes[i].length != _configs[i].length) { | |
| + revert ArrayLengthMismatch(_currencyCodes[i].length, _configs[i].length); | |
| + } | |
| + for (uint256 j = 0; j < _currencyCodes[i].length; j++) { | |
| + _setOracleRateConfig(_depositId, _paymentMethods[i], _currencyCodes[i][j], _configs[i][j]); | |
| + } | |
| + } | |
| + } | |
| + | |
| + /** | |
| + * @notice Removes oracle spread configuration for a listed tuple. | |
| + * @dev Caller must be depositor or delegate. | |
| + * @param _depositId Deposit ID. | |
| + * @param _paymentMethod Payment method key. | |
| + * @param _currencyCode Currency key. | |
| + */ | |
| + function removeOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) | |
| + external | |
| + whenNotPaused | |
| + onlyDepositorOrDelegate(_depositId) | |
| + { | |
| + if (!depositCurrencyListed[_depositId][_paymentMethod][_currencyCode]) { | |
| + revert CurrencyNotSupported(_paymentMethod, _currencyCode); | |
| + } | |
| + | |
| + delete depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode]; | |
| + emit DepositOracleRateConfigRemoved(_depositId, _paymentMethod, _currencyCode); | |
| + } | |
| + | |
| + /** | |
| + * @notice Delegates rate management for a deposit to an external `IRateManager`. | |
| + * @dev Only the depositor (not delegate) can call this function. | |
| + * @param _depositId Deposit ID. | |
| + * @param _rateManager External rate manager contract address. | |
| + * @param _rateManagerId Manager ID within the external contract. | |
| + */ | |
| + function setRateManager( | |
| + uint256 _depositId, | |
| + address _rateManager, | |
| + bytes32 _rateManagerId | |
| + ) | |
| + external | |
| + whenNotPaused | |
| + { | |
| + Deposit storage deposit = deposits[_depositId]; | |
| + if (deposit.depositor == address(0)) revert DepositNotFound(_depositId); | |
| + if (deposit.depositor != msg.sender) revert UnauthorizedCaller(msg.sender, deposit.depositor); | |
| + if (_rateManager == address(0)) revert ZeroAddress(); | |
| + if (_rateManager.code.length == 0) revert InvalidRateManager(_rateManager); | |
| + if (_rateManagerId == bytes32(0)) revert ZeroValue(); | |
| + | |
| + RateManagerConfig memory existing = depositRateManagerConfig[_depositId]; | |
| + if (existing.rateManager != address(0)) revert RateManagerAlreadySet(existing.rateManagerId); | |
| + | |
| + IRateManager rateManager = IRateManager(_rateManager); | |
| + if (!rateManager.isRateManager(_rateManagerId)) revert RateManagerNotFound(_rateManagerId); | |
| + | |
| + rateManager.onDepositOptIn(msg.sender, address(this), _depositId, _rateManagerId); | |
| + | |
| + depositRateManagerConfig[_depositId] = RateManagerConfig({ | |
| + rateManager: _rateManager, | |
| + rateManagerId: _rateManagerId | |
| + }); | |
| + | |
| + emit DepositRateManagerSet(_depositId, _rateManager, _rateManagerId); | |
| } | |
| /** | |
| + * @notice Clears delegated rate manager config for a deposit. | |
| + * @dev Only the depositor (not delegate) can call this function. | |
| + * @param _depositId Deposit ID. | |
| + */ | |
| + function clearRateManager(uint256 _depositId) external whenNotPaused { | |
| + Deposit storage deposit = deposits[_depositId]; | |
| + if (deposit.depositor == address(0)) revert DepositNotFound(_depositId); | |
| + if (deposit.depositor != msg.sender) revert UnauthorizedCaller(msg.sender, deposit.depositor); | |
| + | |
| + RateManagerConfig memory existing = depositRateManagerConfig[_depositId]; | |
| + if (existing.rateManager == address(0)) revert RateManagerNotSet(_depositId); | |
| + | |
| + delete depositRateManagerConfig[_depositId]; | |
| + emit DepositRateManagerCleared(_depositId, existing.rateManager, existing.rateManagerId); | |
| + } | |
| + | |
| + /** | |
| * @notice Allows depositor to update the intent amount range for a deposit. Since intent's are already created within the | |
| * previous intent amount range, changing the intent amount range will not affect any intents that have already been signaled. | |
| * | |
| @@ -463,9 +608,14 @@ | |
| { | |
| if (!depositPaymentMethodActive[_depositId][_paymentMethod]) revert PaymentMethodNotActive(_depositId, _paymentMethod); | |
| if (!depositCurrencyListed[_depositId][_paymentMethod][_currencyCode]) revert CurrencyNotFound(_paymentMethod, _currencyCode); | |
| - | |
| - depositCurrencyMinRate[_depositId][_paymentMethod][_currencyCode] = 0; | |
| + delete depositCurrencyMinRate[_depositId][_paymentMethod][_currencyCode]; | |
| + bool hadOracleConfig = depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode].adapter != address(0); | |
| + if (hadOracleConfig) { | |
| + delete depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode]; | |
| + emit DepositOracleRateConfigRemoved(_depositId, _paymentMethod, _currencyCode); | |
| + } | |
| + | |
| emit DepositMinConversionRateUpdated(_depositId, _paymentMethod, _currencyCode, 0); | |
| } | |
| @@ -598,6 +748,7 @@ | |
| timestamp: block.timestamp, | |
| expiryTime: expiryTime | |
| }); | |
| + intentOrchestrator[_intentHash] = msg.sender; | |
| emit FundsLocked(_depositId, _intentHash, _amount, expiryTime); | |
| @@ -608,9 +759,10 @@ | |
| } | |
| /** | |
| - * @notice ORCHESTRATOR ONLY: Unlocks funds from a cancelled intent by removing the specific intent. | |
| + * @notice ORCHESTRATOR ONLY: Unlocks funds from a cancelled intent by removing the specific intent. | |
| + * @dev Caller must be the same orchestrator that originally locked the intent. | |
| * Releases the lock on deposit liquidity and adds it back to the deposit. | |
| - * | |
| + * | |
| * @param _depositId The deposit ID to unlock funds from | |
| * @param _intentHash The intent hash to find and remove the intent for | |
| */ | |
| @@ -625,21 +777,23 @@ | |
| if (deposit.depositor == address(0)) revert DepositNotFound(_depositId); | |
| if (intent.intentHash == bytes32(0)) revert IntentNotFound(_intentHash); | |
| + address intentOwnerOrchestrator = intentOrchestrator[_intentHash]; | |
| + if (intentOwnerOrchestrator != msg.sender) revert UnauthorizedCaller(msg.sender, intentOwnerOrchestrator); | |
| // Effects | |
| deposit.remainingDeposits += intent.amount; | |
| deposit.outstandingIntentAmount -= intent.amount; | |
| - _pruneIntent(_depositId, _intentHash); | |
| + _pruneIntent(_depositId, _intentHash, true); | |
| emit FundsUnlocked(_depositId, _intentHash, intent.amount); | |
| } | |
| /** | |
| * @notice ORCHESTRATOR ONLY: Unlocks and transfers funds from a fulfilled intent by removing the specific intent. | |
| - * Only callable by orchestrator. Releases the lock on deposlit liquidity and transfers out partial/full locked | |
| - * amount to the given to address. | |
| - * | |
| + * @dev Caller must be the same orchestrator that originally locked the intent. | |
| + * Releases the lock on deposit liquidity and transfers out partial/full locked amount to the given to address. | |
| + * | |
| * @param _depositId The deposit ID to transfer from | |
| * @param _intentHash The intent hash to find and remove the intent for | |
| * @param _transferAmount The amount to actually transfer (may be less than intent amount) | |
| @@ -661,6 +815,8 @@ | |
| if (deposit.depositor == address(0)) revert DepositNotFound(_depositId); | |
| if (intent.intentHash == bytes32(0)) revert IntentNotFound(_intentHash); | |
| + address intentOwnerOrchestrator = intentOrchestrator[_intentHash]; | |
| + if (intentOwnerOrchestrator != msg.sender) revert UnauthorizedCaller(msg.sender, intentOwnerOrchestrator); | |
| if (_transferAmount == 0) revert ZeroValue(); | |
| if (_transferAmount > intent.amount) revert AmountExceedsAvailable(_transferAmount, intent.amount); | |
| @@ -672,7 +828,7 @@ | |
| deposit.remainingDeposits += (intent.amount - _transferAmount); | |
| } | |
| - _pruneIntent(_depositId, _intentHash); | |
| + _pruneIntent(_depositId, _intentHash, true); | |
| IERC20 token = deposit.token; | |
| _closeDepositIfNecessary(_depositId, deposit); | |
| @@ -724,15 +880,15 @@ | |
| /* ============ Governance Functions ============ */ | |
| /** | |
| - * @notice GOVERNANCE ONLY: Sets the orchestrator contract address. Only callable by owner. | |
| - * | |
| - * @param _orchestrator The orchestrator contract address | |
| + * @notice GOVERNANCE ONLY: Sets the orchestrator registry used for escrow authorization. | |
| + * @dev Only callable by owner. | |
| + * @param _orchestratorRegistry New orchestrator registry address. | |
| */ | |
| - function setOrchestrator(address _orchestrator) external onlyOwner { | |
| - if (_orchestrator == address(0)) revert ZeroAddress(); | |
| - | |
| - orchestrator = IOrchestrator(_orchestrator); | |
| - emit OrchestratorUpdated(_orchestrator); | |
| + function setOrchestratorRegistry(address _orchestratorRegistry) external onlyOwner { | |
| + if (_orchestratorRegistry == address(0)) revert ZeroAddress(); | |
| + | |
| + orchestratorRegistry = IOrchestratorRegistry(_orchestratorRegistry); | |
| + emit OrchestratorRegistryUpdated(_orchestratorRegistry); | |
| } | |
| /** | |
| @@ -845,9 +1001,60 @@ | |
| } | |
| function getDepositCurrencyMinRate(uint256 _depositId, bytes32 _paymentMethod, bytes32 _currencyCode) external view returns (uint256) { | |
| - return depositCurrencyMinRate[_depositId][_paymentMethod][_currencyCode]; | |
| + return _getDepositCurrencyMinRate(_depositId, _paymentMethod, _currencyCode); | |
| } | |
| + function getEffectiveRate( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) | |
| + external | |
| + view | |
| + returns (uint256) | |
| + { | |
| + RateManagerConfig memory config = depositRateManagerConfig[_depositId]; | |
| + if (config.rateManager != address(0)) { | |
| + return IRateManager(config.rateManager).getRate( | |
| + config.rateManagerId, | |
| + address(this), | |
| + _depositId, | |
| + _paymentMethod, | |
| + _currencyCode | |
| + ); | |
| + } | |
| + return _getDepositCurrencyMinRate(_depositId, _paymentMethod, _currencyCode); | |
| + } | |
| + | |
| + function getManagerFee(uint256 _depositId) external view returns (address recipient, uint256 fee) { | |
| + RateManagerConfig memory config = depositRateManagerConfig[_depositId]; | |
| + if (config.rateManager == address(0)) { | |
| + return (address(0), 0); | |
| + } | |
| + return IRateManager(config.rateManager).getFee(config.rateManagerId); | |
| + } | |
| + | |
| + function getDepositRateManager(uint256 _depositId) | |
| + external | |
| + view | |
| + returns (address rateManager, bytes32 rateManagerId) | |
| + { | |
| + RateManagerConfig memory config = depositRateManagerConfig[_depositId]; | |
| + return (config.rateManager, config.rateManagerId); | |
| + } | |
| + | |
| + function getDepositOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) | |
| + external | |
| + view | |
| + returns (OracleRateConfig memory) | |
| + { | |
| + return depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode]; | |
| + } | |
| + | |
| function getDepositCurrencyListed(uint256 _depositId, bytes32 _paymentMethod, bytes32 _currencyCode) external view returns (bool) { | |
| return depositCurrencyListed[_depositId][_paymentMethod][_currencyCode]; | |
| } | |
| @@ -916,9 +1123,7 @@ | |
| /** | |
| * @notice Free up deposit liquidity by reclaiming liquidity from expired intents. Only reclaims if remaining deposits amount | |
| - * is less than the minimum required amount. Returns the expired intents that need to be pruned. Only does local state updates, | |
| - * does not call any external contracts. Whenever this function is called, the calling function should also call _tryOrchestratorPruneIntents | |
| - * with the returned intents to expire the intents on the orchestrator contract. | |
| + * is less than the minimum required amount. Returns the expired intents that need to be pruned. | |
| */ | |
| function _reclaimLiquidityIfNecessary( | |
| Deposit storage _deposit, | |
| @@ -942,7 +1147,7 @@ | |
| // Prune intents locally and emit funds unlocked events | |
| for (uint256 i = 0; i < expiredIntents.length; i++) { | |
| Intent memory intent = depositIntents[_depositId][expiredIntents[i]]; | |
| - _pruneIntent(_depositId, intent.intentHash); | |
| + _pruneIntent(_depositId, intent.intentHash, false); | |
| emit FundsUnlocked(_depositId, intent.intentHash, intent.amount); | |
| } | |
| @@ -952,9 +1157,12 @@ | |
| /** | |
| * @notice Prunes an intent from a deposit locally. Does not call orchestrator. | |
| */ | |
| - function _pruneIntent(uint256 _depositId, bytes32 _intentHash) internal { | |
| + function _pruneIntent(uint256 _depositId, bytes32 _intentHash, bool _clearOrchestrator) internal { | |
| delete depositIntents[_depositId][_intentHash]; | |
| depositIntentHashes[_depositId].removeStorage(_intentHash); | |
| + if (_clearOrchestrator) { | |
| + delete intentOrchestrator[_intentHash]; | |
| + } | |
| } | |
| /** | |
| @@ -962,7 +1170,19 @@ | |
| * Note: If the orchestrator reverts, it is caught and ignored to allow the function to continue execution. | |
| */ | |
| function _tryOrchestratorPruneIntents(bytes32[] memory _intents) internal { | |
| - try IOrchestrator(orchestrator).pruneIntents(_intents) {} catch {} | |
| + for (uint256 i = 0; i < _intents.length; i++) { | |
| + bytes32 intentHash = _intents[i]; | |
| + address orchestratorAddress = intentOrchestrator[intentHash]; | |
| + if (orchestratorAddress == address(0)) { | |
| + continue; | |
| + } | |
| + | |
| + bytes32[] memory singleIntent = new bytes32[](1); | |
| + singleIntent[0] = intentHash; | |
| + | |
| + try IOrchestrator(orchestratorAddress).pruneIntents(singleIntent) {} catch {} | |
| + delete intentOrchestrator[intentHash]; | |
| + } | |
| } | |
| /** | |
| @@ -1005,6 +1225,7 @@ | |
| function _closeDeposit(uint256 _depositId, Deposit storage _deposit) internal { | |
| address depositor = _deposit.depositor; | |
| accountDeposits[depositor].removeStorage(_depositId); | |
| + delete depositRateManagerConfig[_depositId]; | |
| _deleteDepositPaymentMethodAndCurrencyData(_depositId); | |
| @@ -1028,6 +1249,7 @@ | |
| for (uint256 j = 0; j < currencies.length; j++) { | |
| bytes32 currencyCode = currencies[j]; | |
| delete depositCurrencyMinRate[_depositId][paymentMethod][currencyCode]; | |
| + delete depositOracleRateConfig[_depositId][paymentMethod][currencyCode]; | |
| delete depositCurrencyListed[_depositId][paymentMethod][currencyCode]; | |
| } | |
| delete depositCurrencies[_depositId][paymentMethod]; | |
| @@ -1095,7 +1317,6 @@ | |
| if (!paymentVerifierRegistry.isCurrency(_paymentMethod, _currencyCode)) { | |
| revert CurrencyNotSupported(_paymentMethod, _currencyCode); | |
| } | |
| - if (_minConversionRate == 0) revert ZeroConversionRate(); | |
| if (depositCurrencyListed[_depositId][_paymentMethod][_currencyCode]) { | |
| revert CurrencyAlreadyExists(_paymentMethod, _currencyCode); | |
| } | |
| @@ -1107,4 +1328,85 @@ | |
| emit DepositCurrencyAdded(_depositId, _paymentMethod, _currencyCode, _minConversionRate); | |
| } | |
| + | |
| + function _setOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode, | |
| + OracleRateConfig calldata _config | |
| + ) internal { | |
| + if (!depositCurrencyListed[_depositId][_paymentMethod][_currencyCode]) { | |
| + revert CurrencyNotSupported(_paymentMethod, _currencyCode); | |
| + } | |
| + if (_config.adapter == address(0)) revert ZeroAddress(); | |
| + if (_config.adapter.code.length == 0) revert InvalidOracleAdapter(_config.adapter); | |
| + if (_config.spreadBps > BPS) revert InvalidSpread(_config.spreadBps); | |
| + if (_config.maxStaleness == 0) revert ZeroValue(); | |
| + | |
| + bytes memory normalizedConfig = IOracleAdapter(_config.adapter).validateConfig(_config.adapterConfig); | |
| + | |
| + depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode] = OracleRateConfig({ | |
| + adapter: _config.adapter, | |
| + adapterConfig: normalizedConfig, | |
| + spreadBps: _config.spreadBps, | |
| + maxStaleness: _config.maxStaleness | |
| + }); | |
| + | |
| + emit DepositOracleRateConfigSet( | |
| + _depositId, | |
| + _paymentMethod, | |
| + _currencyCode, | |
| + _config.adapter, | |
| + normalizedConfig, | |
| + _config.spreadBps, | |
| + _config.maxStaleness | |
| + ); | |
| + } | |
| + | |
| + function _getDepositCurrencyMinRate( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) | |
| + internal | |
| + view | |
| + returns (uint256) | |
| + { | |
| + uint256 fixedRate = depositCurrencyMinRate[_depositId][_paymentMethod][_currencyCode]; | |
| + OracleRateConfig memory oracleConfig = depositOracleRateConfig[_depositId][_paymentMethod][_currencyCode]; | |
| + uint256 spreadRate = _computeSpreadRate(oracleConfig); | |
| + | |
| + return fixedRate > spreadRate ? fixedRate : spreadRate; | |
| + } | |
| + | |
| + function _computeSpreadRate(OracleRateConfig memory _config) internal view returns (uint256) { | |
| + if (_config.adapter == address(0)) { | |
| + return 0; | |
| + } | |
| + | |
| + try IOracleAdapter(_config.adapter).getRate(_config.adapterConfig) returns ( | |
| + bool isValidQuote, | |
| + uint256 marketRate, | |
| + uint256 rateUpdatedAt | |
| + ) { | |
| + if (!isValidQuote || marketRate == 0) { | |
| + return 0; | |
| + } | |
| + if (rateUpdatedAt == 0 || rateUpdatedAt > block.timestamp) { | |
| + return 0; | |
| + } | |
| + if (block.timestamp - rateUpdatedAt > _config.maxStaleness) { | |
| + return 0; | |
| + } | |
| + | |
| + return Math.mulDiv( | |
| + marketRate, | |
| + BPS + uint256(_config.spreadBps), | |
| + BPS, | |
| + Math.Rounding.Up | |
| + ); | |
| + } catch { | |
| + return 0; | |
| + } | |
| + } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- contracts/interfaces/IEscrow.sol 2026-02-18 17:54:06 | |
| +++ contracts/interfaces/IEscrowV2.sol 2026-02-19 14:01:50 | |
| @@ -2,171 +2,118 @@ | |
| pragma solidity ^0.8.18; | |
| -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
| -import { IPostIntentHook } from "./IPostIntentHook.sol"; | |
| +import { IEscrow } from "./IEscrow.sol"; | |
| -interface IEscrow { | |
| - | |
| +/** | |
| + * @title IEscrowV2 | |
| + * @notice Extended escrow interface with native oracle-spread rates and delegated rate managers. | |
| + */ | |
| +interface IEscrowV2 is IEscrow { | |
| /* ============ Structs ============ */ | |
| - struct Intent { | |
| - bytes32 intentHash; // Unique identifier for the intent | |
| - uint256 amount; // Amount locked | |
| - uint256 timestamp; // When this intent was created | |
| - uint256 expiryTime; // When this intent expires | |
| + struct OracleRateConfig { | |
| + address adapter; | |
| + bytes adapterConfig; | |
| + uint16 spreadBps; | |
| + uint32 maxStaleness; | |
| } | |
| - struct Range { | |
| - uint256 min; // Minimum value | |
| - uint256 max; // Maximum value | |
| + struct RateManagerConfig { | |
| + address rateManager; | |
| + bytes32 rateManagerId; | |
| } | |
| - struct Deposit { | |
| - address depositor; // Address of depositor | |
| - address delegate; // Address that can manage this deposit (address(0) if no delegate) | |
| - IERC20 token; // Address of deposit token | |
| - Range intentAmountRange; // Range of take amount per intent | |
| - // Deposit state | |
| - bool acceptingIntents; // State: True if the deposit is accepting intents, False otherwise | |
| - uint256 remainingDeposits; // State: Amount of liquidity immediately available to lock | |
| - uint256 outstandingIntentAmount; // State: Amount of outstanding intents (may include expired intents) | |
| - // Intent guardian | |
| - address intentGuardian; // Address that can extend intent expiry times (address(0) if no guardian) | |
| - // Retention behavior | |
| - bool retainOnEmpty; // If true, do not auto-close/sweep when empty; keep config for reuse | |
| - } | |
| - | |
| - struct Currency { | |
| - bytes32 code; // Currency code (keccak256 hash of the currency code) | |
| - uint256 minConversionRate; // Minimum rate of deposit token to fiat currency (in preciseUnits) | |
| - } | |
| - | |
| - struct DepositPaymentMethodData { | |
| - address intentGatingService; // Public key of gating service that will be used to verify intents | |
| - bytes32 payeeDetails; // Payee details, has to be hash of payee details | |
| - bytes data; // Verification Data: Additional data used for payment verification; Can hold attester address | |
| - // in case of TLS proofs, domain key hash in case of zkEmail proofs, currency code etc. | |
| - } | |
| - | |
| - struct CreateDepositParams { | |
| - IERC20 token; // The token to be deposited | |
| - uint256 amount; // The amount of token to deposit | |
| - Range intentAmountRange; // The max and min take amount for each intent | |
| - bytes32[] paymentMethods; // The payment methods that deposit supports | |
| - DepositPaymentMethodData[] paymentMethodData;// The payment verification data for each payment method that deposit supports | |
| - Currency[][] currencies; // The currencies for each payment method that deposit supports | |
| - address delegate; // Optional delegate address that can manage this deposit (address(0) for no delegate) | |
| - address intentGuardian; // Optional intent guardian address that can extend intent expiry times (address(0) for no guardian) | |
| - bool retainOnEmpty; // Opt-in: keep deposit and config when empty | |
| - } | |
| - | |
| /* ============ Events ============ */ | |
| - event DepositReceived(uint256 indexed depositId, address indexed depositor, IERC20 indexed token, uint256 amount, Range intentAmountRange, address delegate, address intentGuardian); | |
| + event DepositOracleRateConfigSet( | |
| + uint256 indexed depositId, | |
| + bytes32 indexed paymentMethod, | |
| + bytes32 indexed currencyCode, | |
| + address adapter, | |
| + bytes adapterConfig, | |
| + uint16 spreadBps, | |
| + uint32 maxStaleness | |
| + ); | |
| - event DepositPaymentMethodAdded(uint256 indexed depositId, bytes32 indexed paymentMethod, bytes32 indexed payeeDetails, address intentGatingService); | |
| - event DepositPaymentMethodActiveUpdated(uint256 indexed depositId, bytes32 indexed paymentMethod, bool active); | |
| + event DepositOracleRateConfigRemoved( | |
| + uint256 indexed depositId, | |
| + bytes32 indexed paymentMethod, | |
| + bytes32 indexed currencyCode | |
| + ); | |
| - event DepositCurrencyAdded(uint256 indexed depositId, bytes32 indexed paymentMethod, bytes32 indexed currency, uint256 minConversionRate); | |
| - event DepositMinConversionRateUpdated(uint256 indexed depositId, bytes32 indexed paymentMethod, bytes32 indexed currency, uint256 newMinConversionRate); | |
| - | |
| - event DepositFundsAdded(uint256 indexed depositId, address indexed depositor, uint256 amount); | |
| - event DepositWithdrawn(uint256 indexed depositId, address indexed depositor, uint256 amount); | |
| - event DepositClosed(uint256 depositId, address depositor); | |
| - event DepositAcceptingIntentsUpdated(uint256 indexed depositId, bool acceptingIntents); | |
| + event DepositRateManagerSet( | |
| + uint256 indexed depositId, | |
| + address indexed rateManager, | |
| + bytes32 indexed rateManagerId | |
| + ); | |
| - event DepositIntentAmountRangeUpdated(uint256 indexed depositId, Range intentAmountRange); | |
| - event DepositRetainOnEmptyUpdated(uint256 indexed depositId, bool retainOnEmpty); | |
| + event DepositRateManagerCleared( | |
| + uint256 indexed depositId, | |
| + address indexed rateManager, | |
| + bytes32 indexed rateManagerId | |
| + ); | |
| - event DepositDelegateSet(uint256 indexed depositId, address indexed depositor, address indexed delegate); | |
| - event DepositDelegateRemoved(uint256 indexed depositId, address indexed depositor); | |
| + event OrchestratorRegistryUpdated(address indexed orchestratorRegistry); | |
| - event MinDepositAmountSet(uint256 minDepositAmount); | |
| + /* ============ Custom Errors ============ */ | |
| - event OrchestratorUpdated(address indexed orchestrator); | |
| - event PaymentVerifierRegistryUpdated(address indexed paymentVerifierRegistry); | |
| + error InvalidOracleAdapter(address adapter); | |
| + error InvalidRateManager(address rateManager); | |
| + error InvalidSpread(uint256 spreadBps); | |
| + error RateManagerAlreadySet(bytes32 rateManagerId); | |
| + error RateManagerNotFound(bytes32 rateManagerId); | |
| + error RateManagerNotSet(uint256 depositId); | |
| - event FundsLocked(uint256 indexed depositId, bytes32 indexed intentHash, uint256 amount, uint256 expiryTime); | |
| - event FundsUnlocked(uint256 indexed depositId, bytes32 indexed intentHash, uint256 amount); | |
| - event FundsUnlockedAndTransferred( | |
| - uint256 indexed depositId, | |
| - bytes32 indexed intentHash, | |
| - uint256 unlockedAmount, | |
| - uint256 transferredAmount, | |
| - address to | |
| - ); | |
| - event IntentExpiryExtended(uint256 indexed depositId, bytes32 indexed intentHash, uint256 newExpiryTime); | |
| + /* ============ External Functions ============ */ | |
| - event DustRecipientUpdated(address indexed dustRecipient); | |
| - event DustCollected(uint256 indexed depositId, uint256 dustAmount, address indexed dustRecipient); | |
| - event DustThresholdUpdated(uint256 dustThreshold); | |
| - event MaxIntentsPerDepositUpdated(uint256 maxIntentsPerDeposit); | |
| - event IntentExpirationPeriodUpdated(uint256 intentExpirationPeriod); | |
| + function setOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode, | |
| + OracleRateConfig calldata _config | |
| + ) external; | |
| - /* ============ Standardized Custom Errors ============ */ | |
| - | |
| - // Zero value errors | |
| - error ZeroAddress(); | |
| - error ZeroValue(); | |
| - error ZeroMinValue(); | |
| - error ZeroConversionRate(); | |
| + function setOracleRateConfigBatch( | |
| + uint256 _depositId, | |
| + bytes32[] calldata _paymentMethods, | |
| + bytes32[][] calldata _currencyCodes, | |
| + OracleRateConfig[][] calldata _configs | |
| + ) external; | |
| - // Authorization errors | |
| - error UnauthorizedCaller(address caller, address authorized); | |
| - error UnauthorizedCallerOrDelegate(address caller, address owner, address delegate); | |
| + function removeOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) external; | |
| - // Range and amount errors | |
| - error InvalidRange(uint256 min, uint256 max); | |
| - error AmountBelowMin(uint256 amount, uint256 min); | |
| - error AmountAboveMax(uint256 amount, uint256 max); | |
| - error AmountExceedsAvailable(uint256 requested, uint256 available); | |
| + function setRateManager( | |
| + uint256 _depositId, | |
| + address _rateManager, | |
| + bytes32 _rateManagerId | |
| + ) external; | |
| - // Not found errors | |
| - error DepositNotFound(uint256 depositId); | |
| - error IntentNotFound(bytes32 intentHash); | |
| - error PaymentMethodNotActive(uint256 depositId, bytes32 paymentMethod); | |
| - error PaymentMethodNotListed(uint256 depositId, bytes32 paymentMethod); | |
| - error CurrencyNotFound(bytes32 paymentMethod, bytes32 currency); | |
| - error DelegateNotFound(uint256 depositId); | |
| + function clearRateManager(uint256 _depositId) external; | |
| - // Already exists errors | |
| - error PaymentMethodAlreadyExists(uint256 depositId, bytes32 paymentMethod); | |
| - error CurrencyAlreadyExists(bytes32 paymentMethod, bytes32 currency); | |
| - error IntentAlreadyExists(uint256 depositId, bytes32 intentHash); | |
| + function setOrchestratorRegistry(address _orchestratorRegistry) external; | |
| - // State errors | |
| - error DepositNotAcceptingIntents(uint256 depositId); | |
| - error DepositAlreadyInState(uint256 depositId, bool currentState); | |
| - error InsufficientDepositLiquidity(uint256 depositId, uint256 available, uint256 required); | |
| - error MaxIntentsExceeded(uint256 depositId, uint256 current, uint256 max); | |
| + /* ============ View Functions ============ */ | |
| - // Validation errors | |
| - error EmptyPayeeDetails(); | |
| - error ArrayLengthMismatch(uint256 length1, uint256 length2); | |
| + function getDepositOracleRateConfig( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) external view returns (OracleRateConfig memory); | |
| - // Payment method errors | |
| - error PaymentMethodNotWhitelisted(bytes32 paymentMethod); | |
| - error CurrencyNotSupported(bytes32 paymentMethod, bytes32 currency); | |
| + function getDepositRateManager(uint256 _depositId) | |
| + external | |
| + view | |
| + returns (address rateManager, bytes32 rateManagerId); | |
| - | |
| - /* ============ External Functions for Orchestrator ============ */ | |
| + function getEffectiveRate( | |
| + uint256 _depositId, | |
| + bytes32 _paymentMethod, | |
| + bytes32 _currencyCode | |
| + ) external view returns (uint256); | |
| - function lockFunds(uint256 _depositId, bytes32 _intentHash, uint256 _amount) external; | |
| - function unlockFunds(uint256 _depositId, bytes32 _intentHash) external; | |
| - function unlockAndTransferFunds(uint256 _depositId, bytes32 _intentHash, uint256 _transferAmount, address _to) external; | |
| - function extendIntentExpiry(uint256 _depositId, bytes32 _intentHash, uint256 _newExpiryTime) external; | |
| - | |
| - /* ============ View Functions ============ */ | |
| - | |
| - function getDeposit(uint256 _depositId) external view returns (Deposit memory); | |
| - function getDepositIntent(uint256 _depositId, bytes32 _intentHash) external view returns (Intent memory); | |
| - function getDepositPaymentMethods(uint256 _depositId) external view returns (bytes32[] memory); | |
| - function getDepositCurrencies(uint256 _depositId, bytes32 _paymentMethod) external view returns (bytes32[] memory); | |
| - function getDepositCurrencyMinRate(uint256 _depositId, bytes32 _paymentMethod, bytes32 _currencyCode) external view returns (uint256); | |
| - function getDepositPaymentMethodData(uint256 _depositId, bytes32 _paymentMethod) external view returns (DepositPaymentMethodData memory); | |
| - function getDepositPaymentMethodActive(uint256 _depositId, bytes32 _paymentMethod) external view returns (bool); | |
| - function getDepositGatingService(uint256 _depositId, bytes32 _paymentMethod) external view returns (address); | |
| - function getAccountDeposits(address _account) external view returns (uint256[] memory); | |
| - function getDepositIntentHashes(uint256 _depositId) external view returns (bytes32[] memory); | |
| - function getExpiredIntents(uint256 _depositId) external view returns (bytes32[] memory expiredIntents, uint256 reclaimableAmount); | |
| + function getManagerFee(uint256 _depositId) external view returns (address recipient, uint256 fee); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- contracts/interfaces/IOrchestrator.sol 2026-02-19 13:55:27 | |
| +++ contracts/interfaces/IOrchestratorV2.sol 2026-02-19 13:58:47 | |
| @@ -2,162 +2,11 @@ | |
| pragma solidity ^0.8.18; | |
| -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | |
| -import { IPostIntentHook } from "./IPostIntentHook.sol"; | |
| -import { IPreIntentHook } from "./IPreIntentHook.sol"; | |
| +import { IOrchestrator } from "./IOrchestrator.sol"; | |
| -interface IOrchestrator { | |
| - | |
| - /* ============ Structs ============ */ | |
| - | |
| - struct Intent { | |
| - address owner; // Address of the intent owner | |
| - address to; // Address to forward funds to (can be same as owner) | |
| - address escrow; // Address of the escrow contract holding the deposit | |
| - uint256 depositId; // ID of the deposit the intent is associated with | |
| - uint256 amount; // Amount of the deposit.token the owner wants to take | |
| - uint256 timestamp; // Timestamp of the intent | |
| - bytes32 paymentMethod; // The payment method to be used for the offchain payment | |
| - bytes32 fiatCurrency; // Currency code that the owner is paying in offchain (keccak256 hash of the currency code) | |
| - uint256 conversionRate; // Conversion rate of deposit token to fiat currency at the time of intent | |
| - bytes32 payeeId; // Hashed payee identifier to whom the owner will pay offchain | |
| - address referrer; // Address of the referrer who brought this intent (if any) | |
| - uint256 referrerFee; // Fee to be paid to the referrer in preciseUnits (1e16 = 1%) | |
| - IPostIntentHook postIntentHook; // Address of the post-intent hook that will execute any post-intent actions | |
| - bytes data; // Additional data to be passed to the post-intent hook contract | |
| - } | |
| - | |
| - struct SignalIntentParams { | |
| - address escrow; // The escrow contract where the deposit is held | |
| - uint256 depositId; // The ID of the deposit the taker intends to use | |
| - uint256 amount; // The amount of deposit.token the user wants to take | |
| - address to; // Address to forward funds to | |
| - bytes32 paymentMethod; // The payment method to be used for the offchain payment | |
| - bytes32 fiatCurrency; // The currency code for offchain payment | |
| - uint256 conversionRate; // The conversion rate agreed offchain | |
| - address referrer; // Address of the referrer (address(0) if no referrer) | |
| - uint256 referrerFee; // Fee to be paid to the referrer | |
| - bytes gatingServiceSignature; // Signature from the deposit's gating service | |
| - uint256 signatureExpiration; // Timestamp when the gating service signature expires | |
| - IPostIntentHook postIntentHook; // Optional post-intent hook (address(0) for no hook) | |
| - bytes preIntentHookData; // Ephemeral data passed only to the pre-intent hook during signalIntent | |
| - bytes data; // Signal data persisted in Intent and forwarded as post-intent hook signalHookData | |
| - } | |
| - | |
| - struct FulfillIntentParams { | |
| - bytes paymentProof; // Payment proof. Can be Groth16 Proof, TLSNotary proof, TLSProxy proof, attestation etc. | |
| - bytes32 intentHash; // Identifier of intent being fulfilled | |
| - bytes verificationData; // Additional data for payment verifier | |
| - bytes postIntentHookData; // Additional data for post intent hook | |
| - } | |
| - | |
| - /* ============ Events ============ */ | |
| - | |
| - event IntentSignaled( | |
| - bytes32 indexed intentHash, | |
| - address indexed escrow, | |
| - uint256 indexed depositId, | |
| - bytes32 paymentMethod, | |
| - address owner, | |
| - address to, | |
| - uint256 amount, | |
| - bytes32 fiatCurrency, | |
| - uint256 conversionRate, | |
| - uint256 timestamp | |
| - ); | |
| - | |
| - event IntentPruned( | |
| - bytes32 indexed intentHash | |
| - ); | |
| - | |
| - event IntentFulfilled( | |
| - bytes32 indexed intentHash, | |
| - address indexed fundsTransferredTo, // Address that funds were transferred to; can be intent.to or postIntentHook address | |
| - uint256 amount, | |
| - bool isManualRelease | |
| - ); | |
| - | |
| - event IntentManagerFeeSnapshotted(bytes32 indexed intentHash, address indexed feeRecipient, uint256 fee); | |
| - event DepositPreIntentHookSet(address indexed escrow, uint256 indexed depositId, address indexed hook, address setter); | |
| - event DepositWhitelistHookSet(address indexed escrow, uint256 indexed depositId, address indexed hook, address setter); | |
| - | |
| - event AllowMultipleIntentsUpdated(bool allowMultiple); | |
| - | |
| - event PaymentVerifierRegistryUpdated(address indexed paymentVerifierRegistry); | |
| - event RelayerRegistryUpdated(address indexed relayerRegistry); | |
| - event EscrowRegistryUpdated(address indexed escrowRegistry); | |
| - event DepositRateManagerControllerUpdated(address indexed depositRateManagerController); | |
| - | |
| - event ProtocolFeeUpdated(uint256 protocolFee); | |
| - event ProtocolFeeRecipientUpdated(address indexed protocolFeeRecipient); | |
| - event PartialManualReleaseDelayUpdated(uint256 partialManualReleaseDelay); | |
| - | |
| - /* ============ Standardized Custom Errors ============ */ | |
| - | |
| - // Zero value errors | |
| - error ZeroAddress(); | |
| - error ZeroValue(); | |
| - | |
| - // Authorization errors | |
| - error UnauthorizedEscrowCaller(address caller); | |
| - error UnauthorizedCaller(address caller, address authorized); | |
| - error UnauthorizedCallerOrDelegate(address caller, address owner, address delegate); | |
| - | |
| - // Not found errors | |
| - error IntentNotFound(bytes32 intentHash); | |
| - error PaymentMethodDoesNotExist(bytes32 paymentMethod); | |
| - error PaymentMethodNotSupported(bytes32 paymentMethod); | |
| - error CurrencyNotSupported(bytes32 paymentMethod, bytes32 currency); | |
| - | |
| - // Whitelist errors | |
| - error PaymentMethodNotWhitelisted(bytes32 paymentMethod); | |
| - error EscrowNotWhitelisted(address escrow); | |
| - | |
| - // Amount and fee errors | |
| - error AmountBelowMin(uint256 amount, uint256 min); | |
| - error AmountAboveMax(uint256 amount, uint256 max); | |
| - error AmountExceedsLimit(uint256 amount, uint256 limit); | |
| - error FeeExceedsMaximum(uint256 fee, uint256 maximum); | |
| - error RateBelowMinimum(uint256 rate, uint256 minRate); | |
| - | |
| - // Validation errors | |
| - error AccountHasActiveIntent(address account, bytes32 existingIntent); | |
| - error InvalidReferrerFeeConfiguration(); | |
| - error InvalidPostIntentHook(address hook); | |
| - error InvalidPreIntentHook(address hook); | |
| - error InvalidSignature(); | |
| - error SignatureExpired(uint256 expiration, uint256 currentTime); | |
| - error PartialReleaseNotAllowedYet(uint256 currentTime, uint256 allowedTime); | |
| - error DepositRateManagerControllerNotSet(); | |
| - | |
| - // Verification errors | |
| - error PaymentVerificationFailed(); | |
| - error HashMismatch(bytes32 expected, bytes32 actual); | |
| - | |
| - // Transfer errors | |
| - error TransferFailed(address recipient, uint256 amount); | |
| - error EscrowLockFailed(); | |
| - | |
| - /* ============ View Functions ============ */ | |
| - | |
| - function getIntent(bytes32 intentHash) external view returns (Intent memory); | |
| - function getAccountIntents(address account) external view returns (bytes32[] memory); | |
| - function getDepositPreIntentHook(address escrow, uint256 depositId) external view returns (IPreIntentHook); | |
| - function getDepositWhitelistHook(address escrow, uint256 depositId) external view returns (IPreIntentHook); | |
| - | |
| - /* ============ External Functions for Users ============ */ | |
| - | |
| - function signalIntent(SignalIntentParams calldata params) external; | |
| - function setDepositPreIntentHook(address escrow, uint256 depositId, IPreIntentHook hook) external; | |
| - function setDepositWhitelistHook(address escrow, uint256 depositId, IPreIntentHook hook) external; | |
| - | |
| - function cancelIntent(bytes32 intentHash) external; | |
| - | |
| - function fulfillIntent(FulfillIntentParams calldata params) external; | |
| - | |
| - function releaseFundsToPayer(bytes32 intentHash) external; | |
| - | |
| - /* ============ External Functions for Escrow ============ */ | |
| - | |
| - function pruneIntents(bytes32[] calldata intentIds) external; | |
| -} | |
| +/** | |
| + * @title IOrchestratorV2 | |
| + * @notice Marker interface for the EscrowV2-aware orchestrator. | |
| + * @dev Inherits current orchestrator surface and behavior while changing Escrow rate query routing. | |
| + */ | |
| +interface IOrchestratorV2 is IOrchestrator {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- contracts/Orchestrator.sol 2026-02-19 13:55:27 | |
| +++ contracts/OrchestratorV2.sol 2026-02-19 14:02:52 | |
| @@ -11,22 +11,22 @@ | |
| import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; | |
| import { AddressArrayUtils } from "./external/AddressArrayUtils.sol"; | |
| import { Bytes32ArrayUtils } from "./external/Bytes32ArrayUtils.sol"; | |
| -import { IOrchestrator } from "./interfaces/IOrchestrator.sol"; | |
| +import { IOrchestratorV2 } from "./interfaces/IOrchestratorV2.sol"; | |
| import { IEscrow } from "./interfaces/IEscrow.sol"; | |
| +import { IEscrowV2 } from "./interfaces/IEscrowV2.sol"; | |
| import { IEscrowRegistry } from "./interfaces/IEscrowRegistry.sol"; | |
| import { IPostIntentHook } from "./interfaces/IPostIntentHook.sol"; | |
| import { IPreIntentHook } from "./interfaces/IPreIntentHook.sol"; | |
| import { IPaymentVerifier } from "./interfaces/IPaymentVerifier.sol"; | |
| import { IPaymentVerifierRegistry } from "./interfaces/IPaymentVerifierRegistry.sol"; | |
| import { IRelayerRegistry } from "./interfaces/IRelayerRegistry.sol"; | |
| -import { IDepositRateManagerController } from "./interfaces/IDepositRateManagerController.sol"; | |
| /** | |
| - * @title Orchestrator | |
| + * @title OrchestratorV2 | |
| * @notice Orchestrator contract for the ZKP2P protocol. This contract is responsible for managing the intent (order) | |
| * lifecycle and orchestrating the P2P trading of fiat currency and onchain assets. | |
| */ | |
| -contract Orchestrator is Ownable, Pausable, ReentrancyGuard, IOrchestrator { | |
| +contract OrchestratorV2 is Ownable, Pausable, ReentrancyGuard, IOrchestratorV2 { | |
| using AddressArrayUtils for address[]; | |
| using Bytes32ArrayUtils for bytes32[]; | |
| @@ -67,7 +67,6 @@ | |
| IEscrowRegistry public escrowRegistry; // Registry of escrow contracts | |
| IPaymentVerifierRegistry public paymentVerifierRegistry; // Registry of payment verifiers | |
| IRelayerRegistry public relayerRegistry; // Registry of relayers | |
| - IDepositRateManagerController public depositRateManagerController; // External controller for rate manager config | |
| // Protocol fee configuration | |
| uint256 public protocolFee; // Protocol fee taken from taker (in preciseUnits, 1e16 = 1%) | |
| @@ -127,7 +126,7 @@ | |
| _params.paymentMethod | |
| ); | |
| - (address managerFeeRecipient, uint256 managerFee) = depositRateManagerController.getManagerFee(_params.escrow, _params.depositId); | |
| + (address managerFeeRecipient, uint256 managerFee) = IEscrowV2(_params.escrow).getManagerFee(_params.depositId); | |
| // Enforce manager fee cap regardless of registry implementation | |
| if (managerFee > MAX_MANAGER_FEE) revert FeeExceedsMaximum(managerFee, MAX_MANAGER_FEE); // policy cap (e.g., 5%) | |
| intentManagerFeeRecipient[intentHash] = managerFeeRecipient; | |
| @@ -425,18 +424,6 @@ | |
| relayerRegistry = IRelayerRegistry(_relayerRegistry); | |
| emit RelayerRegistryUpdated(_relayerRegistry); | |
| - } | |
| - | |
| - /** | |
| - * @notice GOVERNANCE ONLY: Updates the deposit rate manager controller address. | |
| - * | |
| - * @param _depositRateManagerController New controller address | |
| - */ | |
| - function setDepositRateManagerController(address _depositRateManagerController) external onlyOwner { | |
| - if (_depositRateManagerController == address(0)) revert ZeroAddress(); | |
| - | |
| - depositRateManagerController = IDepositRateManagerController(_depositRateManagerController); | |
| - emit DepositRateManagerControllerUpdated(_depositRateManagerController); | |
| } | |
| /** | |
| @@ -515,8 +502,6 @@ | |
| if (!escrowRegistry.isWhitelistedEscrow(_intent.escrow) && !escrowRegistry.isAcceptingAllEscrows()) { | |
| revert EscrowNotWhitelisted(_intent.escrow); | |
| } | |
| - | |
| - if (address(depositRateManagerController) == address(0)) revert DepositRateManagerControllerNotSet(); | |
| // Verify payment method is still valid in registry | |
| address verifier = paymentVerifierRegistry.getVerifier(_intent.paymentMethod); | |
| @@ -525,8 +510,7 @@ | |
| bool isPaymentMethodActive = IEscrow(_intent.escrow).getDepositPaymentMethodActive(_intent.depositId, _intent.paymentMethod); | |
| if (!isPaymentMethodActive) revert PaymentMethodNotSupported(_intent.paymentMethod); | |
| - uint256 minConversionRate = depositRateManagerController.getEffectiveMinRate( | |
| - _intent.escrow, | |
| + uint256 minConversionRate = IEscrowV2(_intent.escrow).getEffectiveRate( | |
| _intent.depositId, | |
| _intent.paymentMethod, | |
| _intent.fiatCurrency |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment