Source Code
Overview
S Balance
S Value
$0.00Latest 25 from a total of 2,339 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Batch Withdraw | 61070683 | 1 hr ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 61067570 | 3 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 61066543 | 3 hrs ago | IN | 0 S | 0.0061394 | ||||
| Batch Withdraw | 61066305 | 3 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 61057691 | 7 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 61039221 | 16 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 61030592 | 20 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 61029350 | 20 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 61024130 | 23 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 61021672 | 24 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 61018419 | 25 hrs ago | IN | 0 S | 0.00614 | ||||
| Publish And Fund | 61016062 | 25 hrs ago | IN | 0 S | 0.0070054 | ||||
| Refund | 61002714 | 29 hrs ago | IN | 0 S | 0.0069773 | ||||
| Batch Withdraw | 61000528 | 30 hrs ago | IN | 0 S | 0.0061394 | ||||
| Refund | 60998024 | 30 hrs ago | IN | 0 S | 0.0069773 | ||||
| Publish And Fund | 60996071 | 31 hrs ago | IN | 0 S | 0.00724141 | ||||
| Batch Withdraw | 60981159 | 36 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 60970042 | 40 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 60964322 | 42 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 60963208 | 43 hrs ago | IN | 0 S | 0.00614 | ||||
| Batch Withdraw | 60962430 | 43 hrs ago | IN | 0 S | 0.0061406 | ||||
| Batch Withdraw | 60959714 | 44 hrs ago | IN | 0 S | 0.01008605 | ||||
| Publish And Fund | 60948540 | 2 days ago | IN | 0 S | 0.00724212 | ||||
| Refund | 60948501 | 2 days ago | IN | 0 S | 0.00339718 | ||||
| Batch Withdraw | 60947711 | 2 days ago | IN | 0 S | 0.00614 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 61070683 | 1 hr ago | Contract Creation | 0 S | |||
| 61067570 | 3 hrs ago | Contract Creation | 0 S | |||
| 61067299 | 3 hrs ago | 2.2404696 S | ||||
| 61067299 | 3 hrs ago | 2.2404696 S | ||||
| 61067283 | 3 hrs ago | Contract Creation | 0 S | |||
| 61066543 | 3 hrs ago | Contract Creation | 0 S | |||
| 61066305 | 3 hrs ago | Contract Creation | 0 S | |||
| 61058227 | 7 hrs ago | 2.2404696 S | ||||
| 61058227 | 7 hrs ago | 2.2404696 S | ||||
| 61057691 | 7 hrs ago | Contract Creation | 0 S | |||
| 61039221 | 16 hrs ago | Contract Creation | 0 S | |||
| 61033078 | 18 hrs ago | 2.24046961 S | ||||
| 61033078 | 18 hrs ago | 2.24046961 S | ||||
| 61030592 | 20 hrs ago | Contract Creation | 0 S | |||
| 61030277 | 20 hrs ago | 2.24046961 S | ||||
| 61030277 | 20 hrs ago | 2.24046961 S | ||||
| 61030186 | 20 hrs ago | 2.24046961 S | ||||
| 61030186 | 20 hrs ago | 2.24046961 S | ||||
| 61029350 | 20 hrs ago | Contract Creation | 0 S | |||
| 61027284 | 21 hrs ago | 2.24046961 S | ||||
| 61027284 | 21 hrs ago | 2.24046961 S | ||||
| 61024130 | 23 hrs ago | Contract Creation | 0 S | |||
| 61021672 | 24 hrs ago | Contract Creation | 0 S | |||
| 61018419 | 25 hrs ago | Contract Creation | 0 S | |||
| 61016974 | 25 hrs ago | Contract Creation | 0 S |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Portal
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Semver} from "./libs/Semver.sol";
import {IntentSource} from "./IntentSource.sol";
import {Inbox} from "./Inbox.sol";
/**
* @title Portal
* @notice Portal contract combining IntentSource and Inbox functionality
* @dev Main entry point for intent publishing, fulfillment, and proving
*/
contract Portal is IntentSource, Inbox, Semver {
/**
* @notice Initializes the Portal contract
* @dev Creates a unified entry point combining source and destination chain functionality
*/
constructor() {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ISemver} from "../interfaces/ISemver.sol";
/**
* @title Semver
* @notice Implements semantic versioning for contracts
* @dev Abstract contract that provides a standard way to access version information
*/
abstract contract Semver is ISemver {
/**
* @notice Returns the semantic version of the contract
* @dev Implementation of ISemver interface
* @return Current version string in semantic format
*/
function version() external pure returns (string memory) { return "3.2"; }
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IProver} from "./interfaces/IProver.sol";
import {IIntentSource} from "./interfaces/IIntentSource.sol";
import {IVault} from "./interfaces/IVault.sol";
import {IPermit} from "./interfaces/IPermit.sol";
import {Intent, Route, Reward} from "./types/Intent.sol";
import {AddressConverter} from "./libs/AddressConverter.sol";
import {Refund} from "./libs/Refund.sol";
import {OriginSettler} from "./ERC7683/OriginSettler.sol";
import {Vault} from "./vault/Vault.sol";
import {Clones} from "./vault/Clones.sol";
/**
* @title IntentSource
* @notice Abstract contract for managing cross-chain intents and their associated rewards on the source chain
* @dev Base contract containing all core intent functionality for EVM chains
*/
abstract contract IntentSource is OriginSettler, IIntentSource {
using SafeERC20 for IERC20;
using AddressConverter for address;
using Clones for address;
using Math for uint256;
/// @dev CREATE2 prefix for deterministic address calculation (0xff standard, 0x41 TRON)
bytes1 private immutable CREATE2_PREFIX;
/// @dev Tron Mainnet chain ID
uint256 private immutable TRON_MAINNET_CHAIN_ID = 728126428;
/// @dev Tron Testnet (Shasta) chain ID
uint256 private immutable TRON_TESTNET_CHAIN_ID = 2494104990;
/// @dev Implementation contract address for vault cloning
address private immutable VAULT_IMPLEMENTATION;
/// @dev Tracks the lifecycle status of each intent's rewards
mapping(bytes32 => Status) private rewardStatuses;
/**
* @notice Initializes the IntentSource contract
* @dev Sets CREATE2 prefix based on chain ID and deploys vault implementation
* Uses TRON-specific prefix (0x41) for TRON networks, standard prefix (0xff) otherwise
*/
constructor() {
// TRON support
CREATE2_PREFIX = block.chainid == TRON_MAINNET_CHAIN_ID ||
block.chainid == TRON_TESTNET_CHAIN_ID
? bytes1(0x41) // TRON chain custom CREATE2 prefix
: bytes1(0xff);
VAULT_IMPLEMENTATION = address(new Vault());
}
/**
* @notice Ensures intent can be funded based on its current status
* @dev Prevents funding of intents that are already withdrawn or refunded
* Allows funding of Initial or Funded status intents (for partial funding)
* @param intentHash Hash of the intent to validate for funding eligibility
*/
modifier onlyFundable(bytes32 intentHash) {
Status status = rewardStatuses[intentHash];
if (status == Status.Withdrawn || status == Status.Refunded) {
revert InvalidStatusForFunding(status);
}
if (status == Status.Funded) {
return;
}
_;
}
/**
* @notice Retrieves reward status for a given intent hash
* @param intentHash Hash of the intent to query
* @return status Current status of the intent
*/
function getRewardStatus(
bytes32 intentHash
) public view returns (Status status) {
return rewardStatuses[intentHash];
}
/**
* @notice Calculates the hash of an intent and its components
* @param intent The intent to hash
* @return intentHash Combined hash of route and reward
* @return routeHash Hash of the route component
* @return rewardHash Hash of the reward component
*/
function getIntentHash(
Intent memory intent
)
public
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash)
{
return
getIntentHash(
intent.destination,
abi.encode(intent.route),
intent.reward
);
}
/**
* @notice Calculates the hash of an intent and its components
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes for cross-VM compatibility
* @param reward Reward structure containing distribution details
* @return intentHash Combined hash of route and reward
* @return routeHash Hash of the route component
* @return rewardHash Hash of the reward component
*/
function getIntentHash(
uint64 destination,
bytes memory route,
Reward memory reward
)
public
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash)
{
(intentHash, routeHash, rewardHash) = getIntentHash(
destination,
keccak256(route),
reward
);
}
/**
* @notice Calculates intent hash from route hash and reward components
* @param destination Destination chain ID for the intent
* @param _routeHash Pre-computed hash of the route component
* @param reward Reward structure containing distribution details
* @return intentHash Combined hash of route and reward
* @return routeHash Hash of the route component (passed through)
* @return rewardHash Hash of the reward component
*/
function getIntentHash(
uint64 destination,
bytes32 _routeHash,
Reward memory reward
)
public
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash)
{
routeHash = _routeHash;
rewardHash = keccak256(abi.encode(reward));
intentHash = keccak256(
abi.encodePacked(destination, routeHash, rewardHash)
);
}
/**
* @notice Calculates the deterministic address of the intent vault
* @param intent Intent to calculate vault address for
* @return Address of the intent vault
*/
function intentVaultAddress(
Intent calldata intent
) public view returns (address) {
return
intentVaultAddress(
intent.destination,
abi.encode(intent.route),
intent.reward
);
}
/**
* @notice Calculates the deterministic address of the intent vault
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return Address of the intent vault
*/
function intentVaultAddress(
uint64 destination,
bytes memory route,
Reward calldata reward
) public view returns (address) {
(bytes32 intentHash, , ) = getIntentHash(destination, route, reward);
return _getVault(intentHash);
}
/**
* @notice Checks if an intent is completely funded
* @param intent Intent to validate
* @return True if intent is completely funded, false otherwise
*/
function isIntentFunded(Intent calldata intent) public view returns (bool) {
return
isIntentFunded(
intent.destination,
abi.encode(intent.route),
intent.reward
);
}
/**
* @notice Checks if an intent is fully funded using universal format
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return True if intent is completely funded, false otherwise
*/
function isIntentFunded(
uint64 destination,
bytes memory route,
Reward calldata reward
) public view returns (bool) {
(bytes32 intentHash, , ) = getIntentHash(destination, route, reward);
return
rewardStatuses[intentHash] == Status.Funded ||
_isRewardFunded(reward, _getVault(intentHash));
}
/**
* @notice Creates an intent without funding
* @param intent The complete intent struct to be published
* @return intentHash Hash of the created intent
* @return vault Address of the created vault
*/
function publish(
Intent calldata intent
) public returns (bytes32 intentHash, address vault) {
return
publish(
intent.destination,
abi.encode(intent.route),
intent.reward
);
}
/**
* @notice Creates an intent without funding
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return intentHash Hash of the created intent
* @return vault Address of the created vault
*/
function publish(
uint64 destination,
bytes memory route,
Reward memory reward
) public returns (bytes32 intentHash, address vault) {
(intentHash, , ) = getIntentHash(destination, route, reward);
vault = _getVault(intentHash);
_validatePublish(intentHash);
_emitIntentPublished(intentHash, destination, route, reward);
}
/**
* @notice Creates and funds an intent in a single transaction
* @param intent The complete intent struct to be published and funded
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFund(
Intent calldata intent,
bool allowPartial
) public payable returns (bytes32 intentHash, address vault) {
return
publishAndFund(
intent.destination,
abi.encode(intent.route),
intent.reward,
allowPartial
);
}
/**
* @notice Creates and funds an intent in a single transaction
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFund(
uint64 destination,
bytes memory route,
Reward calldata reward,
bool allowPartial
) public payable returns (bytes32 intentHash, address vault) {
return
_publishAndFund(
destination,
route,
reward,
allowPartial,
msg.sender
);
}
/**
* @notice Funds an existing intent
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the route component
* @param reward Reward structure containing distribution details
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the funded intent
*/
function fund(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
bool allowPartial
) external payable returns (bytes32 intentHash) {
(intentHash, , ) = getIntentHash(destination, routeHash, reward);
_fundIntent(
intentHash,
_getVault(intentHash),
reward,
msg.sender,
allowPartial
);
Refund.excessNative();
}
/**
* @notice Funds an intent for a user with permit/allowance
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the route component
* @param reward Reward structure containing distribution details
* @param funder Address to fund the intent from
* @param permitContract Address of the permitContract instance
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the funded intent
*/
function fundFor(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
bool allowPartial,
address funder,
address permitContract
) external payable returns (bytes32 intentHash) {
(intentHash, , ) = getIntentHash(destination, routeHash, reward);
_fundIntentFor(
reward,
intentHash,
allowPartial,
funder,
permitContract
);
}
/**
* @notice Creates and funds an intent using permit/allowance
* @param intent The complete intent struct
* @param funder Address to fund the intent from
* @param permitContract Address of the permitContract instance
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the created and funded intent
*/
function publishAndFundFor(
Intent calldata intent,
bool allowPartial,
address funder,
address permitContract
) public payable returns (bytes32 intentHash, address vault) {
return
publishAndFundFor(
intent.destination,
abi.encode(intent.route),
intent.reward,
allowPartial,
funder,
permitContract
);
}
/**
* @notice Creates and funds an intent on behalf of another address using universal format
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @param funder The address providing the funding
* @param permitContract The permit contract for token approvals
* @param allowPartial Whether to accept partial funding
* @return intentHash Hash of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFundFor(
uint64 destination,
bytes memory route,
Reward calldata reward,
bool allowPartial,
address funder,
address permitContract
) public payable returns (bytes32 intentHash, address vault) {
(intentHash, ) = publish(destination, route, reward);
vault = _fundIntentFor(
reward,
intentHash,
allowPartial,
funder,
permitContract
);
}
/**
* @notice Withdraws rewards associated with an intent to its claimant
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
*/
function withdraw(
uint64 destination,
bytes32 routeHash,
Reward calldata reward
) public {
(bytes32 intentHash, , bytes32 rewardHash) = getIntentHash(
destination,
routeHash,
reward
);
IProver.ProofData memory proof = IProver(reward.prover).provenIntents(
intentHash
);
address claimant = proof.claimant;
// If the intent has been proven on a different chain, challenge the proof
if (proof.destination != destination && claimant != address(0)) {
// Challenge the proof and emit event
IProver(reward.prover).challengeIntentProof(
destination,
routeHash,
rewardHash
);
return;
}
_validateWithdraw(intentHash, claimant);
rewardStatuses[intentHash] = Status.Withdrawn;
IVault vault = IVault(_getOrDeployVault(intentHash));
vault.withdraw(reward, claimant);
emit IntentWithdrawn(intentHash, claimant);
}
/**
* @notice Batch withdraws multiple intents
* @param destinations Array of destination chain IDs for the intents
* @param routeHashes Array of route hashes for the intents
* @param rewards Array of reward structures for the intents
*/
function batchWithdraw(
uint64[] calldata destinations,
bytes32[] calldata routeHashes,
Reward[] calldata rewards
) external {
uint256 length = routeHashes.length;
if (length != rewards.length || length != destinations.length) {
revert ArrayLengthMismatch();
}
for (uint256 i = 0; i < length; ++i) {
withdraw(destinations[i], routeHashes[i], rewards[i]);
}
}
/**
* @notice Refunds rewards to the intent creator
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
*/
function refund(
uint64 destination,
bytes32 routeHash,
Reward calldata reward
) external {
(bytes32 intentHash, , ) = getIntentHash(
destination,
routeHash,
reward
);
_refund(intentHash, destination, reward, reward.creator);
}
/**
* @notice Refunds rewards to a specified address (only callable by reward creator)
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
* @param refundee Address to receive the refunded rewards
*/
function refundTo(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
address refundee
) external {
if (msg.sender != reward.creator) {
revert NotCreatorCaller(msg.sender);
}
(bytes32 intentHash, , ) = getIntentHash(
destination,
routeHash,
reward
);
_refund(intentHash, destination, reward, refundee);
}
/**
* @notice Recover tokens that were sent to the intent vault by mistake
* @dev Must not be among the intent's rewards
* @param destination Destination chain ID for the intent
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
* @param token Token address for handling incorrect vault transfers
*/
function recoverToken(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
address token
) external {
(bytes32 intentHash, , ) = getIntentHash(
destination,
routeHash,
reward
);
_validateRecover(reward, token);
IVault vault = IVault(_getOrDeployVault(intentHash));
vault.recover(reward.creator, token);
emit IntentTokenRecovered(intentHash, reward.creator, token);
}
/**
* @notice Separate function to emit the IntentPublished event
* @dev This helps avoid stack-too-deep errors in the calling function
* @param intentHash Hash of the intent
* @param destination Destination chain ID
* @param route Encoded route data
* @param reward Reward specification
*/
function _emitIntentPublished(
bytes32 intentHash,
uint64 destination,
bytes memory route,
Reward memory reward
) internal {
emit IntentPublished(
intentHash,
destination,
route,
reward.creator,
reward.prover,
reward.deadline,
reward.nativeAmount,
reward.tokens
);
}
/**
* @notice Core OriginSettler implementation for atomic intent creation and funding
* @dev Implements the unified _publishAndFund method for both open() and openFor()
* @dev Provides replay protection through vault state checking in funding logic
* @dev Handles excess ETH return for optimal user experience
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @param allowPartial Whether to accept partial funding
* @param funder The address providing the funding
* @return intentHash Hash of the created and funded intent
* @return vault Address of the created vault
*/
function _publishAndFund(
uint64 destination,
bytes memory route,
Reward memory reward,
bool allowPartial,
address funder
) internal override returns (bytes32 intentHash, address vault) {
(intentHash, vault) = publish(destination, route, reward);
_fundIntent(intentHash, vault, reward, funder, allowPartial);
Refund.excessNative();
}
/**
* @notice Handles the funding of an intent - OriginSettler implementation
* @dev Called by _publishAndFund to atomically fund intents after creation
* @dev Updates reward status and validates funding completeness
* @param intentHash Hash of the intent
* @param vault Address of the intent's vault
* @param reward Reward structure to fund
* @param funder Address providing the funds
* @param allowPartial Whether to allow partial funding
*/
function _fundIntent(
bytes32 intentHash,
address vault,
Reward memory reward,
address funder,
bool allowPartial
) internal onlyFundable(intentHash) {
bool fullyFunded = _fundNative(vault, reward.nativeAmount);
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
IERC20 token = IERC20(reward.tokens[i].token);
fullyFunded =
fullyFunded &&
_fundToken(vault, funder, token, reward.tokens[i].amount);
}
if (!allowPartial && !fullyFunded) {
revert InsufficientFunds(intentHash);
}
if (fullyFunded) {
rewardStatuses[intentHash] = Status.Funded;
}
emit IntentFunded(intentHash, funder, fullyFunded);
}
/**
* @notice Funds vault with native tokens (ETH)
* @param vault Address of the vault to fund
* @param rewardAmount Required native token amount
* @return funded True if vault has sufficient native balance after funding attempt
*/
function _fundNative(
address vault,
uint256 rewardAmount
) internal returns (bool funded) {
uint256 balance = vault.balance;
if (balance >= rewardAmount) {
return true;
}
uint256 remaining = rewardAmount - balance;
uint256 transferAmount = remaining.min(msg.value);
if (transferAmount > 0) {
payable(vault).transfer(transferAmount);
}
return transferAmount >= remaining;
}
/**
* @notice Funds vault with ERC20 tokens
* @param vault Address of the vault to fund
* @param token ERC20 token contract to transfer
* @param rewardAmount Required token amount
* @return funded True if vault has sufficient token balance after funding attempt
*/
function _fundToken(
address vault,
address funder,
IERC20 token,
uint256 rewardAmount
) internal returns (bool funded) {
uint256 balance = token.balanceOf(vault);
if (balance >= rewardAmount) {
return true;
}
uint256 remaining = rewardAmount - balance;
uint256 transferAmount = remaining
.min(token.allowance(funder, address(this)))
.min(token.balanceOf(funder));
if (transferAmount > 0) {
token.safeTransferFrom(funder, vault, transferAmount);
}
return balance + transferAmount >= rewardAmount;
}
/**
* @notice Funds an intent using a permit contract for gasless approvals
* @param reward Reward structure containing funding requirements
* @param intentHash Hash of the intent to fund
* @param funder Address providing the funding
* @param permitContract Address of permit contract for token approvals
* @param allowPartial Whether to allow partial funding
* @return vault Address of the funded vault
*/
function _fundIntentFor(
Reward calldata reward,
bytes32 intentHash,
bool allowPartial,
address funder,
address permitContract
) internal onlyFundable(intentHash) returns (address vault) {
vault = _getOrDeployVault(intentHash);
bool fullyFunded = IVault(vault).fundFor{value: msg.value}(
reward,
funder,
IPermit(permitContract)
);
if (!allowPartial && !fullyFunded) {
revert InsufficientFunds(intentHash);
}
if (fullyFunded) {
rewardStatuses[intentHash] = Status.Funded;
}
emit IntentFunded(intentHash, funder, fullyFunded);
}
/**
* @notice Validates that an intent's vault holds sufficient rewards
* @dev Checks both native token and ERC20 token balances
* @param reward Reward to validate
* @param vault Address of the intent's vault
* @return True if vault has sufficient funds, false otherwise
*/
function _isRewardFunded(
Reward calldata reward,
address vault
) internal view returns (bool) {
uint256 rewardsLength = reward.tokens.length;
if (vault.balance < reward.nativeAmount) return false;
for (uint256 i = 0; i < rewardsLength; ++i) {
address token = reward.tokens[i].token;
uint256 amount = reward.tokens[i].amount;
uint256 balance = IERC20(token).balanceOf(vault);
if (balance < amount) return false;
}
return true;
}
/**
* @notice Validates and publishes a new intent
* @param intentHash Hash of the intent
*/
function _validatePublish(bytes32 intentHash) internal view {
Status status = rewardStatuses[intentHash];
if (status == Status.Withdrawn || status == Status.Refunded) {
revert IntentAlreadyExists(intentHash);
}
}
/**
* @notice Validates that an intent can be refunded
* @dev Checks if intent has been proven/claimed to prevent invalid refunds
* @param intentHash Hash of the intent to validate
* @param destination Expected destination chain ID
* @param reward Reward structure containing prover information
*/
function _validateRefund(
bytes32 intentHash,
uint64 destination,
Reward calldata reward
) internal view {
Status status = rewardStatuses[intentHash];
IProver.ProofData memory proof = IProver(reward.prover).provenIntents(
intentHash
);
// If proof is incorrect or no proof
if (proof.destination != destination || proof.claimant == address(0)) {
if (block.timestamp < reward.deadline) {
revert InvalidStatusForRefund(
status,
block.timestamp,
reward.deadline
);
}
return;
}
if (status == Status.Initial || status == Status.Funded) {
revert IntentNotClaimed(intentHash);
}
}
/**
* @notice Validates that vault can be withdrawn from and claimant is valid
* @dev Allows withdrawal from Initial or Funded status, prevents zero address claimant
* @param intentHash Hash of the intent
* @param claimant Address that will receive the withdrawn rewards
*/
function _validateWithdraw(
bytes32 intentHash,
address claimant
) internal view {
Status status = rewardStatuses[intentHash];
if (status != Status.Initial && status != Status.Funded) {
revert InvalidStatusForWithdrawal(status);
}
if (claimant == address(0)) {
revert InvalidClaimant();
}
}
/**
* @notice Validates that token can be recovered (not zero address and not a reward token)
* @dev Prevents recovery of reward tokens and zero address, allows recovery of mistaken transfers
* @param reward Reward structure containing token list
* @param token Address of the token to recover
*/
function _validateRecover(
Reward calldata reward,
address token
) internal pure {
if (token == address(0)) {
revert InvalidRecoverToken(token);
}
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
if (reward.tokens[i].token == token) {
revert InvalidRecoverToken(token);
}
}
}
/**
* @notice Internal function to refund rewards to a specified address
* @param intentHash Hash of the intent to refund
* @param destination Destination chain ID for the intent
* @param reward Reward structure of the intent
* @param refundee Address to receive the refunded rewards
*/
function _refund(
bytes32 intentHash,
uint64 destination,
Reward calldata reward,
address refundee
) internal {
_validateRefund(intentHash, destination, reward);
rewardStatuses[intentHash] = Status.Refunded;
IVault vault = IVault(_getOrDeployVault(intentHash));
vault.refund(reward, refundee);
emit IntentRefunded(intentHash, refundee);
}
/**
* @notice Gets existing vault address or deploys new one if needed
* @param intentHash Hash used as CREATE2 salt for deterministic addressing
* @return Address of the vault (existing or newly deployed)
*/
function _getOrDeployVault(bytes32 intentHash) internal returns (address) {
address vault = _getVault(intentHash);
return
vault.code.length > 0
? vault
: VAULT_IMPLEMENTATION.clone(intentHash);
}
/**
* @notice Calculates the deterministic vault address without deployment
* @param intentHash Hash used as CREATE2 salt for address calculation
* @return Predicted address of the vault
*/
function _getVault(bytes32 intentHash) internal view returns (address) {
return VAULT_IMPLEMENTATION.predict(intentHash, CREATE2_PREFIX);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IProver} from "./interfaces/IProver.sol";
import {IInbox} from "./interfaces/IInbox.sol";
import {IExecutor} from "./interfaces/IExecutor.sol";
import {Route, Call, TokenAmount} from "./types/Intent.sol";
import {Semver} from "./libs/Semver.sol";
import {Refund} from "./libs/Refund.sol";
import {DestinationSettler} from "./ERC7683/DestinationSettler.sol";
import {Executor} from "./Executor.sol";
/**
* @title Inbox
* @notice Main entry point for fulfilling intents on the destination chain
* @dev Validates intent hash authenticity, executes calldata, and enables provers
* to claim rewards on the source chain by checking the claimants mapping
*/
abstract contract Inbox is DestinationSettler, IInbox {
using SafeERC20 for IERC20;
/**
* @notice Mapping of intent hashes to their claimant identifiers
* @dev Stores the cross-VM compatible claimant identifier for each fulfilled intent
*/
mapping(bytes32 => bytes32) public claimants;
IExecutor public immutable executor;
/**
* @notice Chain ID stored as immutable for gas efficiency
* @dev Used to prepend to proof messages for cross-chain identification
*/
uint64 private immutable CHAIN_ID;
/**
* @notice Initializes the Inbox contract
* @dev Sets up the base contract for handling intent fulfillment on destination chains
*/
constructor() {
executor = new Executor();
// Validate that chain ID fits in uint64 and store it
if (block.chainid > type(uint64).max) {
revert ChainIdTooLarge(block.chainid);
}
CHAIN_ID = uint64(block.chainid);
}
/**
* @notice Fulfills an intent to be proven via storage proofs
* @dev Validates intent hash, executes calls, and marks as fulfilled
* @param intentHash The hash of the intent to fulfill
* @param route The route of the intent
* @param rewardHash The hash of the reward details
* @param claimant Cross-VM compatible claimant identifier
* @return Array of execution results from each call
*/
function fulfill(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant
) external payable returns (bytes[] memory) {
bytes[] memory result = _fulfill(
intentHash,
route,
rewardHash,
claimant
);
// Refund any remaining balance (excess ETH)
Refund.excessNative();
return result;
}
/**
* @notice Fulfills an intent and initiates proving in one transaction
* @dev Executes intent actions and sends proof message to source chain
* @param intentHash The hash of the intent to fulfill
* @param route The route of the intent
* @param rewardHash The hash of the reward details
* @param claimant Cross-VM compatible claimant identifier
* @param prover Address of prover on the destination chain
* @param sourceChainDomainID Domain ID of the source chain where the intent was created
* @param data Additional data for message formatting
* @return Array of execution results
*
* @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
* Each bridge provider uses their own domain ID mapping system:
* - Hyperlane: Uses custom domain IDs that may differ from chain IDs
* - LayerZero: Uses endpoint IDs that map to chains differently
* - Metalayer: Uses domain IDs specific to their routing system
* - Polymer: Uses chain IDs
* You MUST consult the specific bridge provider's documentation to determine
* the correct domain ID for the source chain.
*/
function fulfillAndProve(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant,
address prover,
uint64 sourceChainDomainID,
bytes memory data
)
public
payable
override(DestinationSettler, IInbox)
returns (bytes[] memory)
{
bytes[] memory result = _fulfill(
intentHash,
route,
rewardHash,
claimant
);
// Create array with single intent hash
bytes32[] memory intentHashes = new bytes32[](1);
intentHashes[0] = intentHash;
// Call prove with the intent hash array
// This will also refund any excess ETH
prove(prover, sourceChainDomainID, intentHashes, data);
return result;
}
/**
* @notice Initiates proving process for fulfilled intents
* @dev Sends message to source chain to verify intent execution
* @param prover Address of prover on the destination chain
* @param sourceChainDomainID Domain ID of the source chain
* @param intentHashes Array of intent hashes to prove
* @param data Additional data for message formatting
*
* @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
* Each bridge provider uses their own domain ID mapping system:
* - Hyperlane: Uses custom domain IDs that may differ from chain IDs
* - LayerZero: Uses endpoint IDs that map to chains differently
* - Metalayer: Uses domain IDs specific to their routing system
* - Polymer: Uses chainIDs
* You MUST consult the specific bridge provider's documentation to determine
* the correct domain ID for the source chain.
*/
function prove(
address prover,
uint64 sourceChainDomainID,
bytes32[] memory intentHashes,
bytes memory data
) public payable {
uint256 size = intentHashes.length;
// Encode chain ID followed by intent hash/claimant pairs as bytes
// 8 bytes for chain ID + (32 bytes for intent hash + 32 bytes for claimant) * size
bytes memory encodedClaimants = new bytes(8 + size * 64);
// Prepend chain ID to the encoded data
uint64 chainId = CHAIN_ID;
assembly {
mstore(add(encodedClaimants, 0x20), shl(192, chainId))
}
for (uint256 i = 0; i < size; ++i) {
bytes32 claimantBytes = claimants[intentHashes[i]];
if (claimantBytes == bytes32(0)) {
revert IntentNotFulfilled(intentHashes[i]);
}
// Pack intent hash and claimant into encodedData (after 8-byte chain ID)
assembly {
let offset := add(8, mul(i, 64))
mstore(
add(add(encodedClaimants, 0x20), offset),
mload(add(intentHashes, add(0x20, mul(i, 32))))
)
mstore(
add(add(encodedClaimants, 0x20), add(offset, 32)),
claimantBytes
)
}
// Emit IntentProven event
emit IntentProven(intentHashes[i], claimantBytes);
}
// Provide left over balance to the prover
IProver(prover).prove{value: address(this).balance}(
msg.sender,
sourceChainDomainID,
encodedClaimants,
data
);
}
/**
* @notice Internal function to fulfill intents
* @dev Validates intent and executes calls
* @param intentHash The hash of the intent to fulfill
* @param route The route of the intent
* @param rewardHash The hash of the reward
* @param claimant Cross-VM compatible claimant identifier
* @return Array of execution results
*/
function _fulfill(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant
) internal returns (bytes[] memory) {
// Check if the route has expired
if (block.timestamp > route.deadline) {
revert IntentExpired();
}
bytes32 routeHash = keccak256(abi.encode(route));
bytes32 computedIntentHash = keccak256(
abi.encodePacked(CHAIN_ID, routeHash, rewardHash)
);
if (route.portal != address(this)) {
revert InvalidPortal(route.portal);
}
if (computedIntentHash != intentHash) {
revert InvalidHash(intentHash);
}
if (claimants[intentHash] != bytes32(0)) {
revert IntentAlreadyFulfilled(intentHash);
}
if (claimant == bytes32(0)) {
revert ZeroClaimant();
}
claimants[intentHash] = claimant;
emit IntentFulfilled(intentHash, claimant);
// Transfer ERC20 tokens to the executor
uint256 tokensLength = route.tokens.length;
// Validate that msg.value is at least the route's nativeAmount
// Allow extra value for cross-chain message fees when using fulfillAndProve
if (msg.value < route.nativeAmount) {
revert InsufficientNativeAmount(msg.value, route.nativeAmount);
}
for (uint256 i = 0; i < tokensLength; ++i) {
TokenAmount memory token = route.tokens[i];
IERC20(token.token).safeTransferFrom(
msg.sender,
address(executor),
token.amount
);
}
return executor.execute{value: route.nativeAmount}(route.calls);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title Semver Interface
* @dev An interface for a contract that has a version
*/
interface ISemver {
function version() external pure returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ISemver} from "./ISemver.sol";
/**
* @title IProver
* @notice Interface for proving intent fulfillment
* @dev Defines required functionality for proving intent execution with different
* proof mechanisms (storage or Hyperlane)
*/
interface IProver is ISemver {
/**
* @notice Proof data stored for each proven intent
* @param claimant Address eligible to claim the intent rewards
* @param destination Chain ID where the intent was proven
*/
struct ProofData {
address claimant;
uint64 destination;
}
/**
* @notice Arrays of intent hashes and claimants must have the same length
*/
error ArrayLengthMismatch();
/**
* @notice Portal address cannot be zero
*/
error ZeroPortal();
/**
* @notice Chain ID is too large to fit in uint64
* @param chainId The chain ID that is too large
*/
error ChainIdTooLarge(uint256 chainId);
/**
* @notice Emitted when an intent is successfully proven
* @dev Emitted by the Prover on the source chain.
* @param intentHash Hash of the proven intent
* @param claimant Address eligible to claim the intent rewards
* @param destination Destination chain ID where the intent was proven
*/
event IntentProven(
bytes32 indexed intentHash,
address indexed claimant,
uint64 destination
);
/**
* @notice Emitted when an intent proof is invalidated
* @param intentHash Hash of the invalidated intent
*/
event IntentProofInvalidated(bytes32 indexed intentHash);
/**
* @notice Emitted when attempting to prove an already-proven intent
* @dev Event instead of error to allow batch processing to continue
* @param intentHash Hash of the already proven intent
*/
event IntentAlreadyProven(bytes32 intentHash);
/**
* @notice Gets the proof mechanism type used by this prover
* @return string indicating the prover's mechanism
*/
function getProofType() external pure returns (string memory);
/**
* @notice Initiates the proving process for intents from the destination chain
* @dev Implemented by specific prover mechanisms (storage, Hyperlane, Metalayer)
* @param sender Address of the original transaction sender
* @param sourceChainDomainID Domain ID of the source chain
* @param encodedProofs Encoded (intentHash, claimant) pairs as bytes
* @param data Additional data specific to the proving implementation
*
* @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
* Each bridge provider uses their own domain ID mapping system:
* - Hyperlane: Uses custom domain IDs that may differ from chain IDs
* - LayerZero: Uses endpoint IDs that map to chains differently
* - Metalayer: Uses domain IDs specific to their routing system
* - Polymer: Uses chainIDs
* You MUST consult the specific bridge provider's documentation to determine
* the correct domain ID for the source chain.
*/
function prove(
address sender,
uint64 sourceChainDomainID,
bytes calldata encodedProofs,
bytes calldata data
) external payable;
/**
* @notice Returns the proof data for a given intent hash
* @param intentHash Hash of the intent to query
* @return ProofData containing claimant and destination chain ID
*/
function provenIntents(
bytes32 intentHash
) external view returns (ProofData memory);
/**
* @notice Challenge an intent proof if destination chain ID doesn't match
* @dev Can be called by anyone to remove invalid proofs. This is a safety mechanism to ensure
* intents are only claimable when executed on their intended destination chains.
* @param destination The intended destination chain ID
* @param routeHash The hash of the intent's route
* @param rewardHash The hash of the reward specification
*/
function challengeIntentProof(
uint64 destination,
bytes32 routeHash,
bytes32 rewardHash
) external;
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Intent, Reward, TokenAmount} from "../types/Intent.sol";
/**
* @title IIntentSource
* @notice Interface for managing cross-chain intents and their associated rewards on the source chain
* @dev This contract works in conjunction with a portal contract on the destination chain
* and a prover contract for verification. It handles intent creation, funding,
* and reward distribution.
*/
interface IIntentSource {
/// @notice Intent lifecycle status
enum Status {
Initial, /// @dev Intent created, may be partially funded but not fully funded
Funded, /// @dev Intent has been fully funded with all required rewards
Withdrawn, /// @dev Rewards have been withdrawn by claimant
Refunded /// @dev Rewards have been refunded to creator
}
/**
* @notice Indicates an attempt to publish a duplicate intent
* @param intentHash The hash of the pre-existing intent
*/
error IntentAlreadyExists(bytes32 intentHash);
/**
* @notice Indicates a premature refund attempt before intent completion
* @param intentHash The hash of the unclaimed intent
*/
error IntentNotClaimed(bytes32 intentHash);
/**
* @notice Indicates mismatched array lengths in batch operations
*/
error ArrayLengthMismatch();
/**
* @notice Indicates insufficient funds to complete the intent funding
* @param intentHash The hash of the intent that couldn't be funded
*/
error InsufficientFunds(bytes32 intentHash);
/// @notice Thrown when intent status is invalid for funding operation
error InvalidStatusForFunding(Status status);
/// @notice Thrown when intent status is invalid for withdrawal operation
error InvalidStatusForWithdrawal(Status status);
/// @notice Thrown when attempting to recover an invalid token (zero address or reward token)
error InvalidRecoverToken(address token);
/// @notice Thrown when intent status is invalid for refund operation or deadline not reached
error InvalidStatusForRefund(
Status status,
uint256 currentTime,
uint256 deadline
);
/// @notice Thrown when claimant address is address zero
error InvalidClaimant();
/// @notice Thrown when caller is not the reward creator
error NotCreatorCaller(address caller);
/**
* @notice Signals the creation of a new cross-chain intent
* @param intentHash Unique identifier of the intent
* @param destination Destination chain ID
* @param route Encoded route data for the destination chain
* @param creator Intent originator address
* @param prover Prover contract address
* @param rewardDeadline Timestamp for reward claim eligibility
* @param rewardNativeAmount Native token reward amount
* @param rewardTokens ERC20 token rewards with amounts
*/
event IntentPublished(
bytes32 indexed intentHash,
uint64 destination,
bytes route,
address indexed creator,
address indexed prover,
uint64 rewardDeadline,
uint256 rewardNativeAmount,
TokenAmount[] rewardTokens
);
/**
* @notice Signals funding of an intent
* @param intentHash The hash of the funded intent
* @param funder The address providing the funding
* @param complete Whether the intent was completely funded (true) or partially funded (false)
*/
event IntentFunded(bytes32 intentHash, address funder, bool complete);
/**
* @notice Signals successful reward withdrawal
* @param intentHash The hash of the claimed intent
* @param claimant The address receiving the rewards
*/
event IntentWithdrawn(bytes32 intentHash, address indexed claimant);
/**
* @notice Signals successful reward refund
* @param intentHash The hash of the refunded intent
* @param refundee The address receiving the refund
*/
event IntentRefunded(bytes32 intentHash, address indexed refundee);
/**
* @notice Signals successful token recovery from an intent vault
* @dev Emitted when tokens that were accidentally sent to a vault are recovered
* Only tokens not part of the intent's reward structure can be recovered
* @param intentHash The hash of the intent whose vault had tokens recovered
* @param refundee The address receiving the recovered tokens (typically the intent creator)
* @param token The address of the token contract that was recovered
*/
event IntentTokenRecovered(
bytes32 intentHash,
address indexed refundee,
address indexed token
);
/**
* @notice Retrieves the current reward claim status for an intent
* @param intentHash The hash of the intent
* @return status Current reward status
*/
function getRewardStatus(
bytes32 intentHash
) external view returns (Status status);
/**
* @notice Computes the hash components of an intent
* @param intent The intent to hash
* @return intentHash Combined hash of route and reward components
* @return routeHash Hash of the route specifications
* @return rewardHash Hash of the reward specifications
*/
function getIntentHash(
Intent memory intent
)
external
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash);
/**
* @notice Computes the hash components of an intent
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return intentHash Combined hash of route and reward components
* @return routeHash Hash of the route specifications
* @return rewardHash Hash of the reward specifications
*/
function getIntentHash(
uint64 destination,
bytes memory route,
Reward memory reward
)
external
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash);
/**
* @notice Computes the deterministic vault address for an intent
* @param intent The intent to calculate the vault address for
* @return Predicted vault address
*/
function intentVaultAddress(
Intent calldata intent
) external view returns (address);
/**
* @notice Computes the deterministic vault address for an intent
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return Predicted vault address
*/
function intentVaultAddress(
uint64 destination,
bytes memory route,
Reward calldata reward
) external view returns (address);
/**
* @notice Checks if an intent's rewards are valid and fully funded
* @param intent The intent to validate
* @return True if the intent is properly funded
*/
function isIntentFunded(
Intent calldata intent
) external view returns (bool);
/**
* @notice Checks if an intent's rewards are valid and fully funded
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return True if the intent is properly funded
*/
function isIntentFunded(
uint64 destination,
bytes memory route,
Reward calldata reward
) external view returns (bool);
/**
* @notice Creates a new cross-chain intent with associated rewards
* @dev Intent must be proven on source chain before expiration for valid reward claims
* @param intent The complete intent specification
* @return intentHash Unique identifier of the created intent
* @return vault Address of the created vault
*/
function publish(
Intent calldata intent
) external returns (bytes32 intentHash, address vault);
/**
* @notice Creates a new cross-chain intent with associated rewards
* @dev Intent must be proven on source chain before expiration for valid reward claims
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @return intentHash Unique identifier of the created intent
* @return vault Address of the created vault
*/
function publish(
uint64 destination,
bytes memory route,
Reward memory reward
) external returns (bytes32 intentHash, address vault);
/**
* @notice Creates and funds an intent in a single transaction
* @param intent The complete intent specification
* @param allowPartial Whether to allow partial funding
* @return intentHash Unique identifier of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFund(
Intent calldata intent,
bool allowPartial
) external payable returns (bytes32 intentHash, address vault);
/**
* @notice Creates and funds an intent in a single transaction
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @param allowPartial Whether to allow partial funding
* @return intentHash Unique identifier of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFund(
uint64 destination,
bytes memory route,
Reward memory reward,
bool allowPartial
) external payable returns (bytes32 intentHash, address vault);
/**
* @notice Funds an existing intent
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @param allowPartial Whether to allow partial funding
* @return intentHash The hash of the funded intent
*/
function fund(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
bool allowPartial
) external payable returns (bytes32 intentHash);
/**
* @notice Funds an intent on behalf of another address using permit
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @param allowPartial Whether to accept partial funding
* @param fundingAddress The address providing the funding
* @param permitContract The permit contract address for external token approvals
* @return intentHash The hash of the funded intent
*/
function fundFor(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
bool allowPartial,
address fundingAddress,
address permitContract
) external payable returns (bytes32 intentHash);
/**
* @notice Creates and funds an intent on behalf of another address
* @param intent The complete intent specification
* @param allowPartial Whether to accept partial funding
* @param funder The address providing the funding
* @param permitContract The permit contract for token approvals
* @return intentHash The hash of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFundFor(
Intent calldata intent,
bool allowPartial,
address funder,
address permitContract
) external payable returns (bytes32 intentHash, address vault);
/**
* @notice Creates and funds an intent on behalf of another address
* @param destination Destination chain ID for the intent
* @param route Encoded route data for the intent as bytes
* @param reward The reward structure containing distribution details
* @param allowPartial Whether to accept partial funding
* @param funder The address providing the funding
* @param permitContract The permit contract for token approvals
* @return intentHash The hash of the created and funded intent
* @return vault Address of the created vault
*/
function publishAndFundFor(
uint64 destination,
bytes memory route,
Reward calldata reward,
bool allowPartial,
address funder,
address permitContract
) external payable returns (bytes32 intentHash, address vault);
/**
* @notice Claims rewards for a successfully fulfilled and proven intent
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
*/
function withdraw(
uint64 destination,
bytes32 routeHash,
Reward calldata reward
) external;
/**
* @notice Claims rewards for multiple fulfilled and proven intents
* @param destinations Array of destination chain IDs for the intents
* @param routeHashes Array of route component hashes
* @param rewards Array of corresponding reward specifications
*/
function batchWithdraw(
uint64[] calldata destinations,
bytes32[] calldata routeHashes,
Reward[] calldata rewards
) external;
/**
* @notice Returns rewards to the intent creator
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
*/
function refund(
uint64 destination,
bytes32 routeHash,
Reward calldata reward
) external;
/**
* @notice Returns rewards to a specified address (only callable by reward creator)
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @param refundee Address to receive the refunded rewards
*/
function refundTo(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
address refundee
) external;
/**
* @notice Recovers mistakenly transferred tokens from the intent vault
* @dev Token must not be part of the intent's reward structure
* @param destination Destination chain ID for the intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @param token The address of the token to recover
*/
function recoverToken(
uint64 destination,
bytes32 routeHash,
Reward calldata reward,
address token
) external;
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Reward} from "../types/Intent.sol";
import {IPermit} from "./IPermit.sol";
/**
* @title IVault
* @notice Interface for Vault contract that manages reward escrow functionality
* @dev Handles funding, withdrawal, and refund operations for cross-chain rewards
*/
interface IVault {
/// @notice Thrown when caller is not the portal contract
error NotPortalCaller(address caller);
/// @notice Thrown when attempting to recover a token with zero balance
error ZeroRecoverTokenBalance(address token);
/// @notice Thrown when native token transfer fails
error NativeTransferFailed(address to, uint256 amount);
/**
* @notice Funds the vault with reward tokens and native currency
* @param reward The reward structure containing tokens and amounts
* @param funder Address providing the funding
* @param permit Optional permit contract for token transfers
* @return fullyFunded True if vault was successfully fully funded
*/
function fundFor(
Reward calldata reward,
address funder,
IPermit permit
) external payable returns (bool fullyFunded);
/**
* @notice Withdraws rewards from the vault to the claimant
* @param reward The reward structure to withdraw
* @param claimant Address that will receive the rewards
*/
function withdraw(Reward calldata reward, address claimant) external;
/**
* @notice Refunds rewards to a specified address
* @param reward The reward structure to refund
* @param refundee Address to receive the refunded rewards
*/
function refund(Reward calldata reward, address refundee) external;
/**
* @notice Recovers tokens that are not part of the reward to the creator
* @param refundee Address to receive the recovered tokens
* @param token Address of the token to recover (must not be a reward token)
*/
function recover(address refundee, address token) external;
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/// @title IPermit
/// @notice Handles ERC20 token permissions through signature based allowance setting and ERC20 token transfers by checking allowed amounts
/// @dev Requires user's token approval on the Permit2 like contract
/// @dev This is the subset of the Uniswap permit2 interface
interface IPermit {
/// @notice Thrown when an allowance on a token has expired.
/// @param deadline The timestamp at which the allowed amount is no longer valid
error AllowanceExpired(uint256 deadline);
/// @notice Thrown when an allowance on a token has been depleted.
/// @param amount The maximum amount allowed
error InsufficientAllowance(uint256 amount);
/// @notice Thrown when too many nonces are invalidated.
error ExcessiveInvalidation();
/// @notice Emits an event when the owner successfully invalidates an ordered nonce.
event NonceInvalidation(
address indexed owner,
address indexed token,
address indexed spender,
uint48 newNonce,
uint48 oldNonce
);
/// @notice Emits an event when the owner successfully sets permissions on a token for the spender.
event Approval(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration
);
/// @notice Emits an event when the owner successfully sets permissions using a permit signature on a token for the spender.
event Permit(
address indexed owner,
address indexed token,
address indexed spender,
uint160 amount,
uint48 expiration,
uint48 nonce
);
/// @notice Emits an event when the owner sets the allowance back to 0 with the lockdown function.
event Lockdown(address indexed owner, address token, address spender);
/// @notice Details for a token transfer.
struct AllowanceTransferDetails {
// the owner of the token
address from;
// the recipient of the token
address to;
// the amount of the token
uint160 amount;
// the token to be transferred
address token;
}
/// @notice A mapping from owner address to token address to spender address to PackedAllowance struct, which contains details and conditions of the approval.
/// @notice The mapping is indexed in the above order see: allowance[ownerAddress][tokenAddress][spenderAddress]
/// @dev The packed slot holds the allowed amount, expiration at which the allowed amount is no longer valid, and current nonce thats updated on any signature based approvals.
function allowance(
address user,
address token,
address spender
) external view returns (uint160 amount, uint48 expiration, uint48 nonce);
/// @notice Transfer approved tokens from one address to another
/// @param from The address to transfer from
/// @param to The address of the recipient
/// @param amount The amount of the token to transfer
/// @param token The token address to transfer
/// @dev Requires the from address to have approved at least the desired amount
/// of tokens to msg.sender.
function transferFrom(
address from,
address to,
uint160 amount,
address token
) external;
/// @notice Transfer approved tokens in a batch
/// @param transferDetails Array of owners, recipients, amounts, and tokens for the transfers
/// @dev Requires the from addresses to have approved at least the desired amount
/// of tokens to msg.sender.
function transferFrom(
AllowanceTransferDetails[] calldata transferDetails
) external;
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @notice Represents a single contract call with encoded function data
* @dev Used to execute arbitrary function calls on the destination chain
* @param target The contract address to call
* @param data ABI-encoded function call data
* @param value Amount of native tokens to send with the call
*/
struct Call {
address target;
bytes data;
uint256 value;
}
/**
* @notice Represents a token amount pair
* @dev Used to specify token rewards and transfers
* @param token Address of the ERC20 token contract
* @param amount Amount of tokens in the token's smallest unit
*/
struct TokenAmount {
address token;
uint256 amount;
}
/**
* @notice Defines the routing and execution instructions for cross-chain messages
* @dev Contains all necessary information to route and execute a message on the destination chain
* @param salt Unique identifier provided by the intent creator, used to prevent duplicates
* @param deadline Timestamp by which the route must be executed
* @param portal Address of the portal contract on the destination chain that receives messages
* @param nativeAmount Amount of native tokens to send with the route execution
* @param tokens Array of tokens required for execution of calls on destination chain
* @param calls Array of contract calls to execute on the destination chain in sequence
*/
struct Route {
bytes32 salt;
uint64 deadline;
address portal;
uint256 nativeAmount;
TokenAmount[] tokens;
Call[] calls;
}
/**
* @notice Defines the reward and validation parameters for cross-chain execution
* @dev Specifies who can execute the intent and what rewards they receive
* @param deadline Timestamp after which the intent can no longer be executed
* @param creator Address that created the intent and has authority to modify/cancel
* @param prover Address of the prover contract that must approve execution
* @param nativeAmount Amount of native tokens offered as reward
* @param tokens Array of ERC20 tokens and amounts offered as additional rewards
*/
struct Reward {
uint64 deadline;
address creator;
address prover;
uint256 nativeAmount;
TokenAmount[] tokens;
}
/**
* @notice Complete cross-chain intent combining routing and reward information
* @dev Main structure used to process and execute cross-chain messages
* @param destination Target chain ID where the intent should be executed
* @param route Routing and execution instructions
* @param reward Reward and validation parameters
*/
struct Intent {
uint64 destination;
Route route;
Reward reward;
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title AddressConverter
* @notice Utility library for converting between address and bytes32 types
* @dev Provides simple functions to convert between address (20 bytes) and bytes32 (32 bytes)
*/
library AddressConverter {
error InvalidAddress(bytes32 value);
/**
* @notice Convert an Ethereum address to bytes32
* @dev Pads the 20-byte address to 32 bytes by converting to uint160, then uint256, then bytes32
* @param addr The address to convert
* @return The bytes32 representation of the address
*/
function toBytes32(address addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
/**
* @notice Convert bytes32 to an Ethereum address
* @dev Truncates the 32-byte value to 20 bytes by converting to uint256, then uint160, then address
* @param b The bytes32 value to convert
* @return The address representation of the bytes32 value
*/
function toAddress(bytes32 b) internal pure returns (address) {
if (!isValidAddress(b)) {
revert InvalidAddress(b);
}
return address(uint160(uint256(b)));
}
/**
* @notice Check if a bytes32 value represents a valid Ethereum address
* @dev An Ethereum address must have the top 12 bytes as zero
* @param b The bytes32 value to check
* @return True if the bytes32 value can be safely converted to an Ethereum address
*/
function isValidAddress(bytes32 b) internal pure returns (bool) {
// The top 12 bytes must be zero for a valid Ethereum address
return uint256(b) >> 160 == 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title Refund
* @notice Library for handling native token refunds
* @dev Provides common refund functionality for contracts
*/
library Refund {
/**
* @notice Refunds all remaining native tokens to the sender
* @dev Does not revert on failure to prevent griefing attacks
* @return success Whether the refund was successful
*/
function excessNative() internal returns (bool success) {
uint256 balance = address(this).balance;
if (balance == 0) return true;
(success, ) = payable(msg.sender).call{value: balance}("");
}
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IOriginSettler} from "../interfaces/ERC7683/IOriginSettler.sol";
import {Reward} from "../types/Intent.sol";
import {OnchainCrossChainOrder, ResolvedCrossChainOrder, GaslessCrossChainOrder, Output, FillInstruction, OrderData, ORDER_DATA_TYPEHASH} from "../types/ERC7683.sol";
import {AddressConverter} from "../libs/AddressConverter.sol";
/**
* @title Eco7683OriginSettler
* @notice Entry point to Eco Protocol via EIP-7683 with enhanced security and compliance
* @dev Provides ERC-7683 compliant interface with replay protection and proper validation
* @dev Features comprehensive validation, unified funding logic, and ERC-7683 compliance
* @dev Includes protection against replay attacks through vault state checking
*/
abstract contract OriginSettler is IOriginSettler, EIP712 {
using ECDSA for bytes32;
using SafeERC20 for IERC20;
using AddressConverter for bytes32;
/// @notice typehash for gasless crosschain order
bytes32 public GASLESS_CROSSCHAIN_ORDER_TYPEHASH =
keccak256(
"GaslessCrossChainOrder(address originSettler,address user,uint256 nonce,uint256 originChainId,uint32 openDeadline,uint32 fillDeadline,bytes32 orderDataType,bytes32 orderDataHash)"
);
/**
* @notice Initializes the Eco7683OriginSettler with EIP-712 domain
* @dev Sets up EIP-712 domain for signature verification with "EcoPortal" name and version "1"
*/
constructor() EIP712("EcoPortal", "1") {}
/**
* @notice Opens an Eco intent directly on chain via ERC-7683 interface
* @dev Called by the user to create and fund an intent atomically
* @dev Validates ORDER_DATA_TYPEHASH and decodes OrderData for intent creation
* @dev Uses unified _publishAndFund method for consistent behavior
* @dev Emits Open event with ERC-7683 compliant ResolvedCrossChainOrder
* @param order the OnchainCrossChainOrder containing embedded OrderData
*/
function open(OnchainCrossChainOrder calldata order) external payable {
if (order.orderDataType != ORDER_DATA_TYPEHASH) {
revert TypeSignatureMismatch();
}
// Decode components individually to avoid Solidity's nested struct decoding issues
OrderData memory orderData = abi.decode(order.orderData, (OrderData));
(bytes32 orderId, ) = _publishAndFund(
orderData.destination,
orderData.route,
orderData.reward,
false,
msg.sender
);
// block.timestamp is not going to overflow uint32 until 2106
emit Open(orderId, _resolve(uint32(block.timestamp), orderData));
}
/**
* @notice Opens an Eco intent on behalf of a user via ERC-7683 gasless interface
* @dev Called by a solver to create an intent for a user using their signature
* @dev Performs comprehensive validation: deadlines, signature, chain IDs, origin settler
* @dev Includes replay protection through vault state checking in _publishAndFund
* @dev Uses unified _publishAndFund method for consistent behavior and security
* @dev Emits Open event with ERC-7683 compliant ResolvedCrossChainOrder
* @param order the GaslessCrossChainOrder containing user signature and OrderData
* @param signature the user's EIP-712 signature authorizing the intent creation
*/
function openFor(
GaslessCrossChainOrder calldata order,
bytes calldata signature,
bytes calldata /* originFillerData */
) external payable {
if (block.timestamp > order.openDeadline) {
revert OpenDeadlinePassed();
}
if (order.originSettler != address(this)) {
revert InvalidOriginSettler(order.originSettler, address(this));
}
if (order.originChainId != block.chainid) {
revert InvalidOriginChainId(order.originChainId, block.chainid);
}
if (order.orderDataType != ORDER_DATA_TYPEHASH) {
revert TypeSignatureMismatch();
}
if (!_validateOrderSig(order, signature)) {
revert InvalidSignature();
}
OrderData memory orderData = abi.decode(order.orderData, (OrderData));
// No need for replay protection here
// 1) If intent is Withdrawn or Refunded, it fails
// 2) If intent is Initial, it publishes and funds
// 3) If intent is Funded, it publishes and does nothing
(bytes32 orderId, ) = _publishAndFund(
orderData.destination,
orderData.route,
orderData.reward,
false,
order.user
);
emit Open(orderId, _resolve(order.openDeadline, orderData));
}
/**
* @notice resolves an OnchainCrossChainOrder to a ResolvedCrossChainOrder
* @param order the OnchainCrossChainOrder to be resolved
*/
function resolve(
OnchainCrossChainOrder calldata order
) public view returns (ResolvedCrossChainOrder memory) {
OrderData memory orderData = abi.decode(order.orderData, (OrderData));
// block.timestamp is not going to overflow uint32 until 2106
return _resolve(uint32(block.timestamp), orderData);
}
/**
* @notice resolves GaslessCrossChainOrder to a ResolvedCrossChainOrder
* @param order the GaslessCrossChainOrder to be resolved
* param originFillerData filler data for the origin chain (not used)
*/
function resolveFor(
GaslessCrossChainOrder calldata order,
bytes calldata // originFillerData keeping it for purpose of interface
) public view returns (ResolvedCrossChainOrder memory) {
OrderData memory orderData = abi.decode(order.orderData, (OrderData));
return _resolve(order.openDeadline, orderData);
}
/**
* @notice Helper method for signature verification
* @dev Verifies that the gasless order was properly signed by the user
* @param order The gasless cross-chain order to verify
* @param signature The user's signature
* @return True if the signature is valid, false otherwise
*/
function _validateOrderSig(
GaslessCrossChainOrder calldata order,
bytes calldata signature
) internal view returns (bool) {
bytes32 structHash = keccak256(
abi.encode(
GASLESS_CROSSCHAIN_ORDER_TYPEHASH,
order.originSettler,
order.user,
order.nonce,
order.originChainId,
order.openDeadline,
order.fillDeadline,
order.orderDataType,
keccak256(order.orderData)
)
);
bytes32 hash = _hashTypedDataV4(structHash);
address signer = hash.recover(signature);
return signer == order.user;
}
/**
* @notice Resolves order data into ERC-7683 compliant ResolvedCrossChainOrder format
* @dev Converts Eco-specific OrderData into standardized format for off-chain solvers
* @dev Uses orderData.maxSpent directly instead of reconstructing from route
* @dev Correctly assigns chainIds: minReceived uses origin chain, native rewards use destination
* @dev FillInstruction.originData contains (route, rewardHash) instead of full intent
* @dev Addresses all ERC-7683 compliance issues identified in security review
* @param openDeadline The deadline for opening the order
* @param orderData The updated OrderData with maxSpent, routePortal, and routeDeadline
* @return ResolvedCrossChainOrder ERC-7683 compliant format with proper field mappings
*/
function _resolve(
uint32 openDeadline,
OrderData memory orderData
) public view returns (ResolvedCrossChainOrder memory) {
uint256 rewardTokenCount = orderData.reward.tokens.length;
Output[] memory minReceived = new Output[](
rewardTokenCount + (orderData.reward.nativeAmount > 0 ? 1 : 0)
);
for (uint256 i = 0; i < rewardTokenCount; ++i) {
minReceived[i] = Output(
bytes32(uint256(uint160(orderData.reward.tokens[i].token))), // token
orderData.reward.tokens[i].amount, // amount
bytes32(uint256(uint160(address(0)))), // recipient is zero address
block.chainid // chainId
);
}
if (orderData.reward.nativeAmount > 0) {
minReceived[rewardTokenCount] = Output(
bytes32(0), // token
orderData.reward.nativeAmount, // amount
bytes32(uint256(uint160(address(0)))), // recipient is zero address
block.chainid // chainId
);
}
bytes32 routeHash = keccak256(orderData.route);
bytes32 rewardHash = keccak256(abi.encode(orderData.reward));
bytes32 intentHash = keccak256(
abi.encodePacked(orderData.destination, routeHash, rewardHash)
);
FillInstruction[] memory fillInstructions = new FillInstruction[](1);
bytes memory originData = abi.encode(orderData.route, rewardHash);
fillInstructions[0] = FillInstruction(
orderData.destination,
orderData.routePortal,
originData
);
return
ResolvedCrossChainOrder(
orderData.reward.creator,
block.chainid,
openDeadline,
uint32(orderData.routeDeadline),
intentHash,
orderData.maxSpent,
minReceived,
fillInstructions
);
}
/// @notice EIP712 domain separator
function domainSeparatorV4() public view returns (bytes32) {
return EIP712._domainSeparatorV4();
}
/**
* @notice Core method for atomic intent creation and funding
* @dev Abstract method to be implemented by derived contracts for unified intent handling
* @dev Must handle both publishing new intents and funding existing ones atomically
* @dev Provides replay protection through vault state checking in funding logic
* @dev Should handle excess ETH return for optimal user experience
* @dev Called by both open() and openFor() methods to ensure consistent behavior
* @param destination Destination chain ID where the intent should be executed
* @param route Encoded route data containing execution instructions for destination chain
* @param reward The reward structure containing token amounts, creator, prover, and deadline
* @param allowPartial Whether to accept partial funding if full funding is not possible
* @param funder The address providing the funding (msg.sender for open(), order.user for openFor())
* @return intentHash Unique identifier of the created or existing intent
* @return vault Address of the intent's vault contract for reward escrow
*/
function _publishAndFund(
uint64 destination,
bytes memory route,
Reward memory reward,
bool allowPartial,
address funder
) internal virtual returns (bytes32 intentHash, address vault);
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import {IVault} from "../interfaces/IVault.sol";
import {IPermit} from "../interfaces/IPermit.sol";
import {Reward} from "../types/Intent.sol";
/**
* @title Vault
* @notice Escrow contract for managing cross-chain reward payments
* @dev Implements a lifecycle-based vault that can be funded, withdrawn from, or refunded
*/
contract Vault is IVault {
/// @notice Address of the portal contract that can call this vault
address private immutable portal;
using SafeERC20 for IERC20;
using Math for uint256;
/**
* @notice Creates a new vault instance
* @dev Sets the deployer (IntentSource) as the authorized portal contract
* Only the portal can call fund, withdraw, refund, and recover functions
*/
constructor() {
portal = msg.sender;
}
/**
* @notice Restricts function access to only the portal contract
* @dev Ensures only the IntentSource contract can manage vault operations
*/
modifier onlyPortal() {
if (msg.sender != portal) {
revert NotPortalCaller(msg.sender);
}
_;
}
/**
* @notice Funds the vault with tokens and native currency from the reward
* @param reward The reward structure containing token addresses, amounts, and native value
* @param funder Address that will provide the funding
* @param permit Optional permit contract for gasless token approvals
* @return fullyFunded True if the vault was fully funded, false otherwise
*/
function fundFor(
Reward calldata reward,
address funder,
IPermit permit
) external payable onlyPortal returns (bool fullyFunded) {
fullyFunded = address(this).balance >= reward.nativeAmount;
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
IERC20 token = IERC20(reward.tokens[i].token);
uint256 remaining = _fundFromPermit(
funder,
token,
reward.tokens[i].amount,
permit
);
remaining = _fundFrom(funder, token, remaining);
fullyFunded = fullyFunded && remaining == 0;
}
}
/**
* @notice Withdraws rewards from the vault to the specified claimant
* @param reward The reward structure defining what to withdraw
* @param claimant Address that will receive the withdrawn rewards
*/
function withdraw(
Reward calldata reward,
address claimant
) external onlyPortal {
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
IERC20 token = IERC20(reward.tokens[i].token);
uint256 amount = reward.tokens[i].amount.min(
token.balanceOf(address(this))
);
if (amount > 0) {
token.safeTransfer(claimant, amount);
}
}
uint256 nativeAmount = address(this).balance.min(reward.nativeAmount);
if (nativeAmount == 0) {
return;
}
(bool success, ) = claimant.call{value: nativeAmount}("");
if (!success) {
revert NativeTransferFailed(claimant, nativeAmount);
}
}
/**
* @notice Refunds all vault contents to a specified address
* @param reward The reward structure containing token information
* @param refundee Address to receive the refunded rewards
*/
function refund(Reward calldata reward, address refundee) external onlyPortal {
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
IERC20 token = IERC20(reward.tokens[i].token);
uint256 amount = token.balanceOf(address(this));
if (amount > 0) {
token.safeTransfer(refundee, amount);
}
}
uint256 nativeAmount = address(this).balance;
if (nativeAmount == 0) {
return;
}
(bool success, ) = refundee.call{value: nativeAmount}("");
if (!success) {
revert NativeTransferFailed(refundee, nativeAmount);
}
}
/**
* @notice Recovers tokens that are not part of the reward to the creator
* @param refundee Address to receive the recovered tokens
* @param token Address of the token to recover (must not be a reward token)
*/
function recover(address refundee, address token) external onlyPortal {
IERC20 tokenContract = IERC20(token);
uint256 balance = tokenContract.balanceOf(address(this));
if (balance == 0) {
revert ZeroRecoverTokenBalance(token);
}
tokenContract.safeTransfer(refundee, balance);
}
/**
* @notice Internal function to fund vault with tokens using standard ERC20 transfers
* @param funder Address providing the tokens
* @param token ERC20 token contract
* @param remainingAmount Remaining amount needed to fully fund the reward
* @return uint256 Remaining amount needed to fully fund the reward
*/
function _fundFrom(
address funder,
IERC20 token,
uint256 remainingAmount
) internal returns (uint256) {
if (remainingAmount == 0) {
return 0;
}
uint256 allowance = token.allowance(funder, address(this));
uint256 funderBalance = token.balanceOf(funder);
uint256 transferAmount = remainingAmount.min(funderBalance).min(
allowance
);
if (transferAmount > 0) {
token.safeTransferFrom(funder, address(this), transferAmount);
}
return remainingAmount - transferAmount;
}
/**
* @notice Internal function to fund vault using permit-based transfers
* @param funder Address providing the tokens
* @param token ERC20 token contract
* @param rewardAmount Required token amount for the reward
* @param permit Permit contract for gasless approvals
* @return uint256 Remaining amount needed to fully fund the reward
*/
function _fundFromPermit(
address funder,
IERC20 token,
uint256 rewardAmount,
IPermit permit
) internal returns (uint256) {
uint256 balance = token.balanceOf(address(this));
if (balance >= rewardAmount) {
return 0;
}
if (address(permit) == address(0)) {
return rewardAmount - balance;
}
(uint160 allowance, , ) = permit.allowance(
funder,
address(token),
address(this)
);
uint256 funderBalance = token.balanceOf(funder);
uint256 transferAmount = (rewardAmount - balance)
.min(funderBalance)
.min(uint256(allowance));
if (transferAmount > 0) {
permit.transferFrom(
funder,
address(this),
uint160(transferAmount),
address(token)
);
}
return rewardAmount - token.balanceOf(address(this));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Proxy} from "./Proxy.sol";
/**
* @title Clones
* @notice Library for deploying CREATE2 proxies using minimal proxy pattern
* @dev Provides deterministic proxy deployment with address prediction functionality
* Based on ERC-1167 minimal proxy standard for gas-efficient contract cloning
*/
library Clones {
/**
* @notice Thrown when proxy deployment fails
* @dev A clone instance deployment failed
*/
error ERC1167FailedCreateClone();
/**
* @notice Deploys a minimal proxy contract using CREATE2
* @dev Creates a new proxy instance that delegates all calls to the implementation
* @param implementation Address of the implementation contract to proxy to
* @param salt Unique salt for deterministic address generation
* @return instance Address of the deployed proxy contract
*/
function clone(
address implementation,
bytes32 salt
) internal returns (address instance) {
instance = address(new Proxy{salt: salt}(implementation));
}
/**
* @notice Predicts the address of a proxy before deployment
* @dev Calculates deterministic CREATE2 address using implementation, salt, and prefix
* Supports different chain prefixes (standard 0xff, TRON 0x41, etc.)
* @param implementation Address of the implementation contract
* @param salt Salt used for address generation
* @param prefix CREATE2 prefix byte (0xff for standard chains, 0x41 for TRON)
* @return predicted The deterministic address where the proxy will be deployed
*/
function predict(
address implementation,
bytes32 salt,
bytes1 prefix
) internal view returns (address predicted) {
/* Convert a hash which is bytes32 to an address which is 20-byte long
according to https://docs.soliditylang.org/en/v0.8.9/control-structures.html?highlight=create2#salted-contract-creations-create2 */
predicted = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
prefix,
address(this),
salt,
keccak256(
abi.encodePacked(
type(Proxy).creationCode,
abi.encode(implementation)
)
)
)
)
)
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Route} from "../types/Intent.sol";
/**
* @title IInbox
* @notice Interface for the destination chain portion of the Eco Protocol's intent system
* @dev Handles intent fulfillment and proving via different mechanisms (storage proofs,
* Hyperlane instant/batched)
*/
interface IInbox {
/**
* @notice Emitted when an intent is successfully fulfilled
* @param intentHash Hash of the fulfilled intent
* @param claimant Cross-VM compatible claimant identifier
*/
event IntentFulfilled(bytes32 indexed intentHash, bytes32 indexed claimant);
/**
* @notice Emitted when an intent is proven
* @dev Note that this event is emitted by both the Portal on the destination chain,
* and the Prover on the source chain.
* @param intentHash Hash of the proven intent
* @param claimant Cross-VM compatible claimant identifier
*/
event IntentProven(bytes32 indexed intentHash, bytes32 indexed claimant);
/**
* @notice Intent has already been fulfilled
* @param intentHash Hash of the fulfilled intent
*/
error IntentAlreadyFulfilled(bytes32 intentHash);
/**
* @notice Invalid portal address provided
* @param portal Address that is not a valid portal
*/
error InvalidPortal(address portal);
/**
* @notice Intent has expired and can no longer be fulfilled
*/
error IntentExpired();
/**
* @notice Generated hash doesn't match expected hash
* @param expectedHash Hash that was expected
*/
error InvalidHash(bytes32 expectedHash);
/**
* @notice Zero claimant identifier provided
*/
error ZeroClaimant();
/**
* @notice Attempted to batch an unfulfilled intent
* @param intentHash Hash of the unfulfilled intent
*/
error IntentNotFulfilled(bytes32 intentHash);
/**
* @notice Chain ID is too large to fit in uint64
* @param chainId The chain ID that is too large
*/
error ChainIdTooLarge(uint256 chainId);
/**
* @notice Sent native amount is insufficient for route execution
* @param sent Amount of native tokens sent with the transaction
* @param required Minimum amount of native tokens required by the route
*/
error InsufficientNativeAmount(uint256 sent, uint256 required);
/**
* @notice Fulfills an intent using storage proofs
* @dev Validates intent hash, executes calls, and marks as fulfilled
* @param intentHash The hash of the intent to fulfill
* @param route Route information for the intent
* @param rewardHash Hash of the reward details
* @param claimant Cross-VM compatible claimant identifier
* @return Array of execution results
*/
function fulfill(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant
) external payable returns (bytes[] memory);
/**
* @notice Fulfills an intent and initiates proving in one transaction
* @dev Validates intent hash, executes calls, and marks as fulfilled
* @param intentHash The hash of the intent to fulfill
* @param route Route information for the intent
* @param rewardHash Hash of the reward details
* @param claimant Cross-VM compatible claimant identifier
* @param prover Address of prover on the destination chain
* @param sourceChainDomainID Domain ID of the source chain where the intent was created
* @param data Additional data for message formatting
* @return Array of execution results
*
* @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
* Each bridge provider uses their own domain ID mapping system:
* - Hyperlane: Uses custom domain IDs that may differ from chain IDs
* - LayerZero: Uses endpoint IDs that map to chains differently
* - Metalayer: Uses domain IDs specific to their routing system
* You MUST consult the specific bridge provider's documentation to determine
* the correct domain ID for the source chain.
*/
function fulfillAndProve(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant,
address prover,
uint64 sourceChainDomainID,
bytes memory data
) external payable returns (bytes[] memory);
/**
* @notice Initiates proving process for fulfilled intents
* @dev Sends message to source chain to verify intent execution
* @param prover Address of prover on the destination chain
* @param sourceChainDomainID Domain ID of the source chain
* @param intentHashes Array of intent hashes to prove
* @param data Additional data for message formatting
*
* @dev WARNING: sourceChainDomainID is NOT necessarily the same as chain ID.
* Each bridge provider uses their own domain ID mapping system:
* - Hyperlane: Uses custom domain IDs that may differ from chain IDs
* - LayerZero: Uses endpoint IDs that map to chains differently
* - Metalayer: Uses domain IDs specific to their routing system
* You MUST consult the specific bridge provider's documentation to determine
* the correct domain ID for the source chain.
*/
function prove(
address prover,
uint64 sourceChainDomainID,
bytes32[] memory intentHashes,
bytes memory data
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Call} from "../types/Intent.sol";
/**
* @title IExecutor
* @notice Interface for secure batch execution of intent calls
* @dev Provides controlled execution with built-in safety checks and authorization
* - Restricts execution to authorized portal contracts only
* - Prevents calls to EOAs with calldata
* - Supports batch execution for multiple calls in a single transaction
*/
interface IExecutor {
/**
* @notice Thrown when caller is not the portal to execute calls
* @param caller The unauthorized address that attempted the call
*/
error NonPortalCaller(address caller);
/**
* @notice Attempted call to an EOA
* @param target EOA address to which call was attempted
*/
error CallToEOA(address target);
/**
* @notice Call to a contract failed
* @param call The call that failed
* @param reason The reason for the failure
*/
error CallFailed(Call call, bytes reason);
/**
* @notice Executes multiple intent calls with safety checks
* @dev Validates each target address and executes calls if safe
* - Prevents calls to EOAs that include calldata
* - Reverts if any target call fails
* @param calls Array of call data containing target, value, and calldata
* @return Array of return data from the executed calls
*/
function execute(
Call[] calldata calls
) external payable returns (bytes[] memory);
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {IDestinationSettler} from "../interfaces/ERC7683/IDestinationSettler.sol";
import {Route} from "../types/Intent.sol";
/**
* @title DestinationSettler
* @notice Abstract contract implementing ERC-7683 destination chain settlement for Eco Protocol
* @dev Handles intent fulfillment on destination chains through the ERC-7683 standard interface
*/
abstract contract DestinationSettler is IDestinationSettler {
/**
* @notice Fills a single leg of a particular order on the destination chain
* @dev originData is of type OnchainCrossChainOrder
* @dev fillerData is encoded bytes consisting of the claimant address and any additional data required for the chosen prover
* @param orderId Unique identifier for the order being filled
* @param originData Data emitted on the origin chain to parameterize the fill, equivalent to the originData field from the fillInstruction of the ResolvedCrossChainOrder. An encoded Intent struct.
* @param fillerData Data provided by the filler to inform the fill or express their preferences
*/
function fill(
bytes32 orderId,
bytes calldata originData,
bytes calldata fillerData
) external payable {
(bytes memory encodedRoute, bytes32 rewardHash) = abi.decode(
originData,
(bytes, bytes32)
);
emit OrderFilled(orderId, msg.sender);
(
address prover,
uint64 source,
bytes32 claimant,
bytes memory proverData
) = abi.decode(fillerData, (address, uint64, bytes32, bytes));
fulfillAndProve(
orderId,
abi.decode(encodedRoute, (Route)),
rewardHash,
claimant,
prover,
source,
proverData
);
}
/**
* @notice Fulfills an intent and initiates proving in one transaction
* @dev Abstract function to be implemented by concrete settlement contracts
* @param intentHash The hash of the intent to fulfill
* @param route The route information for the intent
* @param rewardHash The hash of the reward details
* @param claimant Cross-VM compatible claimant identifier
* @param prover Address of prover on the destination chain
* @param source The source chain ID where the intent was created
* @param data Additional data for message formatting
* @return Array of execution results from intent calls
*/
function fulfillAndProve(
bytes32 intentHash,
Route memory route,
bytes32 rewardHash,
bytes32 claimant,
address prover,
uint64 source,
bytes memory data
) public payable virtual returns (bytes[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {IExecutor} from "./interfaces/IExecutor.sol";
import {Call} from "./types/Intent.sol";
/**
* @title Executor
* @notice Contract for secure batch execution of intent calls
* @dev Implements IExecutor with comprehensive safety checks and authorization controls
* - Only the portal contract can execute calls (onlyPortal modifier)
* - Prevents malicious calls through EOA validation
* - Supports batch execution for multiple calls in a single transaction
*/
contract Executor is IExecutor {
/**
* @notice Address of the portal contract authorized to call execute
*/
address private immutable portal;
/**
* @notice Initializes the Executor contract
* @dev Sets the deploying address (portal) as the only authorized caller
*/
constructor() {
portal = msg.sender;
}
/**
* @notice Restricts function access to the portal contract only
* @dev Reverts with NonPortalCaller error if caller is not the portal
*/
modifier onlyPortal() {
if (msg.sender != portal) {
revert NonPortalCaller(msg.sender);
}
_;
}
/**
* @notice Executes multiple intent calls with comprehensive safety checks
* @dev Performs validation and execution for each call in the batch:
* 1. Prevents calls to EOAs that include calldata (potential phishing protection)
* 2. Executes each call and returns results or reverts on any failure
* @param calls Array of call data containing target addresses, values, and calldata
* @return Array of return data from the successfully executed calls
*/
function execute(
Call[] calldata calls
) external payable override onlyPortal returns (bytes[] memory) {
uint256 callsLength = calls.length;
bytes[] memory results = new bytes[](callsLength);
for (uint256 i = 0; i < callsLength; i++) {
results[i] = execute(calls[i]);
}
return results;
}
function execute(Call calldata call) internal returns (bytes memory) {
if (_isCallToEoa(call)) {
revert CallToEOA(call.target);
}
(bool success, bytes memory result) = call.target.call{
value: call.value
}(call.data);
if (!success) {
revert CallFailed(call, result);
}
return result;
}
/**
* @notice Checks if a call is targeting an EOA with calldata
* @dev Returns true if target has no code but calldata is provided
* This prevents potential phishing attacks where calldata might be misinterpreted
* @param call The call to validate
* @return bool True if this is a potentially unsafe call to an EOA
*/
function _isCallToEoa(Call calldata call) internal view returns (bool) {
return call.target.code.length == 0 && call.data.length > 0;
}
/**
* @notice Allows the contract to receive ETH
* @dev Required for handling ETH transfer for intent execution
*/
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError, bytes32) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.20;
import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
* encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
* does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
* produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {IERC-5267}.
*/
function eip712Domain()
public
view
virtual
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: By default this function reads _name which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Name() internal view returns (string memory) {
return _name.toStringWithFallback(_nameFallback);
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: By default this function reads _version which is an immutable value.
* It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
*/
// solhint-disable-next-line func-name-mixedcase
function _EIP712Version() internal view returns (string memory) {
return _version.toStringWithFallback(_versionFallback);
}
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "../../types/ERC7683.sol";
/**
* @title IOriginSettler
* @notice Standard interface for settlement contracts on the origin chain
* @dev Updated interface supporting enhanced validation, replay protection, and ERC-7683 compliance
*/
interface IOriginSettler {
/// @notice Thrown when the sent native token amount is less than the required reward amount
error InsufficientNativeRewardAmount();
/// @notice Thrown when data type signature does not match the expected value
error TypeSignatureMismatch();
/// @notice Thrown when the origin chain ID in the order does not match the current chain
error InvalidOriginChainId(uint256 expected, uint256 actual);
/// @notice Thrown when attempting to open an order after the open deadline has passed
error OpenDeadlinePassed();
/// @notice Thrown when the provided signature is invalid or does not match the order
error InvalidSignature();
/// @notice Thrown when the origin settler address in the order does not match this contract
error InvalidOriginSettler(address expected, address actual);
/**
* @notice Signals that an order has been opened
* @param orderId a unique order identifier within this settlement system
* @param resolvedOrder resolved order that would be returned by resolve if called instead of Open
*/
event Open(bytes32 indexed orderId, ResolvedCrossChainOrder resolvedOrder);
/**
* @notice Opens a cross-chain order directly by the user
* @dev Called by the user to create and fund an intent
* @dev Validates order data type and handles intent funding
* @dev Emits Open event with resolved order data
* @dev Made payable to support native token rewards
* @param order The OnchainCrossChainOrder definition with embedded OrderData
*/
function open(OnchainCrossChainOrder calldata order) external payable;
/**
* @notice Opens a gasless cross-chain order on behalf of a user
* @dev Called by a solver to create an intent for a user via signature
* @dev Validates signature, deadlines, chain IDs, and origin settler address
* @dev Includes replay protection through vault state checking
* @dev Emits Open event with resolved order data
* @dev Made payable to support native token rewards
* @param order The GaslessCrossChainOrder definition with user signature
* @param signature The user's EIP-712 signature authorizing the order
* @param originFillerData Any filler-defined data (currently unused)
*/
function openFor(
GaslessCrossChainOrder calldata order,
bytes calldata signature,
bytes calldata originFillerData
) external payable;
/**
* @notice Resolves a gasless order into ERC-7683 compliant ResolvedCrossChainOrder
* @dev Converts OrderData to standardized format for off-chain solvers
* @dev Uses orderData.maxSpent directly and corrects chainId assignments
* @dev FillInstruction.originData contains (route, rewardHash) not full intent
* @param order The GaslessCrossChainOrder definition with embedded OrderData
* @param originFillerData Any filler-defined data (currently unused)
* @return ResolvedCrossChainOrder ERC-7683 compliant order with proper field mappings
*/
function resolveFor(
GaslessCrossChainOrder calldata order,
bytes calldata originFillerData
) external view returns (ResolvedCrossChainOrder memory);
/**
* @notice Resolves an onchain order into ERC-7683 compliant ResolvedCrossChainOrder
* @dev Converts OrderData to standardized format for off-chain solvers
* @dev Uses orderData.maxSpent directly and corrects chainId assignments
* @dev FillInstruction.originData contains (route, rewardHash) not full intent
* @param order The OnchainCrossChainOrder definition with embedded OrderData
* @return ResolvedCrossChainOrder ERC-7683 compliant order with proper field mappings
*/
function resolve(
OnchainCrossChainOrder calldata order
) external view returns (ResolvedCrossChainOrder memory);
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Reward} from "./Intent.sol";
/**
* @title GaslessCrossChainOrder CrossChainOrder type
* @notice Standard order struct to be signed by users, disseminated to fillers, and submitted to origin settler contracts
* @param originSettler The contract address that the order is meant to be settled by
* Fillers send this order to this contract address on the origin chain
* @param user The address of the user who is initiating the swap whose input tokens will be taken and escrowed
* @param nonce Nonce to be used as replay protection for the order
* @param originChainId The chainId of the origin chain
* @param openDeadline The timestamp by which the order must be opened
* @param fillDeadline The timestamp by which the order must be filled on the destination chain
* @param orderDataType Type identifier for the order data. This is an EIP-712 typehash
* @param orderData Arbitrary implementation-specific data
* Can be used to define tokens, amounts, destination chains, fees, settlement parameters,
* or any other order-type specific information
*/
struct GaslessCrossChainOrder {
address originSettler;
address user;
uint256 nonce;
uint256 originChainId;
uint32 openDeadline;
uint32 fillDeadline;
bytes32 orderDataType;
bytes orderData;
}
/**
* @title OnchainCrossChainOrder CrossChainOrder type
* @notice Standard order struct for user-opened orders, where the user is the msg.sender.
* @param fillDeadline The timestamp by which the order must be filled on the destination chain
* @param orderDataType Type identifier for the order data. This is an EIP-712 typehash
* @param orderData Arbitrary implementation-specific data
* Can be used to define tokens, amounts, destination chains, fees, settlement parameters,
* or any other order-type specific information
*/
struct OnchainCrossChainOrder {
uint32 fillDeadline;
bytes32 orderDataType;
bytes orderData;
}
/**
* @title ResolvedCrossChainOrder type
* @notice An implementation-generic representation of an order intended for filler consumption
* @dev Defines all requirements for filling an order by unbundling the implementation-specific orderData.
* @dev Intended to improve integration generalization by allowing fillers to compute the exact input and output information of any order
* @param user The address of the user who is initiating the transfer
* @param originChainId The chainId of the origin chain
* @param openDeadline The timestamp by which the order must be opened
* @param fillDeadline The timestamp by which the order must be filled on the destination chain(s)
* @param orderId The unique identifier for this order within this settlement system
* @param maxSpent The max outputs that the filler will send. It's possible the actual amount depends on the state of the destination
* chain (destination dutch auction, for instance), so these outputs should be considered a cap on filler liabilities.
* @param minReceived The minimum outputs that must be given to the filler as part of order settlement. Similar to maxSpent, it's possible
* that special order types may not be able to guarantee the exact amount at open time, so this should be considered
* a floor on filler receipts. Setting the `recipient` of an `Output` to address(0) indicates that the filler is not
* known when creating this order.
* @param fillInstructions Each instruction in this array is parameterizes a single leg of the fill. This provides the filler with the information
* necessary to perform the fill on the destination(s).
*/
struct ResolvedCrossChainOrder {
address user;
uint256 originChainId;
uint32 openDeadline;
uint32 fillDeadline;
bytes32 orderId;
Output[] maxSpent;
Output[] minReceived;
FillInstruction[] fillInstructions;
}
/**
* @title Output type
* @notice Tokens that must be received for a valid order fulfillment
* @param token The address of the ERC20 token on the destination chain
* address(0) used as a sentinel for the native token
* @param amount The amount of the token to be sent
* @param recipient The address to receive the output tokens
* @param chainId The destination chain for this output
*/
struct Output {
bytes32 token;
uint256 amount;
bytes32 recipient;
uint256 chainId;
}
/**
* @title FillInstruction type
* @notice Instructions to parameterize each leg of the fill
* @dev Provides all the origin-generated information required to produce a valid fill leg
* @param destinationChainId The chain ID that the order is meant to be settled by
* @param destinationSettler The contract address that the order is meant to be filled on
* @param originData The data generated on the origin chain needed by the destinationSettler to process the fill
*/
struct FillInstruction {
uint256 destinationChainId;
bytes32 destinationSettler;
bytes originData;
}
/**
* @notice contains everything which, when combined with other aspects of GaslessCrossChainOrder
* is sufficient to publish an intent via Eco Protocol
* @dev the orderData field of GaslessCrossChainOrder should be decoded as OrderData
* @param destination the destination chain ID for the intent
* @param route the route data for execution on the destination chain
* @param reward the reward structure containing creator, prover, amounts, and deadline information
* @param routePortal the portal contract address on the destination chain
* @param routeDeadline the deadline for route execution on the destination chain
* @param maxSpent the maximum outputs that the filler will send
*/
struct OrderData {
uint64 destination;
bytes route;
Reward reward;
bytes32 routePortal;
uint64 routeDeadline;
Output[] maxSpent;
}
// EIP712 type hash
bytes32 constant ORDER_DATA_TYPEHASH = keccak256(
"OrderData(uint64 destination,bytes route,Reward reward,bytes32 routePortal,uint64 routeDeadline,Output[] maxSpent)Reward(uint64 deadline,address creator,address prover,uint256 nativeAmount,TokenAmount[] tokens)TokenAmount(address token,uint256 amount)Output(bytes32 token,uint256 amount,bytes32 recipient,uint256 chainId)"
);/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title Proxy
* @notice Minimal proxy contract that forwards all calls to an implementation contract
* @dev Uses delegatecall to preserve caller context while executing implementation logic
* Implementation address is immutable and set during construction
* Supports both function calls (via fallback) and native token transfers (via receive)
*/
contract Proxy {
/// @dev Implementation contract address (private for gas optimization)
address private immutable implementation;
/**
* @notice Creates a new proxy pointing to the specified implementation
* @param _implementation Address of the contract to delegate calls to
*/
constructor(address _implementation) {
implementation = _implementation;
}
/**
* @notice Forwards all function calls to the implementation contract
* @dev Uses delegatecall to preserve msg.sender and msg.value context
* Reverts if the delegatecall fails, preserving the original revert reason
*/
fallback() external payable {
address _implementation = implementation;
assembly {
// Copy msg.data to memory
calldatacopy(0, 0, calldatasize())
// Delegatecall into the implementation
let result := delegatecall(
gas(),
_implementation,
0,
calldatasize(),
0,
0
)
// Copy the returned data
returndatacopy(0, 0, returndatasize())
// Return or revert based on result
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @notice Accepts native token transfers to the proxy
* @dev Required for the proxy to receive ETH transfers
*/
receive() external payable {}
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title IDestinationSettler
* @notice Standard interface for settlement contracts on the destination chain
*/
interface IDestinationSettler {
/**
* @notice Emitted when an intent is fulfilled
* @param orderId Hash of the fulfilled intent
* @param solver Address that fulfilled the intent
*/
event OrderFilled(bytes32 orderId, address solver);
/**
* @notice Fills a single leg of a particular order on the destination chain
* @dev This method has been made payable, in contrast to original interface
* @param orderId Unique order identifier for this order
* @param originData Data emitted on the origin to parameterize the fill
* @param fillerData Data provided by the filler to inform the fill or express their preferences
*/
function fill(
bytes32 orderId,
bytes calldata originData,
bytes calldata fillerData
) external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an EIP-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using
* {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.20;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"@hyperlane-xyz/core/=node_modules/@hyperlane-xyz/core/",
"@eth-optimism/contracts-bedrock/=node_modules/@eth-optimism/contracts-bedrock/",
"@metalayer/contracts/=node_modules/@metalayer/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainIdTooLarge","type":"error"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"InsufficientFunds","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InsufficientNativeAmount","type":"error"},{"inputs":[],"name":"InsufficientNativeRewardAmount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentAlreadyExists","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentAlreadyFulfilled","type":"error"},{"inputs":[],"name":"IntentExpired","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentNotClaimed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentNotFulfilled","type":"error"},{"inputs":[],"name":"InvalidClaimant","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expectedHash","type":"bytes32"}],"name":"InvalidHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"InvalidOriginChainId","type":"error"},{"inputs":[{"internalType":"address","name":"expected","type":"address"},{"internalType":"address","name":"actual","type":"address"}],"name":"InvalidOriginSettler","type":"error"},{"inputs":[{"internalType":"address","name":"portal","type":"address"}],"name":"InvalidPortal","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"InvalidRecoverToken","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"enum IIntentSource.Status","name":"status","type":"uint8"}],"name":"InvalidStatusForFunding","type":"error"},{"inputs":[{"internalType":"enum IIntentSource.Status","name":"status","type":"uint8"},{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"InvalidStatusForRefund","type":"error"},{"inputs":[{"internalType":"enum IIntentSource.Status","name":"status","type":"uint8"}],"name":"InvalidStatusForWithdrawal","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotCreatorCaller","type":"error"},{"inputs":[],"name":"OpenDeadlinePassed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"TypeSignatureMismatch","type":"error"},{"inputs":[],"name":"ZeroClaimant","type":"error"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"claimant","type":"bytes32"}],"name":"IntentFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"funder","type":"address"},{"indexed":false,"internalType":"bool","name":"complete","type":"bool"}],"name":"IntentFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"claimant","type":"bytes32"}],"name":"IntentProven","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"destination","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"route","type":"bytes"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"uint64","name":"rewardDeadline","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"rewardNativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct TokenAmount[]","name":"rewardTokens","type":"tuple[]"}],"name":"IntentPublished","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"refundee","type":"address"}],"name":"IntentRefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"refundee","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"IntentTokenRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"claimant","type":"address"}],"name":"IntentWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"maxSpent","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"minReceived","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bytes32","name":"destinationSettler","type":"bytes32"},{"internalType":"bytes","name":"originData","type":"bytes"}],"internalType":"struct FillInstruction[]","name":"fillInstructions","type":"tuple[]"}],"indexed":false,"internalType":"struct ResolvedCrossChainOrder","name":"resolvedOrder","type":"tuple"}],"name":"Open","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"solver","type":"address"}],"name":"OrderFilled","type":"event"},{"inputs":[],"name":"GASLESS_CROSSCHAIN_ORDER_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"bytes32","name":"routePortal","type":"bytes32"},{"internalType":"uint64","name":"routeDeadline","type":"uint64"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"maxSpent","type":"tuple[]"}],"internalType":"struct OrderData","name":"orderData","type":"tuple"}],"name":"_resolve","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"maxSpent","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"minReceived","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bytes32","name":"destinationSettler","type":"bytes32"},{"internalType":"bytes","name":"originData","type":"bytes"}],"internalType":"struct FillInstruction[]","name":"fillInstructions","type":"tuple[]"}],"internalType":"struct ResolvedCrossChainOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"destinations","type":"uint64[]"},{"internalType":"bytes32[]","name":"routeHashes","type":"bytes32[]"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward[]","name":"rewards","type":"tuple[]"}],"name":"batchWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"claimants","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"contract IExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"internalType":"bytes","name":"originData","type":"bytes"},{"internalType":"bytes","name":"fillerData","type":"bytes"}],"name":"fill","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"internalType":"bytes32","name":"rewardHash","type":"bytes32"},{"internalType":"bytes32","name":"claimant","type":"bytes32"}],"name":"fulfill","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"internalType":"bytes32","name":"rewardHash","type":"bytes32"},{"internalType":"bytes32","name":"claimant","type":"bytes32"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint64","name":"sourceChainDomainID","type":"uint64"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"fulfillAndProve","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"}],"name":"fund","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"},{"internalType":"address","name":"funder","type":"address"},{"internalType":"address","name":"permitContract","type":"address"}],"name":"fundFor","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"_routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"getIntentHash","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"internalType":"bytes32","name":"rewardHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"getIntentHash","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"internalType":"bytes32","name":"rewardHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"}],"name":"getIntentHash","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"internalType":"bytes32","name":"rewardHash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"getRewardStatus","outputs":[{"internalType":"enum IIntentSource.Status","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"intentVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"}],"name":"intentVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"isIntentFunded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"}],"name":"isIntentFunded","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderDataType","type":"bytes32"},{"internalType":"bytes","name":"orderData","type":"bytes"}],"internalType":"struct OnchainCrossChainOrder","name":"order","type":"tuple"}],"name":"open","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"originSettler","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderDataType","type":"bytes32"},{"internalType":"bytes","name":"orderData","type":"bytes"}],"internalType":"struct GaslessCrossChainOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"openFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint64","name":"sourceChainDomainID","type":"uint64"},{"internalType":"bytes32[]","name":"intentHashes","type":"bytes32[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"prove","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"}],"name":"publish","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"publish","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"}],"name":"publishAndFund","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"}],"name":"publishAndFund","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes","name":"route","type":"bytes"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"},{"internalType":"address","name":"funder","type":"address"},{"internalType":"address","name":"permitContract","type":"address"}],"name":"publishAndFundFor","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destination","type":"uint64"},{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"portal","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Call[]","name":"calls","type":"tuple[]"}],"internalType":"struct Route","name":"route","type":"tuple"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"internalType":"struct Intent","name":"intent","type":"tuple"},{"internalType":"bool","name":"allowPartial","type":"bool"},{"internalType":"address","name":"funder","type":"address"},{"internalType":"address","name":"permitContract","type":"address"}],"name":"publishAndFundFor","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"address","name":"token","type":"address"}],"name":"recoverToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"refund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"},{"internalType":"address","name":"refundee","type":"address"}],"name":"refundTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderDataType","type":"bytes32"},{"internalType":"bytes","name":"orderData","type":"bytes"}],"internalType":"struct OnchainCrossChainOrder","name":"order","type":"tuple"}],"name":"resolve","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"maxSpent","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"minReceived","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bytes32","name":"destinationSettler","type":"bytes32"},{"internalType":"bytes","name":"originData","type":"bytes"}],"internalType":"struct FillInstruction[]","name":"fillInstructions","type":"tuple[]"}],"internalType":"struct ResolvedCrossChainOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"originSettler","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderDataType","type":"bytes32"},{"internalType":"bytes","name":"orderData","type":"bytes"}],"internalType":"struct GaslessCrossChainOrder","name":"order","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"resolveFor","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"uint32","name":"openDeadline","type":"uint32"},{"internalType":"uint32","name":"fillDeadline","type":"uint32"},{"internalType":"bytes32","name":"orderId","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"maxSpent","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"token","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct Output[]","name":"minReceived","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"bytes32","name":"destinationSettler","type":"bytes32"},{"internalType":"bytes","name":"originData","type":"bytes"}],"internalType":"struct FillInstruction[]","name":"fillInstructions","type":"tuple[]"}],"internalType":"struct ResolvedCrossChainOrder","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"destination","type":"uint64"},{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"uint64","name":"deadline","type":"uint64"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct TokenAmount[]","name":"tokens","type":"tuple[]"}],"internalType":"struct Reward","name":"reward","type":"tuple"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610220604052346102c1576040516100186040826102c6565b600981526020810190681158dbd41bdc9d185b60ba1b82526040519161003f6040846102c6565b600183526020830191603160f81b8352610058816102e9565b61012052610065846104ab565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100ce60c0826102c6565b5190206080523060c0527f0dc54db9269648aac2dbf0a24ec877f6604de7a39d70a932e517955973048850600255632b6653dc610180526394a9059e6101a052632b6653dc461480156102b4575b1561028e57604160f81b5b6101605260405161109e8082016001600160401b038111838210176102785782916164e4833903906000f0801561026c576001600160a01b03166101c0526040516106918082016001600160401b03811183821017610278578291615e53833903906000f0801561026c576001600160a01b03166101e0526001600160401b03461161025757466001600160401b031661020052604051615809908161064a8239608051816147b4015260a05181614871015260c05181614785015260e051816148030152610100518161482901526101205181611bb001526101405181611bd901526101605181613bdb0152610180518150506101a0518150506101c051818181613b6b0152613e1301526101e051818181611ed7015261428f015261020051818181612aaa01526141960152f35b631063f20160e11b6000524660045260246000fd5b6040513d6000823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b7fff00000000000000000000000000000000000000000000000000000000000000610127565b506394a9059e461461011c565b600080fd5b601f909101601f19168101906001600160401b0382119082101761027857604052565b90815160208110600014610381575090601f815111610325576020815191015160208210610315571790565b6000198260200360031b1b161790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106103695750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001610347565b6001600160401b03811161027857600054600181811c911680156104a1575b602082101461048b57601f8111610456575b50602092601f82116001146103f257928192936000926103e7575b50508160011b916000199060031b1c19161760005560ff90565b0151905038806103cd565b601f1982169360008052806000209160005b86811061043e5750836001959610610425575b505050811b0160005560ff90565b015160001960f88460031b161c19169055388080610417565b91926020600181928685015181550194019201610404565b60008052601f6020600020910160051c810190601f830160051c015b81811061047f57506103b2565b60008155600101610472565b634e487b7160e01b600052602260045260246000fd5b90607f16906103a0565b90815160208110600014610533575090601f8151116104d7576020815191015160208210610315571790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b83811061051b5750508160006044809484010152601f80199101168101030190fd5b602082820181015160448784010152859350016104f9565b6001600160401b03811161027857600154600181811c9116801561063f575b602082101461048b57601f8111610609575b50602092601f82116001146105a45792819293600092610599575b50508160011b916000199060031b1c19161760015560ff90565b01519050388061057f565b601f198216936001600052806000209160005b8681106105f157508360019596106105d8575b505050811b0160015560ff90565b015160001960f88460031b161c191690553880806105ca565b919260206001819286850151815501940192016105b7565b6001600052601f6020600020910160051c810190601f830160051c015b8181106106335750610564565b60008155600101610626565b90607f169061055256fe6080604052600436101561001257600080fd5b60003560e01c80630742ebe4146102575780630d0eeb7a146102525780630e74db051461024d5780630fa76b79146102485780631034b866146102435780631299d6171461023e57806317d4e8071461023957806322bcd51a14610234578063308adade1461022f57806341b477dd1461022a57806352a8339e1461022557806354fd4d501461022057806355a0bec01461021b578063572ac041146102165780636063cd5b1461021157806360d1c29c1461020c578063645c890c1461020757806364cf9bb61461020257806378e890ba146101fd5780637af10029146101f857806382e2c43f146101f3578063844fac8e146101ee57806384b0196e146101e95780638ba5e373146101e45780639f24b4dd146101df578063b2e55f30146101da578063b6681e39146101d5578063c34c08e5146101d0578063df00f8fa146101cb578063e353b5e6146101c6578063e917a962146101c1578063ed60f2a3146101bc578063ee64c551146101b7578063f16f5138146101b2578063f987b9bc146101ad5763fcb8f14e146101a857600080fd5b61236b565b61235a565b6122b5565b61224d565b6120bc565b61200b565b611f89565b611efb565b611e8c565b611de4565b611dbf565b611d14565b611cd2565b611b79565b6118da565b611762565b61162d565b6115bb565b6114d3565b6114c2565b6113d2565b6113af565b6112b2565b61120b565b611184565b611103565b610ed0565b610e91565b610d7f565b610a26565b6109d0565b6108e7565b61086d565b6107e5565b610560565b610499565b67ffffffffffffffff81160361026e57565b600080fd5b359061027e8261025c565b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176102cb57604052565b610280565b6060810190811067ffffffffffffffff8211176102cb57604052565b6080810190811067ffffffffffffffff8211176102cb57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176102cb57604052565b6040519061027e60c083610308565b6040519061027e608083610308565b6040519061027e606083610308565b6040519061027e61010083610308565b67ffffffffffffffff81116102cb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926103cc82610386565b916103da6040519384610308565b82948184528183011161026e578281602093846000960137010152565b9080601f8301121561026e57816020610412933591016103c0565b90565b908160a091031261026e5790565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e576004356104598161025c565b9160243567ffffffffffffffff811161026e5782610479916004016103f7565b916044359067ffffffffffffffff821161026e5761041291600401610415565b3461026e5760206104b26104ac36610423565b916123a7565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff81160361026e57565b359061027e826104d0565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e5760043561052f8161025c565b91602435916044359067ffffffffffffffff821161026e5761055391600401610415565b90606435610412816104d0565b3461026e57610585610571366104f9565b9290939161057f3686610755565b916124bb565b5050916105928282613cde565b60206105bc6105a36105a386613dbf565b73ffffffffffffffffffffffffffffffffffffffff1690565b91016105c7816123cf565b91803b1561026e576040517f648bf77400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015292841660248401526000908390604490829084905af19182156106af5761067773ffffffffffffffffffffffffffffffffffffffff9283927f21ea3a531675a90b5b0263d6dc9be64e34e0bfd422a8b428b2d0729c5d4446e495610694575b506123cf565b169261068f6040519283921695829190602083019252565b0390a3005b806106a360006106a993610308565b80611179565b38610671565b6123d9565b67ffffffffffffffff81116102cb5760051b60200190565b81601f8201121561026e578035906106e3826106b4565b926106f16040519485610308565b82845260208085019360061b8301019181831161026e57602001925b82841061071b575050505090565b60408483031261026e5760206040918251610735816102af565b8635610740816104d0565b8152828701358382015281520193019261070d565b919060a08382031261026e576040519060a0820182811067ffffffffffffffff8211176102cb576040528193803561078c8161025c565b8352602081013561079c816104d0565b602084015260408101356107af816104d0565b60408401526060810135606084015260808101359167ffffffffffffffff831161026e576080926107e092016106cc565b910152565b3461026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356108208161025c565b602435906044359067ffffffffffffffff821161026e576108699261057f61084c933690600401610755565b604080519384526020840192909252908201529081906060820190565b0390f35b3461026e57602061088661088036610423565b91612557565b6040519015158152f35b9081606091031261026e5790565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e576004359067ffffffffffffffff821161026e5761041291600401610890565b3461026e5761096f6108f83661089e565b61092961096982359261090a8461025c565b61095561091a60208301836125b1565b604051948591602083016127fe565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101855284610308565b61096436916040810190612902565b610755565b91612d02565b6040805192835273ffffffffffffffffffffffffffffffffffffffff91909116602083015290f35b600411156109a157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356000526003602052602060ff6040600020541660405190610a2281610997565b8152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435610a5c816104d0565b60243590610a698261025c565b60443567ffffffffffffffff811161026e573660238201121561026e57806004013590610a95826106b4565b91610aa36040519384610308565b8083526024602084019160051b8301019136831161026e57602401905b828210610af6575050506064359267ffffffffffffffff841161026e57610aee610af49436906004016103f7565b92612a89565b005b8135815260209182019101610ac0565b908161010091031261026e5790565b9181601f8401121561026e5782359167ffffffffffffffff831161026e576020838186019501011161026e57565b906020808351928381520192019060005b818110610b615750505090565b909192602060806001926060875180518352848101518584015260408101516040840152015160608201520194019101919091610b54565b60005b838110610bac5750506000910152565b8181015183820152602001610b9c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610bf881518092818752878088019101610b99565b0116010190565b9080602083519182815201916020808360051b8301019401926000915b838310610c2b57505050505090565b9091929394602080610c82837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660019603018752606060408b518051845285810151868501520151918160408201520190610bbc565b97019301930191939290610c1c565b906104129160208152610cbd60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60208201516040820152610cde6040830151606083019063ffffffff169052565b606082015163ffffffff166080820152608082015160a082015260e0610d4b610d1860a085015161010060c0860152610120850190610b43565b60c08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08583030184860152610b43565b920151906101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082850301910152610bff565b3461026e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57610dce903690600401610b06565b60243567ffffffffffffffff811161026e5761086991610df5610e2b923690600401610b15565b5050610dff612c0f565b506080610e1a610e1260e0840184612c62565b810190612cb3565b910135610e2681612106565b613491565b60405191829182610c91565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e57600435610e6d8161025c565b91602435916044359067ffffffffffffffff821161026e5761041291600401610415565b3461026e57610af4610eb9610ea536610e37565b919290610eb23684610755565b90846124bb565b505091602082013592610ecb846104d0565b613f92565b3461026e57610869610e2b610efd610e12610eea3661089e565b610ef2612c0f565b506040810190612c62565b63ffffffff4216613491565b81601f8201121561026e57803590610f20826106b4565b92610f2e6040519485610308565b82845260208085019360051b8301019181831161026e5760208101935b838510610f5a57505050505090565b843567ffffffffffffffff811161026e57820160607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828603011261026e5760405191610fa6836102d0565b6020820135610fb4816104d0565b835260408201359267ffffffffffffffff841161026e57606083610fdf8860208098819801016103f7565b8584015201356040820152815201940193610f4b565b91909160c08184031261026e5761100a610349565b928135845261101b60208301610273565b602085015261102c604083016104ee565b604085015260608201356060850152608082013567ffffffffffffffff811161026e578161105b9184016106cc565b608085015260a082013567ffffffffffffffff811161026e5761107e9201610f09565b60a0830152565b602081016020825282518091526040820191602060408360051b8301019401926000915b8383106110b857505050505090565b90919293946020806110f4837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951610bbc565b970193019301919392906110a9565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e5761086991611157611164923690600401610ff5565b604435906064359261413b565b61116c6144e1565b5060405191829182611085565b600091031261026e57565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5761086960408051906111c58183610308565b600382527f332e320000000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190610bbc565b8015150361026e57565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356112418161025c565b60243567ffffffffffffffff811161026e576112619036906004016103f7565b906044359167ffffffffffffffff831161026e5761128661096f933690600401610415565b6064359061129382611201565b608435926112a0846104d0565b60a435946112ad866104d0565b612ce3565b3461026e576112c0366104f9565b919273ffffffffffffffffffffffffffffffffffffffff60208301356112e5816104d0565b16330361130b57611304610af4946112fd3685610755565b90836124bb565b5050613f92565b7f2eed2070000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e5760043561136f8161025c565b9160243567ffffffffffffffff811161026e578261138f916004016103f7565b916044359067ffffffffffffffff821161026e5761041291600401610755565b3461026e5761086961084c6113c336611339565b919060208151910120906124bb565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5761096f611422611479923690600401610890565b60243561142e81611201565b6044359061143b826104d0565b6114ba6064359361144b856104d0565b6114af81359161145a8361025c565b6114a561146a60208301836125b1565b6040519a8b91602083016127fe565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a610308565b6040810190612902565b966109693689610755565b508095614503565b3461026e5761096f61096936611339565b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc823603011261026e576040519061154d826102d0565b806004013561155b8161025c565b8252602481013567ffffffffffffffff811161026e576115819060043691840101610ff5565b602083015260448101359167ffffffffffffffff831161026e576115b161084c9260046108699536920101610755565b6040820152612fe4565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760206115f461476e565b604051908152f35b9181601f8401121561026e5782359167ffffffffffffffff831161026e576020808501948460051b01011161026e57565b3461026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5761167c9036906004016115fc565b9060243567ffffffffffffffff811161026e5761169d9036906004016115fc565b919060443567ffffffffffffffff811161026e576116bf9036906004016115fc565b949092858514801590611758575b61172e5760005b8581106116dd57005b6116e881848461304f565b35906116f38261025c565b6116fe81888761304f565b3588821015611729576001926117239161171d8460051b8a018a612902565b916138b6565b016116d4565b6129e9565b7fa24a13a60000000000000000000000000000000000000000000000000000000060005260046000fd5b50818514156116cd565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e576117af903690600401610b15565b9160443567ffffffffffffffff811161026e576117d0903690600401610b15565b9093830160408482031261026e57833567ffffffffffffffff811161026e576020916117fd9186016103f7565b930135907f0555709e59fb225fcf12cc582a9e5f7fd8eea54c91f3dc500ab9d8c37c5077706040518061185433878390929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b0390a184019360808186031261026e57803591611870836104d0565b60208201359361187f8561025c565b60408301359260608101359067ffffffffffffffff821161026e57610af4986118d4926118ac92016103f7565b9660208073ffffffffffffffffffffffffffffffffffffffff8351981697830101910161322c565b906132d7565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57611924903690600401610b06565b60243567ffffffffffffffff811161026e57611944903690600401610b15565b60449291923567ffffffffffffffff811161026e57611967903690600401610b15565b5050608082019261198361197a85612cd9565b63ffffffff1690565b4211611b4f57611992836123cf565b73ffffffffffffffffffffffffffffffffffffffff30911603611afd576060830135468103611acb57507faed0ae635eda11553af2dc98f5e5308e49abc5a2c0cae5c9a949b7927d77c40560c084013503611aa1576119f9916119f59184614897565b1590565b611a7757611a72610e2b82610e26611a6b611a3b610e1260e07f3448bbc2203c608599ad448eeb1007cea04b788ac631f9f558e8dd01a3c27b3d980185612c62565b92611a4e845167ffffffffffffffff1690565b906020850151611a656020604088015193016123cf565b926149b3565b5095612cd9565b0390a2005b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f0b6901880000000000000000000000000000000000000000000000000000000060005260046000fd5b7ff5ee213f000000000000000000000000000000000000000000000000000000006000526004524660245260445b6000fd5b611af9611b09846123cf565b7f30833ea50000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045230602452604490565b7f3e3fec280000000000000000000000000000000000000000000000000000000060005260046000fd5b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57611c77611bd47f000000000000000000000000000000000000000000000000000000000000000061505e565b611bfd7f000000000000000000000000000000000000000000000000000000000000000061517c565b6020604051611c0c8282610308565b6000815281611c85818301947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083013687376040519788977f0f00000000000000000000000000000000000000000000000000000000000000895260e0858a015260e0890190610bbc565b908782036040890152610bbc565b91466060870152306080870152600060a087015285830360c0870152519182815201929160005b828110611cbb57505050500390f35b835185528695509381019392810192600101611cac565b3461026e5760206104b2611ce53661089e565b6109296104ac823592611cf78461025c565b6114a5611d06878301836125b1565b6040519485918983016127fe565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435611d4a8161025c565b6024359060443567ffffffffffffffff811161026e57602092611d8f611d77611dae933690600401610415565b9360643592611d8584611201565b61057f3687610755565b505092611d9b84613b2e565b611da733923690610755565b9085614b43565b611db66144e1565b50604051908152f35b3461026e576020610886611dd23661089e565b610929610880823592611cf78461025c565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e57611e31903690600401610ff5565b9060443590606435608435611e45816104d0565b60a43591611e528361025c565b60c4359467ffffffffffffffff861161026e5761086996611e7a611e809736906004016103f7565b956132d7565b60405191829182611085565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435611f318161025c565b60243567ffffffffffffffff811161026e57611f519036906004016103f7565b906044359167ffffffffffffffff831161026e57611f7661096f933690600401610415565b9060643592611f8484611201565b613338565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57611fd661096f913690600401610890565b60243590611fe382611201565b610929612005823592611ff58461025c565b6114a561091a60208301836125b1565b91613338565b6120143661089e565b7faed0ae635eda11553af2dc98f5e5308e49abc5a2c0cae5c9a949b7927d77c405602082013503611aa157610e12816040612050930190612c62565b7f3448bbc2203c608599ad448eeb1007cea04b788ac631f9f558e8dd01a3c27b3d611a72610e2b67ffffffffffffffff845116936120a761209d6020830151966040840151978891612d02565b90963391886149db565b6120af6144e1565b5063ffffffff4216613491565b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560005260046020526020604060002054604051908152f35b63ffffffff81160361026e57565b81601f8201121561026e5780359061212b826106b4565b926121396040519485610308565b82845260208085019360071b8301019181831161026e57602001925b828410612163575050505090565b60808483031261026e57602060809160405161217e816102ec565b8635815282870135838201526040870135604082015260608701356060820152815201930192612155565b91909160c08184031261026e576121be610349565b926121c882610273565b8452602082013567ffffffffffffffff811161026e57816121ea9184016103f7565b6020850152604082013567ffffffffffffffff811161026e578161220f918401610755565b60408501526060820135606085015261222a60808301610273565b608085015260a082013567ffffffffffffffff811161026e5761107e9201612114565b3461026e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043561228881612106565b60243567ffffffffffffffff811161026e57610869916122af610e2b9236906004016121a9565b90613491565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356122eb8161025c565b60443560243567ffffffffffffffff821161026e5761231161234e923690600401610415565b9260643561231e81611201565b6123456084359261232e846104d0565b60a4359461233b866104d0565b61057f3689610755565b50508095614503565b50604051908152602090f35b3461026e57610af461171d36610e37565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576020600254604051908152f35b906123c8916123ba610412943690610755565b9160208151910120906124bb565b5050613b2e565b35610412816104d0565b6040513d6000823e3d90fd5b906020808351928381520192019060005b8181106124035750505090565b909192602061243b600192865190602060409273ffffffffffffffffffffffffffffffffffffffff8151168352015160208201520190565b94019291016123f6565b60c06080610412936020845267ffffffffffffffff815116602085015273ffffffffffffffffffffffffffffffffffffffff602082015116604085015273ffffffffffffffffffffffffffffffffffffffff604082015116606085015260608101518285015201519160a08082015201906123e5565b612551918093604051612502816124d6602082019485612445565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610308565b5190209283916124d6604051938492602084019687917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b51902092565b90612566916123ba3685610755565b505090816000526003602052600160ff6040600020541661258681610997565b1491821561259357505090565b61041292506125a190613b2e565b90613e69565b356104128161025c565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418136030182121561026e570190565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e57016020813591019167ffffffffffffffff821161026e578160061b3603831361026e57565b9160209082815201919060005b8181106126515750505090565b90919260408060019273ffffffffffffffffffffffffffffffffffffffff873561267a816104d0565b16815260208781013590820152019401929101612644565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b906020838281520160208260051b85010193836000915b8483106126f85750505050505090565b9091929394957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301855286357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18436030181121561026e57830173ffffffffffffffffffffffffffffffffffffffff8135612775816104d0565b16825260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e578101906020823592019067ffffffffffffffff831161026e57823603821361026e57836040806127ea60209695879660608860019b01526060860191612692565b9301359101529801969501930191906126e8565b90602082528035602083015267ffffffffffffffff60208201356128218161025c565b16604083015273ffffffffffffffffffffffffffffffffffffffff604082013561284a816104d0565b1660608301526060810135608083015261287b61286a60808301836125e4565b60c060a086015260e0850191612637565b9060a08101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e570160208135910167ffffffffffffffff821161026e578160051b3603811361026e578360c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610412968603019101526126d1565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618136030182121561026e570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b908160061b918083046040149015171561297a57565b612935565b600801908160081161297a57565b9190820180921161297a57565b906129a482610386565b6129b16040519182610308565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06129df8294610386565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051156117295760200190565b80518210156117295760209160051b010190565b9267ffffffffffffffff610412959373ffffffffffffffffffffffffffffffffffffffff612a7b94168652166020850152608060408501526080840190610bbc565b916060818403910152610bbc565b8251939192612aa7612aa2612a9d87612964565b61297f565b61299a565b947f000000000000000000000000000000000000000000000000000000000000000060c01b602087015260005b818110612b5b5750505073ffffffffffffffffffffffffffffffffffffffff164793813b1561026e57612b3b94600094604051968795869485937fbcd58bd20000000000000000000000000000000000000000000000000000000085523360048601612a39565b03925af180156106af57612b4c5750565b806106a3600061027e93610308565b612b79612b688285612a25565b516000526004602052604060002090565b548015612bd5579081600192604860208460051b880101518460061b8c019060288201520152612ba98286612a25565b517fe6d8040a8a6bc519f4e5a42fb2677067c929ddbf2cca9287a44b23fb617a6f00600080a301612ad4565b611af9612be28386612a25565b517fdab74d1e00000000000000000000000000000000000000000000000000000000600052600452602490565b60405190610100820182811067ffffffffffffffff8211176102cb57604052606060e083600081526000602082015260006040820152600083820152600060808201528260a08201528260c08201520152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026e570180359067ffffffffffffffff821161026e5760200191813603831361026e57565b9060208282031261026e57813567ffffffffffffffff811161026e5761041292016121a9565b3561041281612106565b612cfa90610412959397969492610969368a610755565b508096614503565b91929092612d178185516020870120856124bb565b50509384612d2481613b2e565b9481600052600360205260ff60406000205416612d4081610997565b60028114908115612e8b575b50612e5d5773ffffffffffffffffffffffffffffffffffffffff6020850151169273ffffffffffffffffffffffffffffffffffffffff6040860151169467ffffffffffffffff81511690612dc5608060608301519201519367ffffffffffffffff6040519616865260a0602087015260a0860190610bbc565b916040850152606084015282810360808401526020808351928381520192019060005b818110612e1b5750505090807f43974895be1bcec7344337863fa7de24a0d1c315c0a994f663fe0ee220ddc8e4920390a4565b9091926020612e53600192865190602060409273ffffffffffffffffffffffffffffffffffffffff8151168352015160208201520190565b9401929101612de8565b507f5eaf4c690000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60039150612e9881610997565b1438612d4c565b9080602083519182815201916020808360051b8301019401926000915b838310612ecb57505050505090565b9091929394602080827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0856001950301865288519073ffffffffffffffffffffffffffffffffffffffff8251168152604080612f34858501516060878601526060850190610bbc565b93015191015297019301930191939290612ebc565b9061041291602081528151602082015267ffffffffffffffff602083015116604082015273ffffffffffffffffffffffffffffffffffffffff60408301511660608201526060820151608082015260a0612fb1608084015160c08385015260e08401906123e5565b9201519060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082850301910152612e9f565b6130489067ffffffffffffffff8151166020820151604080519361303c85613010602082019586612f49565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286610308565b015192519020906124bb565b9192909190565b91908110156117295760051b0190565b519061027e8261025c565b519061027e826104d0565b81601f8201121561026e5780519061308c826106b4565b9261309a6040519485610308565b82845260208085019360061b8301019181831161026e57602001925b8284106130c4575050505090565b60408483031261026e57602060409182516130de816102af565b86516130e9816104d0565b815282870151838201528152019301926130b6565b81601f8201121561026e57805161311481610386565b926131226040519485610308565b8184526020828401011161026e576104129160208085019101610b99565b81601f8201121561026e57805190613157826106b4565b926131656040519485610308565b82845260208085019360051b8301019181831161026e5760208101935b83851061319157505050505090565b845167ffffffffffffffff811161026e57820160607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828603011261026e57604051916131dd836102d0565b60208201516131eb816104d0565b835260408201519267ffffffffffffffff841161026e576060836132168860208098819801016130fe565b8584015201516040820152815201940193613182565b60208183031261026e5780519067ffffffffffffffff821161026e570160c08183031261026e5761325b610349565b918151835261326c6020830161305f565b602084015261327d6040830161306a565b604084015260608201516060840152608082015167ffffffffffffffff811161026e57816132ac918401613075565b608084015260a082015167ffffffffffffffff811161026e576132cf9201613140565b60a082015290565b9290916132e892969495968461413b565b936040938451926132f98685610308565b600184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0602085019601368737835115611729576104129552612a89565b6133569061334e61336293949695963690610755565b938491612d02565b94909233908685614b43565b61336a6144e1565b509190565b90613379826106b4565b6133866040519182610308565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06133b482946106b4565b019060005b8281106133c557505050565b6020906040516133d4816102ec565b600081526000838201526000604082015260006060820152828285010152016133b9565b6040805191906134089083610308565b60018252817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061343860016106b4565b019060005b82811061344957505050565b602090604051613458816102d0565b60008152600083820152606060408201528282850101520161343d565b92919061348c602091604086526040860190610bbc565b930152565b613499612c0f565b50604082019081519060606080830151519201511515600014613738576134cd6134c860ff60015b168461298d565b61336f565b9160005b8181106136b557506060845101519081613679575b505060208401926136626135f960208651818151910120938051604051613514816124d68682019485612445565b519020948561357761352e8c5167ffffffffffffffff1690565b926124d66040519384928884019687917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b519020946135996135866133f8565b99516124d6604051938492878401613475565b895167ffffffffffffffff169060608b015167ffffffffffffffff6135bc610367565b931683528483015260408201526135d289612a18565b526135dc88612a18565b5051015173ffffffffffffffffffffffffffffffffffffffff1690565b9561365560a061361761197a608085015167ffffffffffffffff1690565b92015194613642613626610376565b73ffffffffffffffffffffffffffffffffffffffff909a168a52565b4660208a015263ffffffff166040890152565b63ffffffff166060870152565b608085015260a084015260c083015260e082015290565b6136ad91613685610358565b90600082526020820152600060408201524660608201526136a68286612a25565b5283612a25565b5038806134e6565b806136eb6105a36105a36136d060019560808b510151612a25565b515173ffffffffffffffffffffffffffffffffffffffff1690565b60206136fc8360808a510151612a25565b510151613707610358565b9182526020820152600060408201524660608201526137268287612a25565b526137318186612a25565b50016134d1565b6134cd6134c860ff60006134c1565b9081604091031261026e57602060405191613761836102af565b805161376c816104d0565b835201516137798161025c565b602082015290565b61378b6002610997565b60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b6137c06001610997565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b9060a06138726104129367ffffffffffffffff81356138098161025c565b16845273ffffffffffffffffffffffffffffffffffffffff602082013561382f816104d0565b16602085015273ffffffffffffffffffffffffffffffffffffffff6040820135613858816104d0565b1660408501526060810135606085015260808101906125e4565b9190928160808201520191612637565b9073ffffffffffffffffffffffffffffffffffffffff6138af6020929594956040855260408501906137eb565b9416910152565b91906138cc6138c53684610755565b82856124bb565b929194905060408401926138e56105a36105a3866123cf565b604080517f99d145b2000000000000000000000000000000000000000000000000000000008152600481018990529591869060249082905afa9485156106af57600095613afd575b506139616020613951875173ffffffffffffffffffffffffffffffffffffffff1690565b96015167ffffffffffffffff1690565b67ffffffffffffffff8085169116141580613ade575b613a6a57505050506139898184614c84565b6139a56139a0846000526003602052604060002090565b613781565b6139b46105a36105a385613dbf565b803b1561026e57816000916139f994836040518097819582947f012c41ca00000000000000000000000000000000000000000000000000000000845260048401613882565b03925af19081156106af577fbb062c23e818de8ea9c157514eb098052cf36904bbe431cd50d4ec92264ca3ac9273ffffffffffffffffffffffffffffffffffffffff92613a55575b50604051938452169180602081015b0390a2565b806106a36000613a6493610308565b38613a41565b613a819396506105a39295506105a39194506123cf565b803b1561026e576040517ffc0eab9100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90931660048401526024830193909352604482015290600090829081838160648101612b3b565b5073ffffffffffffffffffffffffffffffffffffffff85161515613977565b613b2091955060403d604011613b27575b613b188183610308565b810190613747565b933861392d565b503d613b0e565b6105a3610412916124d6613c5e60c960405190613b4e6020820183610308565b80825261574060208301396124d6613bca604051613bb0816124d67f00000000000000000000000000000000000000000000000000000000000000006020830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b604051928391613bc4602084018097614d34565b90614d34565b5190206040519283916020830195307f0000000000000000000000000000000000000000000000000000000000000000889290605594927fff000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009216855260601b166001840152601583015260358201520190565b51902073ffffffffffffffffffffffffffffffffffffffff1690565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026e570180359067ffffffffffffffff821161026e57602001918160061b3603831361026e57565b91908110156117295760061b0190565b919073ffffffffffffffffffffffffffffffffffffffff16918215613d915760808101613d0b8183613c7a565b92905060005b838110613d2057505050509050565b8573ffffffffffffffffffffffffffffffffffffffff613d4a83613d448787613c7a565b90613cce565b35613d54816104d0565b1614613d6257600101613d11565b857f9794df66000000000000000000000000000000000000000000000000000000006000526024906004526000fd5b827f9794df660000000000000000000000000000000000000000000000000000000060005260045260246000fd5b613dc881613b2e565b90813b15613dd4575090565b905060405160c98082019082821067ffffffffffffffff8311176102cb576020918391615740833973ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681520301906000f580156106af5773ffffffffffffffffffffffffffffffffffffffff1690565b9081602091031261026e575190565b9060808201613e788184613c7a565b9390508231606082013511613f895760005b848110613e9b575050505050600190565b613eb1613eac82613d448686613c7a565b6123cf565b6020613ec183613d448787613c7a565b013590602060405180927f70a082310000000000000000000000000000000000000000000000000000000082528173ffffffffffffffffffffffffffffffffffffffff81613f2f8c6004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b0392165afa9081156106af57600091613f5b575b5010613f5157600101613e8a565b5050505050600090565b613f7c915060203d8111613f82575b613f748183610308565b810190613e5a565b38613f43565b503d613f6a565b50505050600090565b929082613f9f9185614d6f565b8260005260036020526040600020613fb76003610997565b60037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055613fef6105a36105a385613dbf565b803b1561026e578160009161403494836040518097819582947faadee52c00000000000000000000000000000000000000000000000000000000845260048401613882565b03925af19081156106af577f8d53c2b04800cf061b987a07179bb6c9730c05536b2f6a3a091fe62303682eb69273ffffffffffffffffffffffffffffffffffffffff92613a55575060405193845216918060208101613a50565b60208183031261026e5780519067ffffffffffffffff821161026e57019080601f8301121561026e5781516140c2816106b4565b926140d06040519485610308565b81845260208085019260051b8201019183831161026e5760208201905b8382106140fc57505050505090565b815167ffffffffffffffff811161026e5760209161411f878480948801016130fe565b8152019101906140ed565b906020610412928181520190612e9f565b909291614163614156602086015167ffffffffffffffff1690565b67ffffffffffffffff1690565b4211614487576124d66141f06040516020810190614185816124d68a85612f49565b5190209260405192839160208301957f000000000000000000000000000000000000000000000000000000000000000087917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b519020604084015173ffffffffffffffffffffffffffffffffffffffff163081036144445750810361441757614230816000526004602052604060002090565b546143ea5781156143c05781614250826000526004602052604060002090565b557fc471de166a60c0b81727dfa2f57d4fc3ad1b45b057c1f034b7058365613bde8d600080a360808101805151906060830190815180341061438f57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16929060005b8281106143485750505060009160a061431592519401516040519485809481937f760f2a0b0000000000000000000000000000000000000000000000000000000083526004830161412a565b03925af19081156106af5760009161432b575090565b61041291503d806000833e6143408183610308565b81019061408e565b806143896143596001938551612a25565b5187602061437e6105a3845173ffffffffffffffffffffffffffffffffffffffff1690565b920151913390614f0c565b016142c9565b7f172f1184000000000000000000000000000000000000000000000000000000006000523460045260245260446000fd5b7f69b3229a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f373d20790000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7f44d659bf0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fd16be7520000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045260246000fd5b7f408b22340000000000000000000000000000000000000000000000000000000060005260046000fd5b3d156144dc573d906144c282610386565b916144d06040519384610308565b82523d6000602084013e565b606090565b4780156144fd57600080808093335af16144f96144b1565b5090565b50600190565b93919091600083600052600360205260ff6040600020541661452481610997565b60028114801561470b575b6146d5578061453f600192610997565b146146cc575090602073ffffffffffffffffffffffffffffffffffffffff85936145a261456b87613dbf565b9860405196879485947f76a66d1b000000000000000000000000000000000000000000000000000000008652169160048501614733565b03813473ffffffffffffffffffffffffffffffffffffffff8a165af19182156106af5760009261469b575b501580614693575b614664579061463d827fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a9493614643575b60405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b0390a190565b61465f61465a846000526003602052604060002090565b6137b6565b614606565b7f07b9062000000000000000000000000000000000000000000000000000000000600052600482905260246000fd5b5080156145d5565b6146be91925060203d6020116146c5575b6146b68183610308565b81019061471e565b90386145cd565b503d6146ac565b95945050505050565b7f89939a210000000000000000000000000000000000000000000000000000000060005261470281610997565b60045260246000fd5b5061471581610997565b6003811461452f565b9081602091031261026e575161041281611201565b91939273ffffffffffffffffffffffffffffffffffffffff90816147616040946060875260608701906137eb565b9616602085015216910152565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630148061486e575b156147d6577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a0815261486860c082610308565b51902090565b507f000000000000000000000000000000000000000000000000000000000000000046146147ad565b6105a36149a76148df946149a173ffffffffffffffffffffffffffffffffffffffff956149996149ad96600254906149916148d1826123cf565b6124d6602084019d8e6123cf565b9360408101359060608101356148f760808301612cd9565b61490360a08401612cd9565b9161492161491a60c08601359560e0810190612c62565b36916103c0565b6020815191012094604051998a9860208a019c8d95909998979463ffffffff9473ffffffffffffffffffffffffffffffffffffffff61010099958188966101208c019f8c521660208b0152166040890152606088015260808701521660a08501521660c083015260e08201520152565b519020615007565b9236916103c0565b90615048565b936123cf565b91161490565b6149c6836149d093600093979597612d02565b9490958587614b43565b6149d86144e1565b50565b9392919084600052600360205260ff604060002054166149fa81610997565b600281148015614b30575b6146d55780614a15600192610997565b14614b29576080614a2a606084015183615245565b920190815151906000925b828410614add57505050508015614aae5792614aa9847fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a94956146435760405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b0390a1565b7f07b9062000000000000000000000000000000000000000000000000000000000600052600484905260246000fd5b90919293600190614af56105a36136d0888651612a25565b81614b06575b509401929190614a35565b614b2391506020614b18888651612a25565b5101519088866152bc565b38614afb565b5050509050565b50614b3a81610997565b60038114614a05565b94939085600052600360205260ff60406000205416614b6181610997565b600281148015614c71575b6146d55780614b7c600192610997565b14614c69576080614b91606085015183615245565b930190815151906000925b828410614c1d57505050501580614c15575b614aae5792614aa9847fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a94956146435760405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b508015614bae565b90919294600190614c356105a36136d0898651612a25565b81614c46575b509501929190614b9c565b614c6391506020614c58898651612a25565b5101519089866152bc565b38614c3b565b505050509050565b50614c7b81610997565b60038114614b6c565b600052600360205260ff60406000205416614c9e81610997565b80151580614d20575b614cf3575073ffffffffffffffffffffffffffffffffffffffff1615614cc957565b7fdbdf7dda0000000000000000000000000000000000000000000000000000000060005260046000fd5b7ffecf1ec00000000000000000000000000000000000000000000000000000000060005261470281610997565b50614d2a81610997565b6001811415614ca7565b90614d4760209282815194859201610b99565b0190565b929167ffffffffffffffff91606494614d6381610997565b60045260245216604452565b91614d8e614d87846000526003602052604060002090565b5460ff1690565b91614da16105a36105a3604085016123cf565b604080517f99d145b2000000000000000000000000000000000000000000000000000000008152600481018790529291839060249082905afa9182156106af57600092614eeb575b5067ffffffffffffffff80614e09602085015167ffffffffffffffff1690565b921691161490811591614ecb575b50614e795750614e2681610997565b8015908115614e65575b50614e385750565b7f6b7aeaaa0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60019150614e7281610997565b1438614e30565b909150614e88614156826125a7565b4210614e92575050565b90614e9f611af9926125a7565b907fc6a2514b000000000000000000000000000000000000000000000000000000006000524290614d4b565b5173ffffffffffffffffffffffffffffffffffffffff1615905038614e17565b614f0591925060403d604011613b2757613b188183610308565b9038614de9565b60009173ffffffffffffffffffffffffffffffffffffffff8392614f90959682604051988160208b01967f23b872dd0000000000000000000000000000000000000000000000000000000088521660248b0152166044890152606488015260648752614f79608488610308565b1694519082865af1614f896144b1565b90836156a2565b8051908115159182614fe9575b5050614fa65750565b7f5274afe70000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045260246000fd5b6150009250906020806119f593830101910161471e565b3880614f9d565b60429061501261476e565b90604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b610412916150559161547e565b909291926154b3565b60ff811461506f5761041290615580565b5060405160008054908160011c9160018116908115615172575b602084108214615145578385528492916020840191811561510e57506001146150ba575b5061041292500382610308565b600080805291507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8483106150f75750610412935001386150ad565b8054828401528593506020909201916001016150e3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682525061041293151560051b019050386150ad565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b92607f1692615089565b60ff811461518d5761041290615580565b506040516000600154908160011c916001811690811561522e575b602084108214615145578385528492916020840191811561510e57506001146151d8575061041292500382610308565b6001600090815291507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8483106152175750610412935001386150ad565b805482840152859350602090920191600101615203565b92607f16926151a8565b9190820391821161297a57565b8031828110156152b457820391821161297a5761526234836155fa565b908180158015615275575b505050101590565b60009283928392839283916152aa575b73ffffffffffffffffffffffffffffffffffffffff1690f1156106af5738818161526d565b6108fc9150615285565b505050600190565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528416939192909190602083602481885afa9283156106af5760009361545d575b5085831015615452576153328387615238565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152306024820152906020826044818a5afa9081156106af5761539d92600092615431575b506155fa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201529095602090829060249082905afa80156106af5761541a966154089260009261543157506155fa565b9384918261541f575b5050505061298d565b101590565b61542893614f0c565b38828180615411565b61544b91925060203d602011613f8257613f748183610308565b9038615397565b505050505050600190565b61547791935060203d602011613f8257613f748183610308565b913861531f565b81519190604183036154a85761304892506020820151906060604084015193015160001a9061560c565b505060009160029190565b6154bc81610997565b806154c5575050565b6154ce81610997565b60018103615500577ff645eedf0000000000000000000000000000000000000000000000000000000060005260046000fd5b61550981610997565b6002810361553f57507ffce698f70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b8061554b600392610997565b146155535750565b7fd78bce0c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60ff811690601f82116155d057604080519261559c8285610308565b602084527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060208501920136833783525290565b7fb3512b0c0000000000000000000000000000000000000000000000000000000060005260046000fd5b9080821015615607575090565b905090565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615696579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156106af5760005173ffffffffffffffffffffffffffffffffffffffff81161561568a5790600090600090565b50600090600190600090565b50505060009160039190565b906156e157508051156156b757805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580615736575b6156f2575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156156ea56fe60a034606257601f60c938819003918201601f19168301916001600160401b03831184841017606757808492602094604052833981010312606257516001600160a01b0381168103606257608052604051604b9081607e82396080518160150152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040523615604957366000803760008036817f00000000000000000000000000000000000000000000000000000000000000005af43d6000803e156044573d6000f35b3d6000fd5b0060a080604052346021573360805261066a908161002782396080518160ac0152f35b600080fdfe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c63760f2a0b0361000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104c65760043567ffffffffffffffff81116104c657366023820112156104c657806004013567ffffffffffffffff81116104c6573660248260051b840101116104c65773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610498576100e36100de8261059d565b61052a565b918183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06101118361059d565b0160005b81811061048757505060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7d82360301905b8381101561040357600060248260051b85010135838112156103ff5784019060248201610173816105f8565b3b15806103e8575b61039e57610188816105f8565b9260648101359083806044830196846101a18988610619565b9190826040519384928337810185815203925af1943d15610396573d9567ffffffffffffffff8711610369576101fe60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8a01160161052a565b9687523d86602089013e5b156102335750505050509060019161022182886105b5565b5261022c81876105b5565b5001610147565b60409593949551947f12988136000000000000000000000000000000000000000000000000000000008652604060048701523573ffffffffffffffffffffffffffffffffffffffff811680910361036557604486015235907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd3682900301821215610361570160248101359060440167ffffffffffffffff821161036157813603811361036157917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83879860c49561035d9897606060648c01528160a48c0152878b013785828a010152011685019060848601527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc828683030101602486015201906104cb565b0390fd5b8580fd5b8680fd5b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b606095610209565b9073ffffffffffffffffffffffffffffffffffffffff6103bf6024936105f8565b7f2db5928900000000000000000000000000000000000000000000000000000000835216600452fd5b506103f66044840182610619565b9050151561017b565b5080fd5b846040518091602082016020835281518091526040830190602060408260051b8601019301916000905b82821061043c57505050500390f35b91936020610477827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0600195979984950301865288516104cb565b960192019201859493919261042d565b806060602080938801015201610115565b7f564f4a6c000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b600080fd5b919082519283825260005b8481106105155750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006020809697860101520116010190565b806020809284010151828286010152016104d6565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f604051930116820182811067ffffffffffffffff82111761056e57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff811161056e5760051b60200190565b80518210156105c95760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b3573ffffffffffffffffffffffffffffffffffffffff811681036104c65790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156104c6570180359067ffffffffffffffff82116104c6576020019181360383136104c6575660a0806040523460365733608052611062908161003c8239608051818181606d0152818161017d015281816102c401526103ec0152f35b600080fdfe6080604052600436101561001257600080fd5b60003560e01c8063012c41ca146103c7578063648bf7741461025657806376a66d1b146100d15763aadee52c1461004857600080fd5b346100cc576100563661043e565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361009e5761009c916107dd565b005b7f407c71ac000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b600080fd5b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100cc5760043567ffffffffffffffff81116100cc578060040160a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc83360301126100cc5761014561041b565b6044359173ffffffffffffffffffffffffffffffffffffffff831683036100cc5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361009e57929190608447606485013511159301936101bd85826104ce565b9390506000955b8487106101d8576020866040519015158152f35b909192939460019061023973ffffffffffffffffffffffffffffffffffffffff61021461020f8b610209888b6104ce565b90610522565b610561565b166102328660206102298d6102098a8d6104ce565b0135838b61098c565b9088610d5d565b8161024d575b5096019594939291906101c4565b9050158861023f565b346100cc5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100cc5760043573ffffffffffffffffffffffffffffffffffffffff811681036100cc576102ad61041b565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361009e5773ffffffffffffffffffffffffffffffffffffffff1690604051907f70a08231000000000000000000000000000000000000000000000000000000008252306004830152602082602481865afa9182156103bb57600092610384575b5081156103565761009c926108d9565b827facf3c8ed0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b90916020823d6020116103b3575b8161039f60209383610582565b810103126103b05750519083610346565b80fd5b3d9150610392565b6040513d6000823e3d90fd5b346100cc576103d53661043e565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361009e5761009c91610650565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036100cc57565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126100cc576004359067ffffffffffffffff82116100cc577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8260a0920301126100cc576004019060243573ffffffffffffffffffffffffffffffffffffffff811681036100cc5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156100cc570180359067ffffffffffffffff82116100cc57602001918160061b360383136100cc57565b91908110156105325760061b0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b3573ffffffffffffffffffffffffffffffffffffffff811681036100cc5790565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176105c357604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b3d1561064b573d9067ffffffffffffffff82116105c3576040519161063f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610582565b82523d6000602084013e565b606090565b6080810161065e81836104ce565b91905060005b8281106106f5575050506060479101358082106000146106ed5750905b81156106e957600080808085855af16106986105f2565b50156106a2575050565b73ffffffffffffffffffffffffffffffffffffffff907fa5b05eec000000000000000000000000000000000000000000000000000000006000521660045260245260446000fd5b5050565b905090610681565b73ffffffffffffffffffffffffffffffffffffffff61071b61020f8361020986896104ce565b16602061072c8361020986896104ce565b01356040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa9081156103bb576000916107ab575b50600193929190808210156107a457505b8781610793575b50505001610664565b61079c926108d9565b38808761078a565b9050610783565b906020823d82116107d5575b816107c460209383610582565b810103126103b05750516001610772565b3d91506107b7565b608081016107eb81836104ce565b92905060005b8381106108155750505050479081156106e957600080808085855af16106986105f2565b73ffffffffffffffffffffffffffffffffffffffff61083b61020f8361020987876104ce565b166040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa9081156103bb576000916108a7575b5090818760019493610896575b505050016107f1565b61089f926108d9565b38808761088d565b906020823d82116108d1575b816108c060209383610582565b810103126103b05750516001610880565b3d91506108b3565b61093b9273ffffffffffffffffffffffffffffffffffffffff604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252610936606483610582565b610f27565b565b9190820391821161094a57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b519065ffffffffffff821682036100cc57565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529094936000939273ffffffffffffffffffffffffffffffffffffffff169190602082602481865afa918215610d52578592610d1e575b5083821015610d155773ffffffffffffffffffffffffffffffffffffffff16958615610d065773ffffffffffffffffffffffffffffffffffffffff604051917f927da10500000000000000000000000000000000000000000000000000000000835216918260048301528360248301523060448301526060826064818b5afa918215610cfb578692610c8a575b506040517f70a08231000000000000000000000000000000000000000000000000000000008152836004820152602081602481885afa908115610c7f578791610c47575b50610adf73ffffffffffffffffffffffffffffffffffffffff928761093d565b9080821015610c3f5750915b1680821015610c375750955b86610b95575b50506024939450602090604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610b895791610b53575b610b50925061093d565b90565b90506020823d602011610b81575b81610b6e60209383610582565b810103126100cc57610b50915190610b46565b3d9150610b61565b604051903d90823e3d90fd5b803b15610c335795608485928373ffffffffffffffffffffffffffffffffffffffff996040519a8b9586947f36c7851600000000000000000000000000000000000000000000000000000000865260048601523060248601521660448401528660648401525af1948515610c285760249495610c13575b8594610afd565b92610c218160209395610582565b9290610c0c565b6040513d85823e3d90fd5b8480fd5b905095610af7565b905091610aeb565b90506020813d602011610c77575b81610c6260209383610582565b81010312610c735751610adf610abf565b8680fd5b3d9150610c55565b6040513d89823e3d90fd5b9091506060813d606011610cf3575b81610ca660609383610582565b81010312610cef5780519073ffffffffffffffffffffffffffffffffffffffff82168203610c7357604081610ce06020610ce79401610979565b5001610979565b509038610a7b565b8580fd5b3d9150610c99565b6040513d88823e3d90fd5b50925050610b5092935061093d565b50929450505050565b9091506020813d602011610d4a575b81610d3a60209383610582565b81010312610c33575190386109ee565b3d9150610d2d565b6040513d87823e3d90fd5b92918015610f1f5773ffffffffffffffffffffffffffffffffffffffff82169173ffffffffffffffffffffffffffffffffffffffff604051957fdd62ed3e0000000000000000000000000000000000000000000000000000000087521692836004870152306024870152602086604481845afa9586156103bb57600096610eea575b50946020602496604051978880927f70a082310000000000000000000000000000000000000000000000000000000082528860048301525afa9586156103bb57600096610eb6575b50610b509495808410600014610eb0575082905b80821015610ea85750925b83610e53575b505061093d565b610ea191604051917f23b872dd000000000000000000000000000000000000000000000000000000006020840152602483015230604483015284606483015260648252610936608483610582565b3880610e4c565b905092610e46565b90610e3b565b6020813d602011610ee2575b81610ecf60209383610582565b81010312610c7357519550610b50610e27565b3d9150610ec2565b956020873d602011610f17575b81610f0460209383610582565b810103126103b057509451946020610ddf565b3d9150610ef7565b506000925050565b60008073ffffffffffffffffffffffffffffffffffffffff610f5e93169360208151910182865af1610f576105f2565b9083610fc5565b8051908115159182610fa1575b5050610f745750565b7f5274afe70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b81925090602091810103126100cc57602001518015908115036100cc573880610f6b565b906110045750805115610fda57805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580611059575b611015575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b1561100d56
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c80630742ebe4146102575780630d0eeb7a146102525780630e74db051461024d5780630fa76b79146102485780631034b866146102435780631299d6171461023e57806317d4e8071461023957806322bcd51a14610234578063308adade1461022f57806341b477dd1461022a57806352a8339e1461022557806354fd4d501461022057806355a0bec01461021b578063572ac041146102165780636063cd5b1461021157806360d1c29c1461020c578063645c890c1461020757806364cf9bb61461020257806378e890ba146101fd5780637af10029146101f857806382e2c43f146101f3578063844fac8e146101ee57806384b0196e146101e95780638ba5e373146101e45780639f24b4dd146101df578063b2e55f30146101da578063b6681e39146101d5578063c34c08e5146101d0578063df00f8fa146101cb578063e353b5e6146101c6578063e917a962146101c1578063ed60f2a3146101bc578063ee64c551146101b7578063f16f5138146101b2578063f987b9bc146101ad5763fcb8f14e146101a857600080fd5b61236b565b61235a565b6122b5565b61224d565b6120bc565b61200b565b611f89565b611efb565b611e8c565b611de4565b611dbf565b611d14565b611cd2565b611b79565b6118da565b611762565b61162d565b6115bb565b6114d3565b6114c2565b6113d2565b6113af565b6112b2565b61120b565b611184565b611103565b610ed0565b610e91565b610d7f565b610a26565b6109d0565b6108e7565b61086d565b6107e5565b610560565b610499565b67ffffffffffffffff81160361026e57565b600080fd5b359061027e8261025c565b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff8211176102cb57604052565b610280565b6060810190811067ffffffffffffffff8211176102cb57604052565b6080810190811067ffffffffffffffff8211176102cb57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176102cb57604052565b6040519061027e60c083610308565b6040519061027e608083610308565b6040519061027e606083610308565b6040519061027e61010083610308565b67ffffffffffffffff81116102cb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926103cc82610386565b916103da6040519384610308565b82948184528183011161026e578281602093846000960137010152565b9080601f8301121561026e57816020610412933591016103c0565b90565b908160a091031261026e5790565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e576004356104598161025c565b9160243567ffffffffffffffff811161026e5782610479916004016103f7565b916044359067ffffffffffffffff821161026e5761041291600401610415565b3461026e5760206104b26104ac36610423565b916123a7565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b73ffffffffffffffffffffffffffffffffffffffff81160361026e57565b359061027e826104d0565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e5760043561052f8161025c565b91602435916044359067ffffffffffffffff821161026e5761055391600401610415565b90606435610412816104d0565b3461026e57610585610571366104f9565b9290939161057f3686610755565b916124bb565b5050916105928282613cde565b60206105bc6105a36105a386613dbf565b73ffffffffffffffffffffffffffffffffffffffff1690565b91016105c7816123cf565b91803b1561026e576040517f648bf77400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416600482015292841660248401526000908390604490829084905af19182156106af5761067773ffffffffffffffffffffffffffffffffffffffff9283927f21ea3a531675a90b5b0263d6dc9be64e34e0bfd422a8b428b2d0729c5d4446e495610694575b506123cf565b169261068f6040519283921695829190602083019252565b0390a3005b806106a360006106a993610308565b80611179565b38610671565b6123d9565b67ffffffffffffffff81116102cb5760051b60200190565b81601f8201121561026e578035906106e3826106b4565b926106f16040519485610308565b82845260208085019360061b8301019181831161026e57602001925b82841061071b575050505090565b60408483031261026e5760206040918251610735816102af565b8635610740816104d0565b8152828701358382015281520193019261070d565b919060a08382031261026e576040519060a0820182811067ffffffffffffffff8211176102cb576040528193803561078c8161025c565b8352602081013561079c816104d0565b602084015260408101356107af816104d0565b60408401526060810135606084015260808101359167ffffffffffffffff831161026e576080926107e092016106cc565b910152565b3461026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356108208161025c565b602435906044359067ffffffffffffffff821161026e576108699261057f61084c933690600401610755565b604080519384526020840192909252908201529081906060820190565b0390f35b3461026e57602061088661088036610423565b91612557565b6040519015158152f35b9081606091031261026e5790565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e576004359067ffffffffffffffff821161026e5761041291600401610890565b3461026e5761096f6108f83661089e565b61092961096982359261090a8461025c565b61095561091a60208301836125b1565b604051948591602083016127fe565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101855284610308565b61096436916040810190612902565b610755565b91612d02565b6040805192835273ffffffffffffffffffffffffffffffffffffffff91909116602083015290f35b600411156109a157565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356000526003602052602060ff6040600020541660405190610a2281610997565b8152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435610a5c816104d0565b60243590610a698261025c565b60443567ffffffffffffffff811161026e573660238201121561026e57806004013590610a95826106b4565b91610aa36040519384610308565b8083526024602084019160051b8301019136831161026e57602401905b828210610af6575050506064359267ffffffffffffffff841161026e57610aee610af49436906004016103f7565b92612a89565b005b8135815260209182019101610ac0565b908161010091031261026e5790565b9181601f8401121561026e5782359167ffffffffffffffff831161026e576020838186019501011161026e57565b906020808351928381520192019060005b818110610b615750505090565b909192602060806001926060875180518352848101518584015260408101516040840152015160608201520194019101919091610b54565b60005b838110610bac5750506000910152565b8181015183820152602001610b9c565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093610bf881518092818752878088019101610b99565b0116010190565b9080602083519182815201916020808360051b8301019401926000915b838310610c2b57505050505090565b9091929394602080610c82837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08660019603018752606060408b518051845285810151868501520151918160408201520190610bbc565b97019301930191939290610c1c565b906104129160208152610cbd60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b60208201516040820152610cde6040830151606083019063ffffffff169052565b606082015163ffffffff166080820152608082015160a082015260e0610d4b610d1860a085015161010060c0860152610120850190610b43565b60c08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08583030184860152610b43565b920151906101007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082850301910152610bff565b3461026e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57610dce903690600401610b06565b60243567ffffffffffffffff811161026e5761086991610df5610e2b923690600401610b15565b5050610dff612c0f565b506080610e1a610e1260e0840184612c62565b810190612cb3565b910135610e2681612106565b613491565b60405191829182610c91565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e57600435610e6d8161025c565b91602435916044359067ffffffffffffffff821161026e5761041291600401610415565b3461026e57610af4610eb9610ea536610e37565b919290610eb23684610755565b90846124bb565b505091602082013592610ecb846104d0565b613f92565b3461026e57610869610e2b610efd610e12610eea3661089e565b610ef2612c0f565b506040810190612c62565b63ffffffff4216613491565b81601f8201121561026e57803590610f20826106b4565b92610f2e6040519485610308565b82845260208085019360051b8301019181831161026e5760208101935b838510610f5a57505050505090565b843567ffffffffffffffff811161026e57820160607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828603011261026e5760405191610fa6836102d0565b6020820135610fb4816104d0565b835260408201359267ffffffffffffffff841161026e57606083610fdf8860208098819801016103f7565b8584015201356040820152815201940193610f4b565b91909160c08184031261026e5761100a610349565b928135845261101b60208301610273565b602085015261102c604083016104ee565b604085015260608201356060850152608082013567ffffffffffffffff811161026e578161105b9184016106cc565b608085015260a082013567ffffffffffffffff811161026e5761107e9201610f09565b60a0830152565b602081016020825282518091526040820191602060408360051b8301019401926000915b8383106110b857505050505090565b90919293946020806110f4837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc086600196030187528951610bbc565b970193019301919392906110a9565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e5761086991611157611164923690600401610ff5565b604435906064359261413b565b61116c6144e1565b5060405191829182611085565b600091031261026e57565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5761086960408051906111c58183610308565b600382527f332e320000000000000000000000000000000000000000000000000000000000602083015251918291602083526020830190610bbc565b8015150361026e57565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356112418161025c565b60243567ffffffffffffffff811161026e576112619036906004016103f7565b906044359167ffffffffffffffff831161026e5761128661096f933690600401610415565b6064359061129382611201565b608435926112a0846104d0565b60a435946112ad866104d0565b612ce3565b3461026e576112c0366104f9565b919273ffffffffffffffffffffffffffffffffffffffff60208301356112e5816104d0565b16330361130b57611304610af4946112fd3685610755565b90836124bb565b5050613f92565b7f2eed2070000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261026e5760043561136f8161025c565b9160243567ffffffffffffffff811161026e578261138f916004016103f7565b916044359067ffffffffffffffff821161026e5761041291600401610755565b3461026e5761086961084c6113c336611339565b919060208151910120906124bb565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5761096f611422611479923690600401610890565b60243561142e81611201565b6044359061143b826104d0565b6114ba6064359361144b856104d0565b6114af81359161145a8361025c565b6114a561146a60208301836125b1565b6040519a8b91602083016127fe565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081018b528a610308565b6040810190612902565b966109693689610755565b508095614503565b3461026e5761096f61096936611339565b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc823603011261026e576040519061154d826102d0565b806004013561155b8161025c565b8252602481013567ffffffffffffffff811161026e576115819060043691840101610ff5565b602083015260448101359167ffffffffffffffff831161026e576115b161084c9260046108699536920101610755565b6040820152612fe4565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760206115f461476e565b604051908152f35b9181601f8401121561026e5782359167ffffffffffffffff831161026e576020808501948460051b01011161026e57565b3461026e5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e5761167c9036906004016115fc565b9060243567ffffffffffffffff811161026e5761169d9036906004016115fc565b919060443567ffffffffffffffff811161026e576116bf9036906004016115fc565b949092858514801590611758575b61172e5760005b8581106116dd57005b6116e881848461304f565b35906116f38261025c565b6116fe81888761304f565b3588821015611729576001926117239161171d8460051b8a018a612902565b916138b6565b016116d4565b6129e9565b7fa24a13a60000000000000000000000000000000000000000000000000000000060005260046000fd5b50818514156116cd565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e576117af903690600401610b15565b9160443567ffffffffffffffff811161026e576117d0903690600401610b15565b9093830160408482031261026e57833567ffffffffffffffff811161026e576020916117fd9186016103f7565b930135907f0555709e59fb225fcf12cc582a9e5f7fd8eea54c91f3dc500ab9d8c37c5077706040518061185433878390929173ffffffffffffffffffffffffffffffffffffffff6020916040840195845216910152565b0390a184019360808186031261026e57803591611870836104d0565b60208201359361187f8561025c565b60408301359260608101359067ffffffffffffffff821161026e57610af4986118d4926118ac92016103f7565b9660208073ffffffffffffffffffffffffffffffffffffffff8351981697830101910161322c565b906132d7565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57611924903690600401610b06565b60243567ffffffffffffffff811161026e57611944903690600401610b15565b60449291923567ffffffffffffffff811161026e57611967903690600401610b15565b5050608082019261198361197a85612cd9565b63ffffffff1690565b4211611b4f57611992836123cf565b73ffffffffffffffffffffffffffffffffffffffff30911603611afd576060830135468103611acb57507faed0ae635eda11553af2dc98f5e5308e49abc5a2c0cae5c9a949b7927d77c40560c084013503611aa1576119f9916119f59184614897565b1590565b611a7757611a72610e2b82610e26611a6b611a3b610e1260e07f3448bbc2203c608599ad448eeb1007cea04b788ac631f9f558e8dd01a3c27b3d980185612c62565b92611a4e845167ffffffffffffffff1690565b906020850151611a656020604088015193016123cf565b926149b3565b5095612cd9565b0390a2005b7f8baa579f0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f0b6901880000000000000000000000000000000000000000000000000000000060005260046000fd5b7ff5ee213f000000000000000000000000000000000000000000000000000000006000526004524660245260445b6000fd5b611af9611b09846123cf565b7f30833ea50000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045230602452604490565b7f3e3fec280000000000000000000000000000000000000000000000000000000060005260046000fd5b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57611c77611bd47f45636f506f7274616c000000000000000000000000000000000000000000000961505e565b611bfd7f310000000000000000000000000000000000000000000000000000000000000161517c565b6020604051611c0c8282610308565b6000815281611c85818301947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083013687376040519788977f0f00000000000000000000000000000000000000000000000000000000000000895260e0858a015260e0890190610bbc565b908782036040890152610bbc565b91466060870152306080870152600060a087015285830360c0870152519182815201929160005b828110611cbb57505050500390f35b835185528695509381019392810192600101611cac565b3461026e5760206104b2611ce53661089e565b6109296104ac823592611cf78461025c565b6114a5611d06878301836125b1565b6040519485918983016127fe565b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435611d4a8161025c565b6024359060443567ffffffffffffffff811161026e57602092611d8f611d77611dae933690600401610415565b9360643592611d8584611201565b61057f3687610755565b505092611d9b84613b2e565b611da733923690610755565b9085614b43565b611db66144e1565b50604051908152f35b3461026e576020610886611dd23661089e565b610929610880823592611cf78461025c565b60e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560243567ffffffffffffffff811161026e57611e31903690600401610ff5565b9060443590606435608435611e45816104d0565b60a43591611e528361025c565b60c4359467ffffffffffffffff861161026e5761086996611e7a611e809736906004016103f7565b956132d7565b60405191829182611085565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000eba53db3b53e2ae621faae3bed4e7fcd11877eac168152f35b60807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e57600435611f318161025c565b60243567ffffffffffffffff811161026e57611f519036906004016103f7565b906044359167ffffffffffffffff831161026e57611f7661096f933690600401610415565b9060643592611f8484611201565b613338565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043567ffffffffffffffff811161026e57611fd661096f913690600401610890565b60243590611fe382611201565b610929612005823592611ff58461025c565b6114a561091a60208301836125b1565b91613338565b6120143661089e565b7faed0ae635eda11553af2dc98f5e5308e49abc5a2c0cae5c9a949b7927d77c405602082013503611aa157610e12816040612050930190612c62565b7f3448bbc2203c608599ad448eeb1007cea04b788ac631f9f558e8dd01a3c27b3d611a72610e2b67ffffffffffffffff845116936120a761209d6020830151966040840151978891612d02565b90963391886149db565b6120af6144e1565b5063ffffffff4216613491565b3461026e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043560005260046020526020604060002054604051908152f35b63ffffffff81160361026e57565b81601f8201121561026e5780359061212b826106b4565b926121396040519485610308565b82845260208085019360071b8301019181831161026e57602001925b828410612163575050505090565b60808483031261026e57602060809160405161217e816102ec565b8635815282870135838201526040870135604082015260608701356060820152815201930192612155565b91909160c08184031261026e576121be610349565b926121c882610273565b8452602082013567ffffffffffffffff811161026e57816121ea9184016103f7565b6020850152604082013567ffffffffffffffff811161026e578161220f918401610755565b60408501526060820135606085015261222a60808301610273565b608085015260a082013567ffffffffffffffff811161026e5761107e9201612114565b3461026e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e5760043561228881612106565b60243567ffffffffffffffff811161026e57610869916122af610e2b9236906004016121a9565b90613491565b60c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576004356122eb8161025c565b60443560243567ffffffffffffffff821161026e5761231161234e923690600401610415565b9260643561231e81611201565b6123456084359261232e846104d0565b60a4359461233b866104d0565b61057f3689610755565b50508095614503565b50604051908152602090f35b3461026e57610af461171d36610e37565b3461026e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026e576020600254604051908152f35b906123c8916123ba610412943690610755565b9160208151910120906124bb565b5050613b2e565b35610412816104d0565b6040513d6000823e3d90fd5b906020808351928381520192019060005b8181106124035750505090565b909192602061243b600192865190602060409273ffffffffffffffffffffffffffffffffffffffff8151168352015160208201520190565b94019291016123f6565b60c06080610412936020845267ffffffffffffffff815116602085015273ffffffffffffffffffffffffffffffffffffffff602082015116604085015273ffffffffffffffffffffffffffffffffffffffff604082015116606085015260608101518285015201519160a08082015201906123e5565b612551918093604051612502816124d6602082019485612445565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610308565b5190209283916124d6604051938492602084019687917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b51902092565b90612566916123ba3685610755565b505090816000526003602052600160ff6040600020541661258681610997565b1491821561259357505090565b61041292506125a190613b2e565b90613e69565b356104128161025c565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418136030182121561026e570190565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e57016020813591019167ffffffffffffffff821161026e578160061b3603831361026e57565b9160209082815201919060005b8181106126515750505090565b90919260408060019273ffffffffffffffffffffffffffffffffffffffff873561267a816104d0565b16815260208781013590820152019401929101612644565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0938186528686013760008582860101520116010190565b906020838281520160208260051b85010193836000915b8483106126f85750505050505090565b9091929394957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820301855286357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18436030181121561026e57830173ffffffffffffffffffffffffffffffffffffffff8135612775816104d0565b16825260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e578101906020823592019067ffffffffffffffff831161026e57823603821361026e57836040806127ea60209695879660608860019b01526060860191612692565b9301359101529801969501930191906126e8565b90602082528035602083015267ffffffffffffffff60208201356128218161025c565b16604083015273ffffffffffffffffffffffffffffffffffffffff604082013561284a816104d0565b1660608301526060810135608083015261287b61286a60808301836125e4565b60c060a086015260e0850191612637565b9060a08101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561026e570160208135910167ffffffffffffffff821161026e578160051b3603811361026e578360c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610412968603019101526126d1565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618136030182121561026e570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b908160061b918083046040149015171561297a57565b612935565b600801908160081161297a57565b9190820180921161297a57565b906129a482610386565b6129b16040519182610308565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06129df8294610386565b0190602036910137565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051156117295760200190565b80518210156117295760209160051b010190565b9267ffffffffffffffff610412959373ffffffffffffffffffffffffffffffffffffffff612a7b94168652166020850152608060408501526080840190610bbc565b916060818403910152610bbc565b8251939192612aa7612aa2612a9d87612964565b61297f565b61299a565b947f000000000000000000000000000000000000000000000000000000000000009260c01b602087015260005b818110612b5b5750505073ffffffffffffffffffffffffffffffffffffffff164793813b1561026e57612b3b94600094604051968795869485937fbcd58bd20000000000000000000000000000000000000000000000000000000085523360048601612a39565b03925af180156106af57612b4c5750565b806106a3600061027e93610308565b612b79612b688285612a25565b516000526004602052604060002090565b548015612bd5579081600192604860208460051b880101518460061b8c019060288201520152612ba98286612a25565b517fe6d8040a8a6bc519f4e5a42fb2677067c929ddbf2cca9287a44b23fb617a6f00600080a301612ad4565b611af9612be28386612a25565b517fdab74d1e00000000000000000000000000000000000000000000000000000000600052600452602490565b60405190610100820182811067ffffffffffffffff8211176102cb57604052606060e083600081526000602082015260006040820152600083820152600060808201528260a08201528260c08201520152565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026e570180359067ffffffffffffffff821161026e5760200191813603831361026e57565b9060208282031261026e57813567ffffffffffffffff811161026e5761041292016121a9565b3561041281612106565b612cfa90610412959397969492610969368a610755565b508096614503565b91929092612d178185516020870120856124bb565b50509384612d2481613b2e565b9481600052600360205260ff60406000205416612d4081610997565b60028114908115612e8b575b50612e5d5773ffffffffffffffffffffffffffffffffffffffff6020850151169273ffffffffffffffffffffffffffffffffffffffff6040860151169467ffffffffffffffff81511690612dc5608060608301519201519367ffffffffffffffff6040519616865260a0602087015260a0860190610bbc565b916040850152606084015282810360808401526020808351928381520192019060005b818110612e1b5750505090807f43974895be1bcec7344337863fa7de24a0d1c315c0a994f663fe0ee220ddc8e4920390a4565b9091926020612e53600192865190602060409273ffffffffffffffffffffffffffffffffffffffff8151168352015160208201520190565b9401929101612de8565b507f5eaf4c690000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60039150612e9881610997565b1438612d4c565b9080602083519182815201916020808360051b8301019401926000915b838310612ecb57505050505090565b9091929394602080827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0856001950301865288519073ffffffffffffffffffffffffffffffffffffffff8251168152604080612f34858501516060878601526060850190610bbc565b93015191015297019301930191939290612ebc565b9061041291602081528151602082015267ffffffffffffffff602083015116604082015273ffffffffffffffffffffffffffffffffffffffff60408301511660608201526060820151608082015260a0612fb1608084015160c08385015260e08401906123e5565b9201519060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082850301910152612e9f565b6130489067ffffffffffffffff8151166020820151604080519361303c85613010602082019586612f49565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101875286610308565b015192519020906124bb565b9192909190565b91908110156117295760051b0190565b519061027e8261025c565b519061027e826104d0565b81601f8201121561026e5780519061308c826106b4565b9261309a6040519485610308565b82845260208085019360061b8301019181831161026e57602001925b8284106130c4575050505090565b60408483031261026e57602060409182516130de816102af565b86516130e9816104d0565b815282870151838201528152019301926130b6565b81601f8201121561026e57805161311481610386565b926131226040519485610308565b8184526020828401011161026e576104129160208085019101610b99565b81601f8201121561026e57805190613157826106b4565b926131656040519485610308565b82845260208085019360051b8301019181831161026e5760208101935b83851061319157505050505090565b845167ffffffffffffffff811161026e57820160607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828603011261026e57604051916131dd836102d0565b60208201516131eb816104d0565b835260408201519267ffffffffffffffff841161026e576060836132168860208098819801016130fe565b8584015201516040820152815201940193613182565b60208183031261026e5780519067ffffffffffffffff821161026e570160c08183031261026e5761325b610349565b918151835261326c6020830161305f565b602084015261327d6040830161306a565b604084015260608201516060840152608082015167ffffffffffffffff811161026e57816132ac918401613075565b608084015260a082015167ffffffffffffffff811161026e576132cf9201613140565b60a082015290565b9290916132e892969495968461413b565b936040938451926132f98685610308565b600184527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0602085019601368737835115611729576104129552612a89565b6133569061334e61336293949695963690610755565b938491612d02565b94909233908685614b43565b61336a6144e1565b509190565b90613379826106b4565b6133866040519182610308565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06133b482946106b4565b019060005b8281106133c557505050565b6020906040516133d4816102ec565b600081526000838201526000604082015260006060820152828285010152016133b9565b6040805191906134089083610308565b60018252817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061343860016106b4565b019060005b82811061344957505050565b602090604051613458816102d0565b60008152600083820152606060408201528282850101520161343d565b92919061348c602091604086526040860190610bbc565b930152565b613499612c0f565b50604082019081519060606080830151519201511515600014613738576134cd6134c860ff60015b168461298d565b61336f565b9160005b8181106136b557506060845101519081613679575b505060208401926136626135f960208651818151910120938051604051613514816124d68682019485612445565b519020948561357761352e8c5167ffffffffffffffff1690565b926124d66040519384928884019687917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b519020946135996135866133f8565b99516124d6604051938492878401613475565b895167ffffffffffffffff169060608b015167ffffffffffffffff6135bc610367565b931683528483015260408201526135d289612a18565b526135dc88612a18565b5051015173ffffffffffffffffffffffffffffffffffffffff1690565b9561365560a061361761197a608085015167ffffffffffffffff1690565b92015194613642613626610376565b73ffffffffffffffffffffffffffffffffffffffff909a168a52565b4660208a015263ffffffff166040890152565b63ffffffff166060870152565b608085015260a084015260c083015260e082015290565b6136ad91613685610358565b90600082526020820152600060408201524660608201526136a68286612a25565b5283612a25565b5038806134e6565b806136eb6105a36105a36136d060019560808b510151612a25565b515173ffffffffffffffffffffffffffffffffffffffff1690565b60206136fc8360808a510151612a25565b510151613707610358565b9182526020820152600060408201524660608201526137268287612a25565b526137318186612a25565b50016134d1565b6134cd6134c860ff60006134c1565b9081604091031261026e57602060405191613761836102af565b805161376c816104d0565b835201516137798161025c565b602082015290565b61378b6002610997565b60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b6137c06001610997565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b9060a06138726104129367ffffffffffffffff81356138098161025c565b16845273ffffffffffffffffffffffffffffffffffffffff602082013561382f816104d0565b16602085015273ffffffffffffffffffffffffffffffffffffffff6040820135613858816104d0565b1660408501526060810135606085015260808101906125e4565b9190928160808201520191612637565b9073ffffffffffffffffffffffffffffffffffffffff6138af6020929594956040855260408501906137eb565b9416910152565b91906138cc6138c53684610755565b82856124bb565b929194905060408401926138e56105a36105a3866123cf565b604080517f99d145b2000000000000000000000000000000000000000000000000000000008152600481018990529591869060249082905afa9485156106af57600095613afd575b506139616020613951875173ffffffffffffffffffffffffffffffffffffffff1690565b96015167ffffffffffffffff1690565b67ffffffffffffffff8085169116141580613ade575b613a6a57505050506139898184614c84565b6139a56139a0846000526003602052604060002090565b613781565b6139b46105a36105a385613dbf565b803b1561026e57816000916139f994836040518097819582947f012c41ca00000000000000000000000000000000000000000000000000000000845260048401613882565b03925af19081156106af577fbb062c23e818de8ea9c157514eb098052cf36904bbe431cd50d4ec92264ca3ac9273ffffffffffffffffffffffffffffffffffffffff92613a55575b50604051938452169180602081015b0390a2565b806106a36000613a6493610308565b38613a41565b613a819396506105a39295506105a39194506123cf565b803b1561026e576040517ffc0eab9100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90931660048401526024830193909352604482015290600090829081838160648101612b3b565b5073ffffffffffffffffffffffffffffffffffffffff85161515613977565b613b2091955060403d604011613b27575b613b188183610308565b810190613747565b933861392d565b503d613b0e565b6105a3610412916124d6613c5e60c960405190613b4e6020820183610308565b80825261574060208301396124d6613bca604051613bb0816124d67f0000000000000000000000003fd339e58769a56d08dcd2683f9012e8812874766020830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b604051928391613bc4602084018097614d34565b90614d34565b5190206040519283916020830195307fff00000000000000000000000000000000000000000000000000000000000000889290605594927fff000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009216855260601b166001840152601583015260358201520190565b51902073ffffffffffffffffffffffffffffffffffffffff1690565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561026e570180359067ffffffffffffffff821161026e57602001918160061b3603831361026e57565b91908110156117295760061b0190565b919073ffffffffffffffffffffffffffffffffffffffff16918215613d915760808101613d0b8183613c7a565b92905060005b838110613d2057505050509050565b8573ffffffffffffffffffffffffffffffffffffffff613d4a83613d448787613c7a565b90613cce565b35613d54816104d0565b1614613d6257600101613d11565b857f9794df66000000000000000000000000000000000000000000000000000000006000526024906004526000fd5b827f9794df660000000000000000000000000000000000000000000000000000000060005260045260246000fd5b613dc881613b2e565b90813b15613dd4575090565b905060405160c98082019082821067ffffffffffffffff8311176102cb576020918391615740833973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003fd339e58769a56d08dcd2683f9012e8812874761681520301906000f580156106af5773ffffffffffffffffffffffffffffffffffffffff1690565b9081602091031261026e575190565b9060808201613e788184613c7a565b9390508231606082013511613f895760005b848110613e9b575050505050600190565b613eb1613eac82613d448686613c7a565b6123cf565b6020613ec183613d448787613c7a565b013590602060405180927f70a082310000000000000000000000000000000000000000000000000000000082528173ffffffffffffffffffffffffffffffffffffffff81613f2f8c6004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b0392165afa9081156106af57600091613f5b575b5010613f5157600101613e8a565b5050505050600090565b613f7c915060203d8111613f82575b613f748183610308565b810190613e5a565b38613f43565b503d613f6a565b50505050600090565b929082613f9f9185614d6f565b8260005260036020526040600020613fb76003610997565b60037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055613fef6105a36105a385613dbf565b803b1561026e578160009161403494836040518097819582947faadee52c00000000000000000000000000000000000000000000000000000000845260048401613882565b03925af19081156106af577f8d53c2b04800cf061b987a07179bb6c9730c05536b2f6a3a091fe62303682eb69273ffffffffffffffffffffffffffffffffffffffff92613a55575060405193845216918060208101613a50565b60208183031261026e5780519067ffffffffffffffff821161026e57019080601f8301121561026e5781516140c2816106b4565b926140d06040519485610308565b81845260208085019260051b8201019183831161026e5760208201905b8382106140fc57505050505090565b815167ffffffffffffffff811161026e5760209161411f878480948801016130fe565b8152019101906140ed565b906020610412928181520190612e9f565b909291614163614156602086015167ffffffffffffffff1690565b67ffffffffffffffff1690565b4211614487576124d66141f06040516020810190614185816124d68a85612f49565b5190209260405192839160208301957f000000000000000000000000000000000000000000000000000000000000009287917fffffffffffffffff0000000000000000000000000000000000000000000000006048949260c01b168352600883015260288201520190565b519020604084015173ffffffffffffffffffffffffffffffffffffffff163081036144445750810361441757614230816000526004602052604060002090565b546143ea5781156143c05781614250826000526004602052604060002090565b557fc471de166a60c0b81727dfa2f57d4fc3ad1b45b057c1f034b7058365613bde8d600080a360808101805151906060830190815180341061438f57507f000000000000000000000000eba53db3b53e2ae621faae3bed4e7fcd11877eac73ffffffffffffffffffffffffffffffffffffffff16929060005b8281106143485750505060009160a061431592519401516040519485809481937f760f2a0b0000000000000000000000000000000000000000000000000000000083526004830161412a565b03925af19081156106af5760009161432b575090565b61041291503d806000833e6143408183610308565b81019061408e565b806143896143596001938551612a25565b5187602061437e6105a3845173ffffffffffffffffffffffffffffffffffffffff1690565b920151913390614f0c565b016142c9565b7f172f1184000000000000000000000000000000000000000000000000000000006000523460045260245260446000fd5b7f69b3229a0000000000000000000000000000000000000000000000000000000060005260046000fd5b7f373d20790000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7f44d659bf0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b7fd16be7520000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045260246000fd5b7f408b22340000000000000000000000000000000000000000000000000000000060005260046000fd5b3d156144dc573d906144c282610386565b916144d06040519384610308565b82523d6000602084013e565b606090565b4780156144fd57600080808093335af16144f96144b1565b5090565b50600190565b93919091600083600052600360205260ff6040600020541661452481610997565b60028114801561470b575b6146d5578061453f600192610997565b146146cc575090602073ffffffffffffffffffffffffffffffffffffffff85936145a261456b87613dbf565b9860405196879485947f76a66d1b000000000000000000000000000000000000000000000000000000008652169160048501614733565b03813473ffffffffffffffffffffffffffffffffffffffff8a165af19182156106af5760009261469b575b501580614693575b614664579061463d827fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a9493614643575b60405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b0390a190565b61465f61465a846000526003602052604060002090565b6137b6565b614606565b7f07b9062000000000000000000000000000000000000000000000000000000000600052600482905260246000fd5b5080156145d5565b6146be91925060203d6020116146c5575b6146b68183610308565b81019061471e565b90386145cd565b503d6146ac565b95945050505050565b7f89939a210000000000000000000000000000000000000000000000000000000060005261470281610997565b60045260246000fd5b5061471581610997565b6003811461452f565b9081602091031261026e575161041281611201565b91939273ffffffffffffffffffffffffffffffffffffffff90816147616040946060875260608701906137eb565b9616602085015216910152565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000399dbd5df04f83103f77a58cba2b7c4d3cdede971630148061486e575b156147d6577f896d309903d7c8ee00d0c14a565221b22d65cf31d06a1706765a114114498ed390565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f2648237a1a02509aa35a842caa2dcd403357af537cbcb66a84381016b8bc3ddf60408201527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260a0815261486860c082610308565b51902090565b507f000000000000000000000000000000000000000000000000000000000000009246146147ad565b6105a36149a76148df946149a173ffffffffffffffffffffffffffffffffffffffff956149996149ad96600254906149916148d1826123cf565b6124d6602084019d8e6123cf565b9360408101359060608101356148f760808301612cd9565b61490360a08401612cd9565b9161492161491a60c08601359560e0810190612c62565b36916103c0565b6020815191012094604051998a9860208a019c8d95909998979463ffffffff9473ffffffffffffffffffffffffffffffffffffffff61010099958188966101208c019f8c521660208b0152166040890152606088015260808701521660a08501521660c083015260e08201520152565b519020615007565b9236916103c0565b90615048565b936123cf565b91161490565b6149c6836149d093600093979597612d02565b9490958587614b43565b6149d86144e1565b50565b9392919084600052600360205260ff604060002054166149fa81610997565b600281148015614b30575b6146d55780614a15600192610997565b14614b29576080614a2a606084015183615245565b920190815151906000925b828410614add57505050508015614aae5792614aa9847fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a94956146435760405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b0390a1565b7f07b9062000000000000000000000000000000000000000000000000000000000600052600484905260246000fd5b90919293600190614af56105a36136d0888651612a25565b81614b06575b509401929190614a35565b614b2391506020614b18888651612a25565b5101519088866152bc565b38614afb565b5050509050565b50614b3a81610997565b60038114614a05565b94939085600052600360205260ff60406000205416614b6181610997565b600281148015614c71575b6146d55780614b7c600192610997565b14614c69576080614b91606085015183615245565b930190815151906000925b828410614c1d57505050501580614c15575b614aae5792614aa9847fc1ed05721d27ad6b2555d61388ac393b120f5cc0e6009e53230e02c68e60064a94956146435760405193849384919273ffffffffffffffffffffffffffffffffffffffff6040929594606085019685521660208401521515910152565b508015614bae565b90919294600190614c356105a36136d0898651612a25565b81614c46575b509501929190614b9c565b614c6391506020614c58898651612a25565b5101519089866152bc565b38614c3b565b505050509050565b50614c7b81610997565b60038114614b6c565b600052600360205260ff60406000205416614c9e81610997565b80151580614d20575b614cf3575073ffffffffffffffffffffffffffffffffffffffff1615614cc957565b7fdbdf7dda0000000000000000000000000000000000000000000000000000000060005260046000fd5b7ffecf1ec00000000000000000000000000000000000000000000000000000000060005261470281610997565b50614d2a81610997565b6001811415614ca7565b90614d4760209282815194859201610b99565b0190565b929167ffffffffffffffff91606494614d6381610997565b60045260245216604452565b91614d8e614d87846000526003602052604060002090565b5460ff1690565b91614da16105a36105a3604085016123cf565b604080517f99d145b2000000000000000000000000000000000000000000000000000000008152600481018790529291839060249082905afa9182156106af57600092614eeb575b5067ffffffffffffffff80614e09602085015167ffffffffffffffff1690565b921691161490811591614ecb575b50614e795750614e2681610997565b8015908115614e65575b50614e385750565b7f6b7aeaaa0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60019150614e7281610997565b1438614e30565b909150614e88614156826125a7565b4210614e92575050565b90614e9f611af9926125a7565b907fc6a2514b000000000000000000000000000000000000000000000000000000006000524290614d4b565b5173ffffffffffffffffffffffffffffffffffffffff1615905038614e17565b614f0591925060403d604011613b2757613b188183610308565b9038614de9565b60009173ffffffffffffffffffffffffffffffffffffffff8392614f90959682604051988160208b01967f23b872dd0000000000000000000000000000000000000000000000000000000088521660248b0152166044890152606488015260648752614f79608488610308565b1694519082865af1614f896144b1565b90836156a2565b8051908115159182614fe9575b5050614fa65750565b7f5274afe70000000000000000000000000000000000000000000000000000000060005273ffffffffffffffffffffffffffffffffffffffff1660045260246000fd5b6150009250906020806119f593830101910161471e565b3880614f9d565b60429061501261476e565b90604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b610412916150559161547e565b909291926154b3565b60ff811461506f5761041290615580565b5060405160008054908160011c9160018116908115615172575b602084108214615145578385528492916020840191811561510e57506001146150ba575b5061041292500382610308565b600080805291507f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8483106150f75750610412935001386150ad565b8054828401528593506020909201916001016150e3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682525061041293151560051b019050386150ad565b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526022600452fd5b92607f1692615089565b60ff811461518d5761041290615580565b506040516000600154908160011c916001811690811561522e575b602084108214615145578385528492916020840191811561510e57506001146151d8575061041292500382610308565b6001600090815291507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8483106152175750610412935001386150ad565b805482840152859350602090920191600101615203565b92607f16926151a8565b9190820391821161297a57565b8031828110156152b457820391821161297a5761526234836155fa565b908180158015615275575b505050101590565b60009283928392839283916152aa575b73ffffffffffffffffffffffffffffffffffffffff1690f1156106af5738818161526d565b6108fc9150615285565b505050600190565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301528416939192909190602083602481885afa9283156106af5760009361545d575b5085831015615452576153328387615238565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152306024820152906020826044818a5afa9081156106af5761539d92600092615431575b506155fa565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201529095602090829060249082905afa80156106af5761541a966154089260009261543157506155fa565b9384918261541f575b5050505061298d565b101590565b61542893614f0c565b38828180615411565b61544b91925060203d602011613f8257613f748183610308565b9038615397565b505050505050600190565b61547791935060203d602011613f8257613f748183610308565b913861531f565b81519190604183036154a85761304892506020820151906060604084015193015160001a9061560c565b505060009160029190565b6154bc81610997565b806154c5575050565b6154ce81610997565b60018103615500577ff645eedf0000000000000000000000000000000000000000000000000000000060005260046000fd5b61550981610997565b6002810361553f57507ffce698f70000000000000000000000000000000000000000000000000000000060005260045260246000fd5b8061554b600392610997565b146155535750565b7fd78bce0c0000000000000000000000000000000000000000000000000000000060005260045260246000fd5b60ff811690601f82116155d057604080519261559c8285610308565b602084527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe060208501920136833783525290565b7fb3512b0c0000000000000000000000000000000000000000000000000000000060005260046000fd5b9080821015615607575090565b905090565b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411615696579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156106af5760005173ffffffffffffffffffffffffffffffffffffffff81161561568a5790600090600090565b50600090600190600090565b50505060009160039190565b906156e157508051156156b757805190602001fd5b7f1425ea420000000000000000000000000000000000000000000000000000000060005260046000fd5b81511580615736575b6156f2575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000006000521660045260246000fd5b50803b156156ea56fe60a034606257601f60c938819003918201601f19168301916001600160401b03831184841017606757808492602094604052833981010312606257516001600160a01b0381168103606257608052604051604b9081607e82396080518160150152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040523615604957366000803760008036817f00000000000000000000000000000000000000000000000000000000000000005af43d6000803e156044573d6000f35b3d6000fd5b00
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in S
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.