Overview
MNT Balance
MNT Value
$0.00Latest 25 from a total of 2,294 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Publish And Fund | 76449258 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76445573 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76445566 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76445559 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76445549 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76445542 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76444785 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76444526 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76444515 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76444176 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76443840 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76442660 | 332 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398479 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398471 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398464 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398456 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398449 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398442 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398434 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398427 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398419 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398409 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398398 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398389 | 333 days ago | IN | 0 MNT | 0.00452 | ||||
| Publish And Fund | 76398381 | 333 days ago | IN | 0 MNT | 0.00452 |
Latest 5 internal transactions
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 76352506 | 334 days ago | Contract Creation | 0 MNT | |||
| 76292446 | 335 days ago | Contract Creation | 0 MNT | |||
| 76292446 | 335 days ago | Contract Creation | 0 MNT | |||
| 76292236 | 335 days ago | Contract Creation | 0 MNT | |||
| 76277696 | 336 days ago | Contract Creation | 0 MNT |
Cross-Chain Transactions
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xBFAE6C5c...d0F75aB8f The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Source Code (Solidity Standard Json-Input format)
/* -*- 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 {IIntentSource} from "./interfaces/IIntentSource.sol";
import {BaseProver} from "./prover/BaseProver.sol";
import {Intent, Route, Reward, Call} from "./types/Intent.sol";
import {Semver} from "./libs/Semver.sol";
import {Vault} from "./Vault.sol";
/**
* @title IntentSource
* @notice Source chain contract for the Eco Protocol's intent system
* @dev Used to create intents and withdraw associated rewards. Works in conjunction with
* an inbox contract on the destination chain. Verifies intent fulfillment through
* a prover contract on the source chain
* @dev This contract should not hold any funds or hold any roles for other contracts.
*/
contract IntentSource is IIntentSource, Semver {
using SafeERC20 for IERC20;
mapping(bytes32 intentHash => VaultStorage) public vaults;
constructor() {}
/**
* @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
) external view returns (RewardStatus status) {
return RewardStatus(vaults[intentHash].state.status);
}
/**
* @notice Retrieves vault state for a given intent hash
* @param intentHash Hash of the intent to query
* @return VaultState struct containing vault information
*/
function getVaultState(
bytes32 intentHash
) external view returns (VaultState memory) {
return vaults[intentHash].state;
}
/**
* @notice Retrieves the permitContact address funding an intent
*/
function getPermitContract(
bytes32 intentHash
) external view returns (address) {
return vaults[intentHash].permitContract;
}
/**
* @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 calldata intent
)
public
pure
returns (bytes32 intentHash, bytes32 routeHash, bytes32 rewardHash)
{
routeHash = keccak256(abi.encode(intent.route));
rewardHash = keccak256(abi.encode(intent.reward));
intentHash = keccak256(abi.encodePacked(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
) external view returns (address) {
(bytes32 intentHash, bytes32 routeHash, ) = getIntentHash(intent);
return _getIntentVaultAddress(intentHash, routeHash, intent.reward);
}
/**
* @notice Creates an intent without funding
* @param intent The complete intent struct to be published
* @return intentHash Hash of the created intent
*/
function publish(
Intent calldata intent
) external returns (bytes32 intentHash) {
(intentHash, , ) = getIntentHash(intent);
VaultState memory state = vaults[intentHash].state;
_validateAndPublishIntent(intent, intentHash, state);
}
/**
* @notice Creates and funds an intent in a single transaction
* @param intent The complete intent struct to be published and funded
* @return intentHash Hash of the created and funded intent
*/
function publishAndFund(
Intent calldata intent,
bool allowPartial
) external payable returns (bytes32 intentHash) {
bytes32 routeHash;
(intentHash, routeHash, ) = getIntentHash(intent);
VaultState memory state = vaults[intentHash].state;
_validateInitialFundingState(state, intentHash);
_validateSourceChain(intent.route.source, intentHash);
_validateAndPublishIntent(intent, intentHash, state);
address vault = _getIntentVaultAddress(
intentHash,
routeHash,
intent.reward
);
_fundIntent(intentHash, intent.reward, vault, msg.sender, allowPartial);
_returnExcessEth(intentHash, address(this).balance);
}
/**
* @notice Funds an existing intent
* @param routeHash Hash of the route component
* @param reward Reward structure containing distribution details
* @return intentHash Hash of the funded intent
*/
function fund(
bytes32 routeHash,
Reward calldata reward,
bool allowPartial
) external payable returns (bytes32 intentHash) {
bytes32 rewardHash = keccak256(abi.encode(reward));
intentHash = keccak256(abi.encodePacked(routeHash, rewardHash));
VaultState memory state = vaults[intentHash].state;
_validateInitialFundingState(state, intentHash);
address vault = _getIntentVaultAddress(intentHash, routeHash, reward);
_fundIntent(intentHash, reward, vault, msg.sender, allowPartial);
_returnExcessEth(intentHash, address(this).balance);
}
/**
* @notice Funds an intent for a user with permit/allowance
* @param routeHash Hash of the route component
* @param reward Reward structure containing distribution details
* @param funder Address to fund the intent from
* @param permitContact Address of the permitContact instance
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the funded intent
*/
function fundFor(
bytes32 routeHash,
Reward calldata reward,
address funder,
address permitContact,
bool allowPartial
) external returns (bytes32 intentHash) {
bytes32 rewardHash = keccak256(abi.encode(reward));
intentHash = keccak256(abi.encodePacked(routeHash, rewardHash));
VaultState memory state = vaults[intentHash].state;
address vault = _getIntentVaultAddress(intentHash, routeHash, reward);
_fundIntentFor(
state,
reward,
intentHash,
routeHash,
vault,
funder,
permitContact,
allowPartial
);
}
/**
* @notice Creates and funds an intent using permit/allowance
* @param intent The complete intent struct
* @param funder Address to fund the intent from
* @param permitContact Address of the permitContact instance
* @param allowPartial Whether to allow partial funding
* @return intentHash Hash of the created and funded intent
*/
function publishAndFundFor(
Intent calldata intent,
address funder,
address permitContact,
bool allowPartial
) external returns (bytes32 intentHash) {
bytes32 routeHash;
(intentHash, routeHash, ) = getIntentHash(intent);
VaultState memory state = vaults[intentHash].state;
_validateAndPublishIntent(intent, intentHash, state);
_validateSourceChain(intent.route.source, intentHash);
address vault = _getIntentVaultAddress(
intentHash,
routeHash,
intent.reward
);
_fundIntentFor(
state,
intent.reward,
intentHash,
routeHash,
vault,
funder,
permitContact,
allowPartial
);
}
/**
* @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
) external view returns (bool) {
if (intent.route.source != block.chainid) return false;
(bytes32 intentHash, bytes32 routeHash, ) = getIntentHash(intent);
address vault = _getIntentVaultAddress(
intentHash,
routeHash,
intent.reward
);
return _isRewardFunded(intent.reward, vault);
}
/**
* @notice Withdraws rewards associated with an intent to its claimant
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
*/
function withdrawRewards(bytes32 routeHash, Reward calldata reward) public {
bytes32 rewardHash = keccak256(abi.encode(reward));
bytes32 intentHash = keccak256(abi.encodePacked(routeHash, rewardHash));
address claimant = BaseProver(reward.prover).provenIntents(intentHash);
VaultState memory state = vaults[intentHash].state;
// Claim the rewards if the intent has not been claimed
if (
claimant != address(0) &&
state.status != uint8(RewardStatus.Claimed) &&
state.status != uint8(RewardStatus.Refunded)
) {
state.status = uint8(RewardStatus.Claimed);
state.mode = uint8(VaultMode.Claim);
state.allowPartialFunding = 0;
state.usePermit = 0;
state.target = claimant;
vaults[intentHash].state = state;
emit Withdrawal(intentHash, claimant);
new Vault{salt: routeHash}(intentHash, reward);
return;
}
if (claimant == address(0)) {
revert UnauthorizedWithdrawal(intentHash);
} else {
revert RewardsAlreadyWithdrawn(intentHash);
}
}
/**
* @notice Batch withdraws multiple intents
* @param routeHashes Array of route hashes for the intents
* @param rewards Array of reward structures for the intents
*/
function batchWithdraw(
bytes32[] calldata routeHashes,
Reward[] calldata rewards
) external {
uint256 length = routeHashes.length;
if (length != rewards.length) {
revert ArrayLengthMismatch();
}
for (uint256 i = 0; i < length; ++i) {
withdrawRewards(routeHashes[i], rewards[i]);
}
}
/**
* @notice Refunds rewards to the intent creator
* @param routeHash Hash of the intent's route
* @param reward Reward structure of the intent
*/
function refund(bytes32 routeHash, Reward calldata reward) external {
bytes32 rewardHash = keccak256(abi.encode(reward));
bytes32 intentHash = keccak256(abi.encodePacked(routeHash, rewardHash));
VaultState memory state = vaults[intentHash].state;
if (
state.status != uint8(RewardStatus.Claimed) &&
state.status != uint8(RewardStatus.Refunded) &&
block.timestamp <= reward.deadline
) {
revert IntentNotExpired(intentHash);
}
if (state.status != uint8(RewardStatus.Claimed)) {
state.status = uint8(RewardStatus.Refunded);
}
state.mode = uint8(VaultMode.Refund);
state.allowPartialFunding = 0;
state.usePermit = 0;
state.target = address(0);
vaults[intentHash].state = state;
emit Refund(intentHash, reward.creator);
new Vault{salt: routeHash}(intentHash, reward);
}
/**
* @notice Recover tokens that were sent to the intent vault by mistake
* @dev Must not be among the intent's rewards
* @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(
bytes32 routeHash,
Reward calldata reward,
address token
) external {
if (token == address(0)) {
revert InvalidRefundToken();
}
bytes32 rewardHash = keccak256(abi.encode(reward));
bytes32 intentHash = keccak256(abi.encodePacked(routeHash, rewardHash));
VaultState memory state = vaults[intentHash].state;
// selfdestruct() will refund all native tokens to the creator
// we can't refund native intents before the claim/refund happens
// because deploying and destructing the vault will refund the native reward prematurely
if (
state.status != uint8(RewardStatus.Claimed) &&
state.status != uint8(RewardStatus.Refunded) &&
reward.nativeValue > 0
) {
revert IntentNotClaimed(intentHash);
}
// Check if the token is part of the reward
for (uint256 i = 0; i < reward.tokens.length; ++i) {
if (reward.tokens[i].token == token) {
revert InvalidRefundToken();
}
}
state.mode = uint8(VaultMode.RecoverToken);
state.allowPartialFunding = 0;
state.usePermit = 0;
state.target = token;
vaults[intentHash].state = state;
emit Refund(intentHash, reward.creator);
new Vault{salt: routeHash}(intentHash, reward);
}
/**
* @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.nativeValue) 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 Calculates the deterministic address of an intent vault using CREATE2
* @dev Follows EIP-1014 for address calculation
* @param intentHash Hash of the full intent
* @param routeHash Hash of the route component
* @param reward Reward structure
* @return The calculated vault address
*/
function _getIntentVaultAddress(
bytes32 intentHash,
bytes32 routeHash,
Reward calldata reward
) internal view returns (address) {
/* 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 */
return
address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
address(this),
routeHash,
keccak256(
abi.encodePacked(
type(Vault).creationCode,
abi.encode(intentHash, reward)
)
)
)
)
)
)
);
}
/**
* @notice Validates and publishes a new intent
* @param intent The intent to validate and publish
* @param intentHash Hash of the intent
* @param state Current vault state
*/
function _validateAndPublishIntent(
Intent calldata intent,
bytes32 intentHash,
VaultState memory state
) internal {
if (
state.status == uint8(RewardStatus.Claimed) ||
state.status == uint8(RewardStatus.Refunded)
) {
revert IntentAlreadyExists(intentHash);
}
emit IntentCreated(
intentHash,
intent.route.salt,
intent.route.source,
intent.route.destination,
intent.route.inbox,
intent.route.tokens,
intent.route.calls,
intent.reward.creator,
intent.reward.prover,
intent.reward.deadline,
intent.reward.nativeValue,
intent.reward.tokens
);
}
/**
* @notice Disabling fundFor for native intents
* @dev Deploying vault in Fund mode might cause a loss of native reward
* @param reward Reward structure to validate
* @param vault Address of the intent vault
* @param intentHash Hash of the intent
*/
function _disableNativeReward(
Reward calldata reward,
address vault,
bytes32 intentHash
) internal view {
// selfdestruct() will refund all native tokens to the creator
// we can't use Fund mode for intents with native value
// because deploying and destructing the vault will refund the native reward prematurely
if (reward.nativeValue > 0 && vault.balance > 0) {
revert CannotFundForWithNativeReward(intentHash);
}
}
/**
* @notice Validates the initial funding state
* @param state Current vault state
* @param intentHash Hash of the intent
*/
function _validateInitialFundingState(
VaultState memory state,
bytes32 intentHash
) internal pure {
if (state.status != uint8(RewardStatus.Initial)) {
revert IntentAlreadyFunded(intentHash);
}
}
/**
* @notice Validates the funding state for partial funding
* @param state Current vault state
* @param intentHash Hash of the intent
*/
function _validateFundingState(
VaultState memory state,
bytes32 intentHash
) internal pure {
if (
state.status != uint8(RewardStatus.Initial) &&
state.status != uint8(RewardStatus.PartiallyFunded)
) {
revert IntentAlreadyFunded(intentHash);
}
}
/**
* @notice Handles the funding of an intent
* @param intentHash Hash of the intent
* @param reward Reward structure to fund
* @param vault Address of the intent vault
* @param funder Address providing the funds
*/
function _fundIntent(
bytes32 intentHash,
Reward calldata reward,
address vault,
address funder,
bool allowPartial
) internal {
emit IntentFunded(intentHash, msg.sender);
if (reward.nativeValue > 0) {
if (msg.value < reward.nativeValue) {
revert InsufficientNativeReward(intentHash);
}
payable(vault).transfer(reward.nativeValue);
}
uint256 rewardsLength = reward.tokens.length;
// Iterate through each token in the reward structure
for (uint256 i; i < rewardsLength; ++i) {
// Get token address and required amount for current reward
address token = reward.tokens[i].token;
uint256 amount = reward.tokens[i].amount;
uint256 balance = IERC20(token).balanceOf(vault);
// Only proceed if vault needs more tokens and we have permission to transfer them
if (amount > balance) {
// Calculate how many more tokens the vault needs to be fully funded
uint256 remainingAmount = amount - balance;
// Check how many tokens this contract is allowed to transfer from funding source
uint256 allowance = IERC20(token).allowance(
funder,
address(this)
);
uint256 transferAmount;
// Calculate transfer amount as minimum of what's needed and what's allowed
if (allowance >= amount) {
transferAmount = amount;
} else if (allowPartial) {
transferAmount = allowance;
} else {
revert InsufficientTokenAllowance(token, funder, amount);
}
if (transferAmount > 0) {
// Transfer tokens from funding source to vault using safe transfer
IERC20(token).safeTransferFrom(
funder,
vault,
transferAmount
);
}
}
}
}
function _fundIntentFor(
VaultState memory state,
Reward calldata reward,
bytes32 intentHash,
bytes32 routeHash,
address vault,
address funder,
address permitContact,
bool allowPartial
) internal {
_disableNativeReward(reward, vault, intentHash);
_validateFundingState(state, intentHash);
if (state.status == uint8(RewardStatus.Initial)) {
state.status = allowPartial
? uint8(RewardStatus.PartiallyFunded)
: uint8(RewardStatus.Funded);
}
state.mode = uint8(VaultMode.Fund);
state.allowPartialFunding = allowPartial ? 1 : 0;
state.usePermit = permitContact != address(0) ? 1 : 0;
state.target = funder;
if (permitContact != address(0)) {
vaults[intentHash].permitContract = permitContact;
}
vaults[intentHash].state = state;
new Vault{salt: routeHash}(intentHash, reward);
if (state.status == uint8(RewardStatus.Funded)) {
emit IntentFunded(intentHash, funder);
} else if (
state.status == uint8(RewardStatus.PartiallyFunded) &&
_isRewardFunded(reward, vault)
) {
state.status = uint8(RewardStatus.Funded);
vaults[intentHash].state = state;
emit IntentFunded(intentHash, funder);
} else {
emit IntentPartiallyFunded(intentHash, funder);
}
}
/**
* @notice Validates that the intent is being published on correct chain
* @param sourceChain Chain ID specified in the intent
* @param intentHash Hash of the intent
*/
function _validateSourceChain(
uint256 sourceChain,
bytes32 intentHash
) internal view {
if (sourceChain != block.chainid) {
revert WrongSourceChain(intentHash);
}
}
/**
* @notice Returns excess ETH to the sender
* @param intentHash Hash of the intent
* @param amount Amount of ETH to return
*/
function _returnExcessEth(bytes32 intentHash, uint256 amount) internal {
if (amount > 0) {
(bool success, ) = payable(msg.sender).call{value: amount}("");
if (!success) revert NativeRewardTransferFailed(intentHash);
}
}
}/* -*- 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 {IIntentSource} from "./interfaces/IIntentSource.sol";
import {IVault} from "./interfaces/IVault.sol";
import {IPermit} from "./interfaces/IPermit.sol";
import {Reward} from "./types/Intent.sol";
/**
* @title Vault
* @notice A self-destructing contract that handles reward distribution for intents
* @dev Created by IntentSource for each intent, handles token and native currency transfers,
* then self-destructs after distributing rewards
*/
contract Vault is IVault {
using SafeERC20 for IERC20;
/**
* @notice Creates and immediately executes reward distribution
* @dev Contract self-destructs after execution
*/
constructor(bytes32 intentHash, Reward memory reward) {
IIntentSource intentSource = IIntentSource(msg.sender);
VaultState memory state = intentSource.getVaultState(intentHash);
if (state.mode == uint8(VaultMode.Fund)) {
_fundIntent(intentSource, intentHash, state, reward);
} else if (state.mode == uint8(VaultMode.Claim)) {
_processRewardTokens(reward, state.target);
_processNativeReward(reward, state.target);
} else if (state.mode == uint8(VaultMode.Refund)) {
_processRewardTokens(reward, reward.creator);
} else if (state.mode == uint8(VaultMode.RecoverToken)) {
_recoverToken(state.target, reward.creator);
}
selfdestruct(payable(reward.creator));
}
/**
* @dev Funds the intent with required tokens
*/
function _fundIntent(
IIntentSource intentSource,
bytes32 intentHash,
VaultState memory state,
Reward memory reward
) internal {
// Get the address that is providing the tokens for funding
address fundingSource = state.target;
uint256 rewardsLength = reward.tokens.length;
address permitContract;
if (state.usePermit == 1) {
permitContract = intentSource.getPermitContract(intentHash);
}
// Iterate through each token in the reward structure
for (uint256 i; i < rewardsLength; ++i) {
// Get token address and required amount for current reward
address token = reward.tokens[i].token;
uint256 amount = reward.tokens[i].amount;
uint256 balance = IERC20(token).balanceOf(address(this));
// Only proceed if vault needs more tokens and we have permission to transfer them
if (amount > balance) {
// Calculate how many more tokens the vault needs to be fully funded
uint256 remainingAmount = amount - balance;
if (permitContract != address(0)) {
remainingAmount = _transferFromPermit(
IPermit(permitContract),
fundingSource,
token,
remainingAmount
);
}
if (remainingAmount > 0) {
_transferFrom(
fundingSource,
token,
remainingAmount,
state.allowPartialFunding
);
}
}
}
}
/**
* @dev Processes all reward tokens
*/
function _processRewardTokens(
Reward memory reward,
address claimant
) internal {
uint256 rewardsLength = reward.tokens.length;
for (uint256 i; i < rewardsLength; ++i) {
address token = reward.tokens[i].token;
uint256 amount = reward.tokens[i].amount;
uint256 balance = IERC20(token).balanceOf(address(this));
if (claimant == reward.creator || balance < amount) {
if (claimant != reward.creator) {
emit RewardTransferFailed(token, claimant, amount);
}
if (balance > 0) {
_tryTransfer(token, claimant, balance);
}
} else {
_tryTransfer(token, claimant, amount);
// Return excess balance to creator
if (balance > amount) {
_tryTransfer(token, reward.creator, balance - amount);
}
}
}
}
/**
* @dev Processes native token reward
*/
function _processNativeReward(
Reward memory reward,
address claimant
) internal {
if (reward.nativeValue > 0) {
uint256 amount = reward.nativeValue;
if (address(this).balance < reward.nativeValue) {
emit RewardTransferFailed(address(0), claimant, amount);
amount = address(this).balance;
}
(bool success, ) = payable(claimant).call{value: amount}("");
if (!success) {
emit RewardTransferFailed(address(0), claimant, amount);
}
}
}
/**
* @dev Processes refund token if specified
*/
function _recoverToken(address refundToken, address creator) internal {
uint256 refundAmount = IERC20(refundToken).balanceOf(address(this));
require(refundAmount > 0, ZeroRefundTokenBalance(refundToken));
IERC20(refundToken).safeTransfer(creator, refundAmount);
}
/**
* @notice Attempts to transfer tokens to a recipient, emitting an event on failure
* @dev Uses inline assembly to safely handle return data from token transfers
* @param token Address of the token being transferred
* @param to Address of the recipient
* @param amount Amount of tokens to transfer
*/
function _tryTransfer(address token, address to, uint256 amount) internal {
bytes memory data = abi.encodeWithSelector(
IERC20(token).transfer.selector,
to,
amount
);
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(
gas(),
token,
0,
add(data, 0x20),
mload(data),
0,
0x20
)
if not(iszero(success)) {
returnSize := returndatasize()
returnValue := mload(0)
}
}
if (
!success ||
(
returnSize == 0
? address(token).code.length == 0
: returnValue != 1
)
) {
emit RewardTransferFailed(token, to, amount);
}
}
/**
* @notice Transfers tokens from funding source to vault
* @param fundingSource Address that is providing the tokens for funding
* @param token Address of the token being transferred
* @param amount Amount of tokens to transfer
* @param allowPartialFunding Whether to allow partial funding
*/
function _transferFrom(
address fundingSource,
address token,
uint256 amount,
uint8 allowPartialFunding
) internal {
// Check how many tokens this contract is allowed to transfer from funding source
uint256 allowance = IERC20(token).allowance(
fundingSource,
address(this)
);
uint256 transferAmount;
// Calculate transfer amount as minimum of what's needed and what's allowed
if (allowance >= amount) {
transferAmount = amount;
} else if (allowPartialFunding == 1) {
transferAmount = allowance;
} else {
revert InsufficientTokenAllowance(token, fundingSource, amount);
}
if (transferAmount > 0) {
// Transfer tokens from funding source to vault using safe transfer
IERC20(token).safeTransferFrom(
fundingSource,
address(this),
transferAmount
);
}
}
/**
* @notice Transfers tokens from funding source to vault using external Permit contract
* @param permit Permit2 like contract to use for token transfer
* @param fundingSource Address that is providing the tokens for funding
* @param token Address of the token being transferred
* @param amount Amount of tokens to transfer
* @return remainingAmount Amount of tokens that still need to be transferred
*/
function _transferFromPermit(
IPermit permit,
address fundingSource,
address token,
uint256 amount
) internal returns (uint256 remainingAmount) {
// Check how many tokens this contract is allowed to transfer from funding source
(uint160 allowance, , ) = permit.allowance(
fundingSource,
token,
address(this)
);
uint256 transferAmount;
// Calculate transfer amount as minimum of what's needed and what's allowed
if (allowance >= amount) {
transferAmount = amount;
remainingAmount = 0;
} else {
transferAmount = allowance;
remainingAmount = amount - allowance;
}
if (transferAmount > 0) {
// Transfer tokens from funding source to vault using Permit.transferFrom
permit.transferFrom(
fundingSource,
address(this),
uint160(transferAmount),
token
);
}
}
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ISemver} from "./ISemver.sol";
import {IVaultStorage} from "./IVaultStorage.sol";
import {Intent, Reward, Call, 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 an inbox contract on the destination chain
* and a prover contract for verification. It handles intent creation, funding,
* and reward distribution.
*/
interface IIntentSource is ISemver, IVaultStorage {
/**
* @notice Indicates an attempt to fund an intent on an incorrect chain
* @param intentHash The hash of the intent that was incorrectly targeted
*/
error WrongSourceChain(bytes32 intentHash);
/**
* @notice Indicates a failed native token transfer during reward distribution
* @param intentHash The hash of the intent whose reward transfer failed
*/
error NativeRewardTransferFailed(bytes32 intentHash);
/**
* @notice Indicates an attempt to publish a duplicate intent
* @param intentHash The hash of the pre-existing intent
*/
error IntentAlreadyExists(bytes32 intentHash);
/**
* @notice Indicates an attempt to fund an already funded intent
* @param intentHash The hash of the previously funded intent
*/
error IntentAlreadyFunded(bytes32 intentHash);
/**
* @notice Indicates insufficient native token payment for the required reward
* @param intentHash The hash of the intent with insufficient funding
*/
error InsufficientNativeReward(bytes32 intentHash);
/**
* @notice Thrown when the vault has insufficient token allowance for reward funding
*/
error InsufficientTokenAllowance(
address token,
address spender,
uint256 amount
);
/**
* @notice Indicates an invalid attempt to fund with native tokens
* @param intentHash The hash of the intent that cannot accept native tokens
*/
error CannotFundForWithNativeReward(bytes32 intentHash);
/**
* @notice Indicates an unauthorized reward withdrawal attempt
* @param _hash The hash of the intent with protected rewards
*/
error UnauthorizedWithdrawal(bytes32 _hash);
/**
* @notice Indicates an attempt to withdraw already claimed rewards
* @param _hash The hash of the intent with depleted rewards
*/
error RewardsAlreadyWithdrawn(bytes32 _hash);
/**
* @notice Indicates a premature withdrawal attempt before intent expiration
* @param intentHash The hash of the unexpired intent
*/
error IntentNotExpired(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 an invalid token specified for refund
*/
error InvalidRefundToken();
/**
* @notice Indicates mismatched array lengths in batch operations
*/
error ArrayLengthMismatch();
/**
* @notice Signals partial funding of an intent
* @param intentHash The hash of the partially funded intent
* @param fundingSource The address providing the partial funding
*/
event IntentPartiallyFunded(bytes32 intentHash, address fundingSource);
/**
* @notice Signals complete funding of an intent
* @param intentHash The hash of the fully funded intent
* @param fundingSource The address providing the complete funding
*/
event IntentFunded(bytes32 intentHash, address fundingSource);
/**
* @notice Signals the creation of a new cross-chain intent
* @param hash Unique identifier of the intent
* @param salt Creator-provided uniqueness factor
* @param source Source chain identifier
* @param destination Destination chain identifier
* @param inbox Address of the receiving contract on the destination chain
* @param routeTokens Required tokens for executing destination chain calls
* @param calls Instructions to execute on the destination chain
* @param creator Intent originator address
* @param prover Prover contract address
* @param deadline Timestamp for reward claim eligibility
* @param nativeValue Native token reward amount
* @param rewardTokens ERC20 token rewards with amounts
*/
event IntentCreated(
bytes32 indexed hash,
bytes32 salt,
uint256 source,
uint256 destination,
address inbox,
TokenAmount[] routeTokens,
Call[] calls,
address indexed creator,
address indexed prover,
uint256 deadline,
uint256 nativeValue,
TokenAmount[] rewardTokens
);
/**
* @notice Signals successful reward withdrawal
* @param _hash The hash of the claimed intent
* @param _recipient The address receiving the rewards
*/
event Withdrawal(bytes32 _hash, address indexed _recipient);
/**
* @notice Signals successful reward refund
* @param _hash The hash of the refunded intent
* @param _recipient The address receiving the refund
*/
event Refund(bytes32 _hash, address indexed _recipient);
/**
* @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 (RewardStatus status);
/**
* @notice Retrieves the current state of an intent's vault
* @param intentHash The hash of the intent
* @return Current vault state
*/
function getVaultState(
bytes32 intentHash
) external view returns (VaultState memory);
/**
* @notice Retrieves the permit contract for token transfers
* @param intentHash The hash of the intent
* @return Address of the permit contract
*/
function getPermitContract(
bytes32 intentHash
) external view returns (address);
/**
* @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 calldata intent
)
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 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
*/
function publish(
Intent calldata intent
) external returns (bytes32 intentHash);
/**
* @notice Creates and funds an intent in a single transaction
* @param intent The complete intent specification
* @return intentHash Unique identifier of the created and funded intent
*/
function publishAndFund(
Intent calldata intent,
bool allowPartial
) external payable returns (bytes32 intentHash);
/**
* @notice Funds an existing intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @return intentHash The hash of the funded intent
*/
function fund(
bytes32 routeHash,
Reward calldata reward,
bool allowPartial
) external payable returns (bytes32 intentHash);
/**
* @notice Funds an intent on behalf of another address using permit
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
* @param fundingAddress The address providing the funding
* @param permitContract The permit contract address for external token approvals
* @param allowPartial Whether to accept partial funding
* @return intentHash The hash of the funded intent
*/
function fundFor(
bytes32 routeHash,
Reward calldata reward,
address fundingAddress,
address permitContract,
bool allowPartial
) external returns (bytes32 intentHash);
/**
* @notice Creates and funds an intent on behalf of another address
* @param intent The complete intent specification
* @param funder The address providing the funding
* @param permitContact The permit contract for token approvals
* @param allowPartial Whether to accept partial funding
* @return intentHash The hash of the created and funded intent
*/
function publishAndFundFor(
Intent calldata intent,
address funder,
address permitContact,
bool allowPartial
) external returns (bytes32 intentHash);
/**
* @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 Claims rewards for a successfully fulfilled and proven intent
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
*/
function withdrawRewards(
bytes32 routeHash,
Reward calldata reward
) external;
/**
* @notice Claims rewards for multiple fulfilled and proven intents
* @param routeHashes Array of route component hashes
* @param rewards Array of corresponding reward specifications
*/
function batchWithdraw(
bytes32[] calldata routeHashes,
Reward[] calldata rewards
) external;
/**
* @notice Returns rewards to the intent creator
* @param routeHash The hash of the intent's route component
* @param reward The reward specification
*/
function refund(bytes32 routeHash, Reward calldata reward) external;
/**
* @notice Recovers mistakenly transferred tokens from the intent vault
* @dev Token must not be part of the intent's reward structure
* @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(
bytes32 routeHash,
Reward calldata reward,
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;
}// 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 Types of proofs that can validate intent fulfillment
* @param Storage Traditional storage-based proof mechanism
* @param Hyperlane Proof using Hyperlane's cross-chain messaging
*/
enum ProofType {
Storage,
Hyperlane
}
/**
* @notice Emitted when an intent is successfully proven
* @param _hash Hash of the proven intent
* @param _claimant Address eligible to claim the intent's rewards
*/
event IntentProven(bytes32 indexed _hash, address indexed _claimant);
/**
* @notice Gets the proof mechanism type used by this prover
* @return ProofType enum indicating the prover's mechanism
*/
function getProofType() external pure returns (ProofType);
/**
* @notice Gets the address eligible to claim rewards for a proven intent
* @param intentHash Hash of the intent to query
* @return Address of the claimant, or zero address if unproven
*/
function getIntentClaimant(
bytes32 intentHash
) external view returns (address);
}// 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);
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {IVaultStorage} from "./IVaultStorage.sol";
/**
* @title IVault
* @notice Interface defining errors for the Vault.sol contract
*/
interface IVault is IVaultStorage {
/**
* @notice Thrown when the vault has insufficient token allowance for reward funding
* @param token The token address
* @param spender The spender address
* @param amount The amount of tokens required
*/
error InsufficientTokenAllowance(
address token,
address spender,
uint256 amount
);
/**
* @notice Thrown when the vault has zero balance of the refund token
* @param token The token address
*/
error ZeroRefundTokenBalance(address token);
/**
* @notice Thrown when the vault is not able to properly reward the claimant
* @dev For edge cases where the reward balance is not sufficient etc
*/
event RewardTransferFailed(
address indexed token,
address indexed to,
uint256 amount
);
}/* -*- c-basic-offset: 4 -*- */
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/**
* @title IVaultStorage
* @notice Interface for the storage layout of the Vault contract
*/
interface IVaultStorage {
enum RewardStatus {
Initial,
PartiallyFunded,
Funded,
Claimed,
Refunded
}
/**
* @notice Mode of the vault contract
*/
enum VaultMode {
Fund,
Claim,
Refund,
RecoverToken
}
/**
* @notice Status of the vault contract
* @dev Tracks the current mode and funding status
* @param status Current status of the vault
* @param mode Current mode of the vault
* @param allowPartial Whether partial funding is allowed
* @param usePermit Whether permit is enabled
* @param target Address of the funder in Fund, claimant in Claim or refund token in RecoverToken mode
*/
struct VaultState {
uint8 status; // RewardStatus
uint8 mode; // VaultMode
uint8 allowPartialFunding; // boolean
uint8 usePermit; // boolean
address target; // funder, claimant or refund token address
}
/**
* @notice Storage for the vault contract
* @dev Tracks the current state and permit contract instance
* @param state Current state of the vault
* @param permitContract Address of the permit contract instance
*/
struct VaultStorage {
VaultState state; // 1 bytes32 storage slot
address permitContract; // permit instance when enabled
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;
import {ISemver} from "../interfaces/ISemver.sol";
abstract contract Semver is ISemver {
function version() external pure returns (string memory) { return "1.15.0-2e287b3"; }
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {IProver} from "../interfaces/IProver.sol";
/**
* @title BaseProver
* @notice Base implementation for intent proving contracts
* @dev Provides core storage and functionality for tracking proven intents
* and their claimants
*/
abstract contract BaseProver is IProver {
/**
* @notice Mapping from intent hash to address eligible to claim rewards
* @dev Zero address indicates intent hasn't been proven
*/
mapping(bytes32 => address) public provenIntents;
/**
* @notice Gets the address eligible to claim rewards for a given intent
* @param intentHash Hash of the intent to query
* @return Address of the claimant, or zero address if unproven
*/
function getIntentClaimant(
bytes32 intentHash
) external view override returns (address) {
return provenIntents[intentHash];
}
}/* -*- 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 source Chain ID where the intent originated
* @param destination Target chain ID where the calls should be executed
* @param inbox Address of the inbox contract on the destination chain that receives messages
* @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;
uint256 source;
uint256 destination;
address inbox;
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 creator Address that created the intent and has authority to modify/cancel
* @param prover Address of the prover contract that must approve execution
* @param deadline Timestamp after which the intent can no longer be executed
* @param nativeValue Amount of native tokens offered as reward
* @param tokens Array of ERC20 tokens and amounts offered as additional rewards
*/
struct Reward {
address creator;
address prover;
uint256 deadline;
uint256 nativeValue;
TokenAmount[] tokens;
}
/**
* @notice Complete cross-chain intent combining routing and reward information
* @dev Main structure used to process and execute cross-chain messages
* @param route Routing and execution instructions
* @param reward Reward and validation parameters
*/
struct Intent {
Route route;
Reward reward;
}// 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/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) (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/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();
}
}
}{
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none",
"useLiteralContent": false
},
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"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/",
"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/"
],
"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":"bytes32","name":"intentHash","type":"bytes32"}],"name":"CannotFundForWithNativeReward","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"InsufficientNativeReward","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InsufficientTokenAllowance","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentAlreadyExists","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentAlreadyFunded","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentNotClaimed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"IntentNotExpired","type":"error"},{"inputs":[],"name":"InvalidRefundToken","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"NativeRewardTransferFailed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"RewardsAlreadyWithdrawn","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"UnauthorizedWithdrawal","type":"error"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"WrongSourceChain","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"source","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"destination","type":"uint256"},{"indexed":false,"internalType":"address","name":"inbox","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct TokenAmount[]","name":"routeTokens","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"indexed":false,"internalType":"struct Call[]","name":"calls","type":"tuple[]"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"prover","type":"address"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeValue","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":"IntentCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"fundingSource","type":"address"}],"name":"IntentFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"fundingSource","type":"address"}],"name":"IntentPartiallyFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"}],"name":"Refund","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_hash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"_recipient","type":"address"}],"name":"Withdrawal","type":"event"},{"inputs":[{"internalType":"bytes32[]","name":"routeHashes","type":"bytes32[]"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"routeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"funder","type":"address"},{"internalType":"address","name":"permitContact","type":"address"},{"internalType":"bool","name":"allowPartial","type":"bool"}],"name":"fundFor","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"getPermitContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"getRewardStatus","outputs":[{"internalType":"enum IVaultStorage.RewardStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"getVaultState","outputs":[{"components":[{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint8","name":"allowPartialFunding","type":"uint8"},{"internalType":"uint8","name":"usePermit","type":"uint8"},{"internalType":"address","name":"target","type":"address"}],"internalType":"struct IVaultStorage.VaultState","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"source","type":"uint256"},{"internalType":"uint256","name":"destination","type":"uint256"},{"internalType":"address","name":"inbox","type":"address"},{"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":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"address","name":"funder","type":"address"},{"internalType":"address","name":"permitContact","type":"address"},{"internalType":"bool","name":"allowPartial","type":"bool"}],"name":"publishAndFundFor","outputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"bytes32","name":"intentHash","type":"bytes32"}],"name":"vaults","outputs":[{"components":[{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint8","name":"allowPartialFunding","type":"uint8"},{"internalType":"uint8","name":"usePermit","type":"uint8"},{"internalType":"address","name":"target","type":"address"}],"internalType":"struct IVaultStorage.VaultState","name":"state","type":"tuple"},{"internalType":"address","name":"permitContract","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"routeHash","type":"bytes32"},{"components":[{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"prover","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"nativeValue","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":"withdrawRewards","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
0x608060405234601c57600e6020565b61552061002c823961552090f35b6026565b60405190565b600080fdfe60806040526004361015610013575b610d49565b61001e60003561012d565b8063111980f7146101285780631299d61714610123578063251043bf1461011e5780632c308f52146101195780634f1c807014610114578063526a72aa1461010f57806354fd4d501461010a578063695a461c1461010557806369f7cdc61461010057806381a09d34146100fb5780638616615e146100f657806393a359e9146100f157806396c5c272146100ec578063a900c652146100e7578063ab4b583e146100e2578063cca23bf2146100dd5763fb4035f60361000e57610d11565b610ca8565b610a1d565b6109a2565b61096d565b610915565b6108be565b610835565b61076a565b6106d4565b6105b2565b6104e3565b610405565b6103d1565b610350565b6102d2565b610222565b60e01c90565b60405190565b600080fd5b600080fd5b90565b61014f81610143565b0361015657565b600080fd5b9050359061016882610146565b565b600080fd5b908160a091031261017d5790565b61016a565b151590565b61019081610182565b0361019757565b600080fd5b905035906101a982610187565b565b90916060828403126101fa576101c4836000840161015b565b9260208301359067ffffffffffffffff82116101f5576101e9816101f293860161016f565b9360400161019c565b90565b61013e565b610139565b61020890610143565b9052565b9190610220906000602085019401906101ff565b565b61024a6102396102333660046101ab565b91610fde565b610241610133565b9182918261020c565b0390f35b600080fd5b9060208282031261026d5761026a9160000161015b565b90565b610139565b634e487b7160e01b600052602160045260246000fd5b6005111561029257565b610272565b906102a182610288565b565b6102ac90610297565b90565b6102b8906102a3565b9052565b91906102d0906000602085019401906102af565b565b34610302576102fe6102ed6102e8366004610253565b6110d6565b6102f5610133565b918291826102bc565b0390f35b61024e565b908160409103126103155790565b61016a565b9060208282031261034b57600082013567ffffffffffffffff8111610346576103439201610307565b90565b61013e565b610139565b346103805761037c61036b61036636600461031a565b611101565b610373610133565b9182918261020c565b0390f35b61024e565b9190916040818403126103c65761039f836000830161015b565b92602082013567ffffffffffffffff81116103c1576103be920161016f565b90565b61013e565b610139565b60000190565b34610400576103ea6103e4366004610385565b90611405565b6103f2610133565b806103fc816103cb565b0390f35b61024e565b346104345761041e610418366004610385565b906116ef565b610426610133565b80610430816103cb565b0390f35b61024e565b60018060a01b031690565b61044d90610439565b90565b61045981610444565b0361046057565b600080fd5b9050359061047282610450565b565b919060a0838203126104de5761048d816000850161015b565b92602081013567ffffffffffffffff81116104d957826104ae91830161016f565b926104d66104bf8460408501610465565b936104cd8160608601610465565b9360800161019c565b90565b61013e565b610139565b34610517576105136105026104f9366004610474565b93929092611a17565b61050a610133565b9182918261020c565b0390f35b61024e565b600091031261052757565b610139565b5190565b60209181520190565b60005b83811061054d575050906000910152565b80602091830151818501520161053c565b601f801991011690565b6105876105906020936105959361057e8161052c565b93848093610530565b95869101610539565b61055e565b0190565b6105af9160208201916000818403910152610568565b90565b346105e2576105c236600461051c565b6105de6105cd611b62565b6105d5610133565b91829182610599565b0390f35b61024e565b600080fd5b600080fd5b600080fd5b909182601f830112156106305781359167ffffffffffffffff831161062b57602001926020830284011161062657565b6105f1565b6105ec565b6105e7565b909182601f8301121561066f5781359167ffffffffffffffff831161066a57602001926020830284011161066557565b6105f1565b6105ec565b6105e7565b90916040828403126106cf57600082013567ffffffffffffffff81116106ca57836106a09184016105f6565b929093602082013567ffffffffffffffff81116106c5576106c19201610635565b9091565b61013e565b61013e565b610139565b34610706576106f06106e7366004610674565b92919091611c2b565b6106f8610133565b80610702816103cb565b0390f35b61024e565b60808183031261076557600081013567ffffffffffffffff81116107605782610735918301610307565b9261075d6107468460208501610465565b936107548160408601610465565b9360600161019c565b90565b61013e565b610139565b3461079e5761079a61078961078036600461070b565b92919091611cfa565b610791610133565b9182918261020c565b0390f35b61024e565b60ff1690565b6107b2906107a3565b9052565b6107bf90610444565b9052565b9060808061081d936107dd600082015160008601906107a9565b6107ef602082015160208601906107a9565b610801604082015160408601906107a9565b610813606082015160608601906107a9565b01519101906107b6565b565b919061083390600060a085019401906107c3565b565b346108655761086161085061084b366004610253565b611dfb565b610858610133565b9182918261081f565b0390f35b61024e565b90916060828403126108b957610883836000840161015b565b9260208301359067ffffffffffffffff82116108b4576108a8816108b193860161016f565b93604001610465565b90565b61013e565b610139565b346108ed576108d76108d136600461086a565b91611e7c565b6108df610133565b806108e9816103cb565b0390f35b61024e565b6108fb90610182565b9052565b9190610913906000602085019401906108f2565b565b346109455761094161093061092b36600461031a565b6121a2565b610938610133565b918291826108ff565b0390f35b61024e565b61095390610444565b9052565b919061096b9060006020850194019061094a565b565b3461099d5761099961098861098336600461031a565b612221565b610990610133565b91829182610957565b0390f35b61024e565b346109d2576109ce6109bd6109b8366004610253565b612252565b6109c5610133565b91829182610957565b0390f35b61024e565b9190604083820312610a185760008301359067ffffffffffffffff8211610a1357610a0781610a10938601610307565b9360200161019c565b90565b61013e565b610139565b610a45610a34610a2e3660046109d7565b90612274565b610a3c610133565b9182918261020c565b0390f35b610a5290610143565b90565b90610a5f90610a49565b600052602052604060002090565b60001c90565b60ff1690565b610a85610a8a91610a6d565b610a73565b90565b610a979054610a79565b90565b90610aa4906107a3565b9052565b60081c90565b610aba610abf91610aa8565b610a73565b90565b610acc9054610aae565b90565b60101c90565b610ae1610ae691610acf565b610a73565b90565b610af39054610ad5565b90565b60181c90565b610b08610b0d91610af6565b610a73565b90565b610b1a9054610afc565b90565b60201c90565b60018060a01b031690565b610b3a610b3f91610b1d565b610b23565b90565b610b4c9054610b2e565b90565b90610b5990610444565b9052565b634e487b7160e01b600052604160045260246000fd5b90610b7d9061055e565b810190811067ffffffffffffffff821117610b9757604052565b610b5d565b90610baf610ba8610133565b9283610b73565b565b610bbb60a0610b9c565b90565b90610c3a610c316000610bcf610bb1565b94610be6610bde838301610a8d565b838801610a9a565b610bfd610bf4838301610ac2565b60208801610a9a565b610c14610c0b838301610ae9565b60408801610a9a565b610c2b610c22838301610b10565b60608801610a9a565b01610b42565b60808401610b4f565b565b610c48610c4d91610a6d565b610b23565b90565b610c5a9054610c3c565b90565b610c68906000610a55565b90610c816001610c7a60008501610bbe565b9301610c50565b90565b9160a0610ca6929493610c9f60c082019660008301906107c3565b019061094a565b565b34610cd957610cc0610cbb366004610253565b610c5d565b90610cd5610ccc610133565b92839283610c84565b0390f35b61024e565b604090610d08610d0f9496959396610cfe606084019860008501906101ff565b60208301906101ff565b01906101ff565b565b34610d4457610d40610d2c610d2736600461031a565b6125d9565b610d37939193610133565b93849384610cde565b0390f35b61024e565b600080fd5b600090565b50610d62906020810190610465565b90565b90565b610d7181610d65565b03610d7857565b600080fd5b90503590610d8a82610d68565b565b50610d9b906020810190610d7d565b90565b610da790610d65565b9052565b600080fd5b600080fd5b600080fd5b9035600160200382360303811215610dfb57016020813591019167ffffffffffffffff8211610df6576040820236038313610df157565b610db0565b610dab565b610db5565b60209181520190565b90565b906020610e39610e4193610e30610e266000830183610d53565b60008601906107b6565b82810190610d8c565b910190610d9e565b565b90610e5081604093610e0c565b0190565b5090565b60400190565b91610e6c82610e7292610e00565b92610e09565b90816000905b828210610e86575050505090565b90919293610ea8610ea2600192610e9d8886610e54565b610e43565b95610e58565b920190929192610e78565b610f3f91610f3160a0820192610ed9610ecf6000830183610d53565b60008501906107b6565b610ef3610ee96020830183610d53565b60208501906107b6565b610f0d610f036040830183610d8c565b6040850190610d9e565b610f27610f1d6060830183610d8c565b6060850190610d9e565b6080810190610dba565b916080818503910152610e5e565b90565b610f589160208201916000818403910152610eb3565b90565b60200190565b5190565b90565b610f74610f7991610143565b610f65565b9052565b602081610f8f610f9793839695610f68565b018092610f68565b0190565b610fa490610bbe565b90565b90565b610fbe610fb9610fc392610439565b610fa7565b610439565b90565b610fcf90610faa565b90565b610fdb90610fc6565b90565b92919061109f91610fed610d4e565b5061109561100c61101b84611000610133565b92839160208301610f42565b60208201810382520382610b73565b61102d61102782610f61565b91610f5b565b206110588761104961103d610133565b93849260208401610f7d565b60208201810382520382610b73565b61106a61106482610f61565b91610f5b565b209561108c611085600061107f818b90610a55565b01610f9b565b88906126ca565b8690849161283c565b8592339293612a69565b6110b3826110ac30610fd2565b3190612e5a565b565b600090565b6110ce6110c96110d3926107a3565b610fa7565b610297565b90565b6110f96000806110f26110fe946110eb6110b5565b5082610a55565b0101610a8d565b6110ba565b90565b9061110a610d4e565b50611138611117836125d9565b505092611130600061112a818790610a55565b01610f9b565b849091613093565b565b61114490516107a3565b90565b3561115181610d68565b90565b6004111561115e57565b610272565b9061116d82611154565b565b61117890611163565b90565b90565b61119261118d6111979261117b565b610fa7565b6107a3565b90565b6111ae6111a96111b39261117b565b610fa7565b610439565b90565b6111bf9061119a565b90565b60001b90565b906111d460ff916111c2565b9181191691161790565b6111f26111ed6111f7926107a3565b610fa7565b6107a3565b90565b90565b9061121261120d611219926111de565b6111fa565b82546111c8565b9055565b60081b90565b9061123061ff009161121d565b9181191691161790565b9061124f61124a611256926111de565b6111fa565b8254611223565b9055565b60101b90565b9061126e62ff00009161125a565b9181191691161790565b9061128d611288611294926111de565b6111fa565b8254611260565b9055565b60181b90565b906112ad63ff00000091611298565b9181191691161790565b906112cc6112c76112d3926111de565b6111fa565b825461129e565b9055565b6112e19051610444565b90565b60201b90565b90611300640100000000600160c01b03916112e4565b9181191691161790565b61131390610fc6565b90565b90565b9061132e6113296113359261130a565b611316565b82546112ea565b9055565b906113ac608060006113b29461135c82820161135684880161113a565b906111fd565b61137482820161136e6020880161113a565b9061123a565b61138c8282016113866040880161113a565b90611278565b6113a482820161139e6060880161113a565b906112b7565b0192016112d7565b90611319565b565b906113be91611339565b565b356113ca81610450565b90565b916113f1926113e4604082019360008301906101ff565b6020818403910152610eb3565b90565b6113fc610133565b3d6000823e3d90fd5b9061142161143082611415610133565b92839160208301610f42565b60208201810382520382610b73565b61144261143c82610f61565b91610f5b565b2061146d8361145e611452610133565b93849260208401610f7d565b60208201810382520382610b73565b61147f61147982610f61565b91610f5b565b20916114976000611491818690610a55565b01610f9b565b6114a36000820161113a565b6114be6114b86114b360036102a3565b6107a3565b916107a3565b141580611668575b80611642575b61162257806114e0600061156c930161113a565b6114fb6114f56114f060036102a3565b6107a3565b916107a3565b03611607575b61151761150e600261116f565b60208301610a9a565b61152d611524600061117e565b60408301610a9a565b61154361153a600061117e565b60608301610a9a565b61155961155060006111b6565b60808301610b4f565b6000611566818790610a55565b016113b4565b82611579600084016113c0565b6115b86115a67f0ba6f12b978882904e7444c7a8fcadd2d9f692a6a97aa18e5fb44c3bbc5801239261130a565b926115af610133565b9182918261020c565b0390a2916115c4610133565b916119a483019083821067ffffffffffffffff8311176116025783926115f1926119a4613b7c86396113cd565b03906000f5156115fd57565b6113f4565b610b5d565b61161d61161460046102a3565b60008301610a9a565b611501565b61163e8460009182916332567f1d60e21b83526004830161020c565b0390fd5b504261166161165b61165660408701611147565b610d65565b91610d65565b11156114cc565b506116756000820161113a565b61169061168a61168560046102a3565b6107a3565b916107a3565b14156114c6565b6116a090610faa565b90565b6116ac90611697565b90565b6116b890610fc6565b90565b60e01b90565b905051906116ce82610450565b565b906020828203126116ea576116e7916000016116c1565b90565b610139565b909161170c61171b84611700610133565b92839160208301610f42565b60208201810382520382610b73565b61172d61172782610f61565b91610f5b565b206117588361174961173d610133565b93849260208401610f7d565b60208201810382520382610b73565b61176a61176482610f61565b91610f5b565b20926117b6602061178c6117876117828386016113c0565b6116a3565b6116af565b6399d145b2906117ab889261179f610133565b958694859384936116bb565b83526004830161020c565b03915afa908115611a12576000916119e4575b50926117e160006117db818890610a55565b01610f9b565b846117fd6117f76117f260006111b6565b610444565b91610444565b1415806119b5575b80611986575b61187457858561182c61182661182160006111b6565b610444565b91610444565b146000146118545761185090600091829163dac420a360e01b83526004830161020c565b0390fd5b61187090600091829163313d14a960e11b83526004830161020c565b0390fd5b6118f69061189461188b60039897949596986102a3565b60008301610a9a565b6118aa6118a1600161116f565b60208301610a9a565b6118c06118b7600061117e565b60408301610a9a565b6118d66118cd600061117e565b60608301610a9a565b6118e38360808301610b4f565b60006118f0818890610a55565b016113b4565b83906119376119257f6653a45d3871e4110fa55dac0269f9f93a6d9078d402f7153594e50573d7f0cd9261130a565b9261192e610133565b9182918261020c565b0390a291611943610133565b916119a483019083821067ffffffffffffffff831117611981578392611970926119a4613b7c86396113cd565b03906000f51561197c57565b6113f4565b610b5d565b506119936000820161113a565b6119ae6119a86119a360046102a3565b6107a3565b916107a3565b141561180b565b506119c26000820161113a565b6119dd6119d76119d260036102a3565b6107a3565b916107a3565b1415611805565b611a05915060203d8111611a0b575b6119fd8183610b73565b8101906116d0565b386117c9565b503d6119f3565b6113f4565b9493909192611ad593611a28610d4e565b50611a44611a5385611a38610133565b92839160208301610f42565b60208201810382520382610b73565b611a65611a5f82610f61565b91610f5b565b20611a9088611a81611a75610133565b93849260208401610f7d565b60208201810382520382610b73565b611aa2611a9c82610f61565b91610f5b565b2096611aba6000611ab4818b90610a55565b01610f9b565b90611ac78982889161283c565b9195899192939495966132ee565b565b606090565b67ffffffffffffffff8111611afa57611af660209161055e565b0190565b610b5d565b90611b11611b0c83611adc565b610b9c565b918252565b60007f312e31352e302d32653238376233000000000000000000000000000000000000910152565b611b48600e611aff565b90611b5560208301611b16565b565b611b5f611b3e565b90565b611b6a611ad7565b50611b73611b57565b90565b5090565b5090565b611b92611b8d611b979261117b565b610fa7565b610d65565b90565b6001611ba69101610d65565b90565b634e487b7160e01b600052603260045260246000fd5b9190811015611bcf576020020190565b611ba9565b35611bde81610146565b90565b600080fd5b600080fd5b600080fd5b903590600160a00381360303821215611c07570190565b611be1565b90821015611c26576020611c239202810190611bf0565b90565b611ba9565b93929193611c3a818390611b76565b9384611c58611c52611c4d898890611b7a565b610d65565b91610d65565b03611cc157611c676000611b7e565b5b80611c7b611c7588610d65565b91610d65565b1015611cb857611cb390611cae611c9c611c9786888591611bbf565b611bd4565b611ca88a898591611c0c565b906116ef565b611b9a565b611c68565b50945050505050565b600063512509d360e11b815280611cda600482016103cb565b0390fd5b903590600160c00381360303821215611cf5570190565b611be1565b909392611d9a92611d09610d4e565b50611d12610d4e565b50611d1c836125d9565b50969096611d366000611d30818b90610a55565b01610f9b565b90611d43868a8491613093565b611d66611d5f6020611d59896000810190611cde565b01611147565b8a9061361a565b611d8e611d828a83611d7c8a6020810190611bf0565b9161283c565b92966020810190611bf0565b899192939495966132ee565b565b600090565b600090565b611dae610bb1565b9060208080808086611dbe611d9c565b815201611dc9611d9c565b815201611dd4611d9c565b815201611ddf611d9c565b815201611dea611da1565b81525050565b611df8611da6565b90565b6000611e13611e1992611e0c611df0565b5082610a55565b01610f9b565b90565b903590600160200381360303821215611e5e570180359067ffffffffffffffff8211611e5957602001916040820236038313611e5457565b611beb565b611be6565b611be1565b5090565b9190811015611e77576040020190565b611ba9565b9282611e99611e93611e8e60006111b6565b610444565b91610444565b1461218057611eb9611ec883611ead610133565b92839160208301610f42565b60208201810382520382610b73565b611eda611ed482610f61565b91610f5b565b20611f0585611ef6611eea610133565b93849260208401610f7d565b60208201810382520382610b73565b611f17611f1182610f61565b91610f5b565b20611f2e6000611f28818490610a55565b01610f9b565b94611f3b6000870161113a565b611f56611f50611f4b60036102a3565b6107a3565b916107a3565b141580612151575b8061212b575b61210b57611f726000611b7e565b5b80611f9c611f96611f91611f8b896080810190611e1c565b90611e63565b610d65565b91610d65565b101561200757611fc56000611fbf611fb8886080810190611e1c565b8591611e67565b016113c0565b611fd7611fd188610444565b91610444565b14611fea57611fe590611b9a565b611f73565b600063cd91597b60e01b815280612003600482016103cb565b0390fd5b50919461205d612070929561202861201f600361116f565b60208501610a9a565b61203e612035600061117e565b60408501610a9a565b61205461204b600061117e565b60608501610a9a565b60808301610b4f565b600061206a818790610a55565b016113b4565b8261207d600084016113c0565b6120bc6120aa7f0ba6f12b978882904e7444c7a8fcadd2d9f692a6a97aa18e5fb44c3bbc5801239261130a565b926120b3610133565b9182918261020c565b0390a2916120c8610133565b916119a483019083821067ffffffffffffffff8311176121065783926120f5926119a4613b7c86396113cd565b03906000f51561210157565b6113f4565b610b5d565b6121278260009182916335bd755560e11b83526004830161020c565b0390fd5b5061213860608501611147565b61214b6121456000611b7e565b91610d65565b11611f64565b5061215e6000870161113a565b61217961217361216e60046102a3565b6107a3565b916107a3565b1415611f5e565b600063cd91597b60e01b815280612199600482016103cb565b0390fd5b600090565b6121aa61219d565b506121c460206121be836000810190611cde565b01611147565b6121d66121d046610d65565b91610d65565b03612216578061220e6122036121ee612213946125d9565b506121fd856020810190611bf0565b9161283c565b916020810190611bf0565b613654565b90565b50600090565b600090565b61224961224f9161223061221c565b5061223a816125d9565b50929092916020810190611bf0565b9161283c565b90565b600161226b6122719261226361221c565b506000610a55565b01610c50565b90565b61231a906123039392612285610d4e565b5061228e610d4e565b50612298826125d9565b509590956122ed6122b560006122af818b90610a55565b01610f9b565b6122c0818a906126ca565b6122e36122dc60206122d6896000810190611cde565b01611147565b8a9061361a565b8590899091613093565b86906122fd856020810190611bf0565b9161283c565b61231286936020810190611bf0565b339293612a69565b61232e8261232730610fd2565b3190612e5a565b565b5061233f90602081019061015b565b90565b61234b90610143565b9052565b903560016020038236030381121561239057016020813591019167ffffffffffffffff821161238b57602082023603831361238657565b610db0565b610dab565b610db5565b60209181520190565b90565b90356001602003823603038112156123e257016020813591019167ffffffffffffffff82116123dd5760018202360383136123d857565b610db0565b610dab565b610db5565b60209181520190565b90826000939282370152565b91906124168161240f8161241b956123e7565b80956123f0565b61055e565b0190565b9061247790604061246f6124656060840161244a6124406000890189610d53565b60008701906107b6565b61245760208801886123a1565b9086830360208801526123fc565b9482810190610d8c565b910190610d9e565b90565b906124849161241f565b90565b903560016060038236030381121561249d570190565b610db5565b60200190565b91816124b391612395565b90816124c46020830284019461239e565b92836000925b8484106124da5750505050505090565b90919293949560206125056124ff83856001950388526124fa8b88612487565b61247a565b986124a2565b9401940192949391906124ca565b6125bd916125af6125a460c0830161253b6125316000870187612330565b6000860190612342565b61255561254b6020870187610d8c565b6020860190610d9e565b61256f6125656040870187610d8c565b6040860190610d9e565b61258961257f6060870187610d53565b60608601906107b6565b6125966080860186610dba565b908583036080870152610e5e565b9260a081019061234f565b9160a08185039101526124a8565b90565b6125d69160208201916000818403910152612513565b90565b6125e1610d4e565b506125ea610d4e565b506125f3610d4e565b50612666612675612652612625612634612611866000810190611cde565b612619610133565b928391602083016125c0565b60208201810382520382610b73565b61264661264082610f61565b91610f5b565b20936020810190611bf0565b61265a610133565b92839160208301610f42565b60208201810382520382610b73565b61268761268182610f61565b91610f5b565b20816126b482916126a5612699610133565b93849260208401610f7d565b60208201810382520382610b73565b6126c66126c082610f61565b91610f5b565b2092565b60006126d6910161113a565b6126f16126eb6126e660006102a3565b6107a3565b916107a3565b036126f95750565b6127159060009182916330a4e71560e01b83526004830161020c565b0390fd5b905090565b61274361273a9260209261273181610f61565b94858093612719565b93849101610539565b0190565b6127559061275b939261271e565b9061271e565b90565b905090565b600060ff60f81b910152565b61277b6001809261275e565b61278481612763565b0190565b60601b90565b61279790612788565b90565b6127a39061278e565b90565b6127b26127b791610444565b61279a565b9052565b602093926127e460146127ec946127dc6127d5899661276f565b80926127a6565b018092610f68565b018092610f68565b0190565b6128046127ff61280992610d65565b610fa7565b610d65565b90565b61281861281d91610a6d565b6127f0565b90565b61283461282f61283992610d65565b610fa7565b610439565b90565b61291e90612906612923936128f76129289661285661221c565b506128d061286330610fd2565b93956128aa6119a49161287860208401610b9c565b92808452613b7c602085013961289b61288f610133565b958692602084016113cd565b60208201810382520384610b73565b6128c16128b5610133565b93849260208401612747565b60208201810382520382610b73565b6128e26128dc82610f61565b91610f5b565b206128eb610133565b948593602085016127bb565b60208201810382520382610b73565b61291861291282610f61565b91610f5b565b2061280c565b612820565b610fc6565b90565b91602061294d929493612946604082019660008301906101ff565b019061094a565b565b61295890610faa565b90565b6129649061294f565b90565b61297090610fc6565b90565b600090565b61298190610faa565b90565b61298d90612978565b90565b61299990610fc6565b90565b905051906129a982610d68565b565b906020828203126129c5576129c29160000161299c565b90565b610139565b634e487b7160e01b600052601160045260246000fd5b6129ef6129f591939293610d65565b92610d65565b8203918211612a0057565b6129ca565b916020612a27929493612a206040820196600083019061094a565b019061094a565b565b612a3290610d65565b9052565b604090612a60612a679496959396612a566060840198600085019061094a565b602083019061094a565b0190612a29565b565b9493949291909280337f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d91612aa8612a9f610133565b9283928361292b565b0390a1612ab760608501611147565b612aca612ac46000611b7e565b91610d65565b11612d4b575b50612ae8612ae2846080810190611e1c565b90611e63565b93612af1612973565b5b80612b05612aff88610d65565b91610d65565b1015612d4257612b2e6000612b28612b21886080810190611e1c565b8591611e67565b016113c0565b612b516020612b4b612b44896080810190611e1c565b8691611e67565b01611147565b612b916020612b67612b6285612984565b612990565b6370a0823190612b868992612b7a610133565b958694859384936116bb565b835260048301610957565b03915afa908115612d3d57600091612d0f575b5081612bb8612bb283610d65565b91610d65565b11612bcf575b505050612bca90611b9a565b612af2565b612bd990826129e0565b50612beb612be683612984565b612990565b602063dd62ed3e918890612c19612c0130610fd2565b94612c24612c0d610133565b968795869485946116bb565b845260048401612a05565b03915afa908115612d0a57600091612cdc575b50612c40612973565b5080612c54612c4e84610d65565b91610d65565b1015600014612ca4575090612bca92915b80612c79612c736000611b7e565b91610d65565b11612c87575b829350612bbe565b612c93612c9d92612984565b90878791926137fb565b3880612c7f565b9089600014612cb9575090612bca9291612c65565b86612cd88491926000938493638f87ba6760e01b855260048501612a36565b0390fd5b612cfd915060203d8111612d03575b612cf58183610b73565b8101906129ab565b38612c37565b503d612ceb565b6113f4565b612d30915060203d8111612d36575b612d288183610b73565b8101906129ab565b38612ba4565b503d612d1e565b6113f4565b50945050505050565b34612d69612d63612d5e60608801611147565b610d65565b91610d65565b10612db457506000808080612d85612d808661295b565b612967565b612d9160608901611147565b90828215612dab575bf115612da65738612ad0565b6113f4565b506108fc612d9a565b612dd0906000918291631368c98360e11b83526004830161020c565b0390fd5b612de060008092612719565b0190565b612ded90612dd4565b90565b67ffffffffffffffff8111612e0e57612e0a60209161055e565b0190565b610b5d565b90612e25612e2083612df0565b610b9c565b918252565b606090565b3d600014612e4c57612e403d612e13565b903d6000602084013e5b565b612e54612e2a565b90612e4a565b9080612e6f612e696000611b7e565b91610d65565b11612e79575b5050565b600080612eb892612e91612e8c3361295b565b612967565b90612e9a610133565b9081612ea581612de4565b03925af1612eb1612e2f565b5015610182565b612ec25780612e75565b612ede90600091829163da9a84fd60e01b83526004830161020c565b0390fd5b903590600160200381360303821215612f24570180359067ffffffffffffffff8211612f1f57602001916020820236038313612f1a57565b611beb565b611be6565b611be1565b60209181520190565b91612f4082612f4692612f29565b92610e09565b90816000905b828210612f5a575050505090565b90919293612f7c612f76600192612f718886610e54565b610e43565b95610e58565b920190929192612f4c565b60209181520190565b9181612f9b91612f87565b9081612fac6020830284019461239e565b92836000925b848410612fc25750505050505090565b9091929394956020612fed612fe78385600195038852612fe28b88612487565b61247a565b986124a2565b940194019294939190612fb2565b9791906130909c9a966130789661305261306d979c9e9c6130486130829c9860408f61304161305f9a61303761012084019b60008501906101ff565b6020830190612a29565b0190612a29565b60608d019061094a565b8a830360808c0152612f32565b9187830360a0890152612f90565b9660c0850190612a29565b60e0830190612a29565b610100818503910152612f32565b90565b916130a06000820161113a565b6130bb6130b56130b060036102a3565b6107a3565b916107a3565b14908115613265575b5061324557906130e260006130dc8382810190611cde565b01611bd4565b906130fc60206130f6836000810190611cde565b01611147565b926131166040613110846000810190611cde565b01611147565b93613130606061312a856000810190611cde565b016113c0565b9361324061314f613145866000810190611cde565b6080810190611e1c565b9661316b613161886000810190611cde565b60a0810190612ee2565b9790986131876000613181846020810190611bf0565b016113c0565b986131a0602061319a8582810190611bf0565b016113c0565b9a6131ba60406131b4866020810190611bf0565b01611147565b926131ef6131e56131da60606131d4896020810190611bf0565b01611147565b966020810190611bf0565b6080810190611e1c565b97909661322e6132286132227fd802f2610d0c85b3f19be4413f3cf49de1d4e787edecd538274437a5b9aa648d9f610a49565b9f61130a565b9f61130a565b9f613237610133565b9c8d9c8d612ffb565b0390a4565b613261906000918291635eaf4c6960e01b83526004830161020c565b0390fd5b613272915060000161113a565b61328d61328761328260046102a3565b6107a3565b916107a3565b14386130c4565b90565b6132ab6132a66132b092613294565b610fa7565b6107a3565b90565b906132c460018060a01b03916111c2565b9181191691161790565b906132e36132de6132ea9261130a565b611316565b82546132b3565b9055565b94969590939291956133028585899161384b565b61330d8688906138b7565b6133196000870161113a565b61333461332e61332960006102a3565b6107a3565b916107a3565b146135e4575b613350613347600061116f565b60208801610a9a565b6000146135d25761336e6133646001613297565b5b60408701610a9a565b8061338a61338461337f60006111b6565b610444565b91610444565b14156000146135c0576133aa6133a06001613297565b5b60608701610a9a565b6133b78760808701610b4f565b806133d36133cd6133c860006111b6565b610444565b91610444565b036135a2575b506133f18460006133eb818990610a55565b016113b4565b8483906133fc610133565b916119a483019083821067ffffffffffffffff83111761359d578392613429926119a4613b7c86396113cd565b03906000f5156135985761343f6000840161113a565b61345a61345461344f60026102a3565b6107a3565b916107a3565b146000146134a257505050907f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d9161349c613493610133565b9283928361292b565b0390a15b565b6134ae6000840161113a565b6134c96134c36134be60016102a3565b6107a3565b916107a3565b149182613587575b505060001461354757613507906134f46134eb60026102a3565b60008301610a9a565b6000613501818590610a55565b016113b4565b907f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d9161353e613535610133565b9283928361292b565b0390a15b6134a0565b50907f97cf148f008486c490afd3b522e2398d5039247c7fffe81fcae2a8c6ee6221039161357f613576610133565b9283928361292b565b0390a1613542565b6135919250613654565b38806134d1565b6113f4565b610b5d565b6135ba9060016135b460008990610a55565b016132ce565b386133d9565b6133aa6135cd600061117e565b6133a1565b61336e6135df600061117e565b613365565b80600014613608576136036135f960016102a3565b5b60008801610a9a565b61333a565b61360361361560026102a3565b6135fa565b61362c61362646610d65565b91610d65565b036136345750565b6136509060009182916305c2a22560e21b83526004830161020c565b0390fd5b61365c61219d565b5061367461366e826080810190611e1c565b90611e63565b91803161369461368e61368960608601611147565b610d65565b91610d65565b106137c2576136a36000611b7e565b5b806136b76136b186610d65565b91610d65565b10156137b9576136e060006136da6136d3866080810190611e1c565b8591611e67565b016113c0565b613742602061371861371361370d836137076137008b6080810190611e1c565b8a91611e67565b01611147565b94612984565b612990565b6370a0823190613737879261372b610133565b958694859384936116bb565b835260048301610957565b03915afa9081156137b45761376a9161376491600091613786575b5092610d65565b91610d65565b1061377d5761377890611b9a565b6136a4565b50505050600090565b6137a7915060203d81116137ad575b61379f8183610b73565b8101906129ab565b3861375d565b503d613795565b6113f4565b50505050600190565b505050600090565b63ffffffff1690565b63ffffffff60e01b1690565b6137f36137ee6137f8926137ca565b6116bb565b6137d3565b90565b6004926138356138499593613844939461381c6323b872dd929491926137df565b93613825610133565b9788956020870190815201612a36565b60208201810382520383610b73565b61396d565b565b60606138579101611147565b61386a6138646000611b7e565b91610d65565b11908161389a575b5061387a5750565b61389690600091829163d287282d60e01b83526004830161020c565b0390fd5b9050316138b06138aa6000611b7e565b91610d65565b1138613872565b6138c36000820161113a565b6138de6138d86138d360006102a3565b6107a3565b916107a3565b1415908161390f575b506138ef5750565b61390b9060009182916330a4e71560e01b83526004830161020c565b0390fd5b61391c915060000161113a565b61393761393161392c60016102a3565b6107a3565b916107a3565b1415386138e7565b9050519061394c82610187565b565b90602082820312613968576139659160000161393f565b90565b610139565b906139809061397b83612990565b613a00565b61398981610f61565b61399c6139966000611b7e565b91610d65565b141590816139d5575b506139ad5750565b6139b96139d191612990565b6000918291635274afe760e01b835260048301610957565b0390fd5b6139fa91506139f49060206139e982610f61565b81830101910161394e565b15610182565b386139a5565b90613a1f91613a0d612e2a565b5090613a196000611b7e565b91613a2e565b90565b613a2b90610fc6565b90565b9091613a38612e2a565b50613a4230613a22565b31613a55613a4f83610d65565b91610d65565b10613a825760008091613a7f948491602082019151925af190613a76612e2f565b90919091613aaa565b90565b613aa6613a8e30613a22565b600091829163cd78605960e01b835260048301610957565b0390fd5b90613abe90613ab7612e2a565b5015610182565b600014613acb5750613b32565b613ad482610f61565b613ae7613ae16000611b7e565b91610d65565b1480613b16575b613af6575090565b613b12906000918291639996b31560e01b835260048301610957565b0390fd5b50803b613b2c613b266000611b7e565b91610d65565b14613aee565b613b3b81610f61565b613b4e613b486000611b7e565b91610d65565b11600014613b5e57805190602001fd5b6000630a12f52160e11b815280613b77600482016103cb565b0390fdfe608060405234610017576100116102d3565b906104b2565b610022565b60405190565b600080fd5b601f801991011690565b634e487b7160e01b600052604160045260246000fd5b9061005190610027565b810190811060018060401b0382111761006957604052565b610031565b9061008161007a61001c565b9283610047565b565b600080fd5b600080fd5b90565b6100998161008d565b036100a057565b600080fd5b905051906100b282610090565b565b600080fd5b600080fd5b60018060a01b031690565b6100d2906100be565b90565b6100de816100c9565b036100e557565b600080fd5b905051906100f7826100d5565b565b90565b610105816100f9565b0361010c57565b600080fd5b9050519061011e826100fc565b565b600080fd5b60018060401b03811161013b5760208091020190565b610031565b600080fd5b91906040838203126101815761017a9061015f604061006e565b9361016d82600083016100ea565b6000860152602001610111565b6020830152565b6100b4565b9092919261019b61019682610125565b61006e565b9381855260406020860192028301928184116101da57915b8383106101c05750505050565b60206040916101cf8486610145565b8152019201916101b3565b610140565b9080601f830112156101fd578160206101fa93519101610186565b90565b610120565b91909160a08184031261028a5761021960a061006e565b9261022781600084016100ea565b600085015261023981602084016100ea565b602085015261024b8160408401610111565b604085015261025d8160608401610111565b6060850152608082015160018060401b0381116102855761027e92016101df565b6080830152565b6100b9565b6100b4565b9190916040818403126102ce576102a983600083016100a5565b92602082015160018060401b0381116102c9576102c69201610202565b90565b610088565b610083565b6102f16119a4803803806102e68161006e565b92833981019061028f565b9091565b90565b61030c610307610311926100be565b6102f5565b6100be565b90565b61031d906102f8565b90565b61032990610314565b90565b610335906102f8565b90565b6103419061032c565b90565b600080fd5b60e01b90565b60ff1690565b61035e8161034f565b0361036557565b600080fd5b9050519061037782610355565b565b919060a0838203126103eb576103e49061039360a061006e565b936103a1826000830161036a565b60008601526103b3826020830161036a565b60208601526103c5826040830161036a565b60408601526103d7826060830161036a565b60608601526080016100ea565b6080830152565b6100b4565b9060a08282031261040a5761040791600001610379565b90565b610083565b6104189061008d565b9052565b91906104309060006020850194019061040f565b565b61043a61001c565b3d6000823e3d90fd5b61044d905161034f565b90565b634e487b7160e01b600052602160045260246000fd5b6004111561047057565b610450565b9061047f82610466565b565b61048a90610475565b90565b61049790516100c9565b90565b6104a3906102f8565b90565b6104af9061049a565b90565b906104f56104bf33610320565b9160a06104cb84610338565b6381a09d34906104ea87926104de61001c565b96879485938493610349565b83526004830161041c565b03915afa9283156106905761055a94610555946000948591610662575b509161052060208401610443565b61053a61053461052f88610481565b61034f565b9161034f565b14851461055c579161054e92918492610dbd565b5b0161048d565b6104a6565bff5b505061056a60208201610443565b61058561057f61057a6001610481565b61034f565b9161034f565b1483146105bf576105b9906105a6836105a06080840161048d565b906108db565b6105b3608084920161048d565b90610bf0565b5b61054f565b6105cb60208201610443565b6105e66105e06105db6002610481565b61034f565b9161034f565b1483146106095750610603816105fd84840161048d565b906108db565b5b6105ba565b61061560208201610443565b61063061062a6106256003610481565b61034f565b9161034f565b1461063c575b50610604565b61064b608061065c920161048d565b61065684840161048d565b9061074e565b38610636565b610683915060a03d8111610689575b61067b8183610047565b8101906103f0565b38610512565b503d610671565b610432565b61069e906102f8565b90565b6106aa90610695565b90565b6106b69061032c565b90565b6106c29061032c565b90565b906020828203126106df576106dc91600001610111565b90565b610083565b6106ed906100c9565b9052565b9190610705906000602085019401906106e4565b565b90565b61071e61071961072392610707565b6102f5565b6100f9565b90565b1561072e5750565b61074a9060009182916308a285bb60e21b8352600483016106f1565b0390fd5b90610798916020610766610761836106a1565b6106ad565b6370a082319061078d610778306106b9565b9261078161001c565b97889485938493610349565b8352600483016106f1565b03915afa928315610811576107e1936107d9916000916107e3575b50916107d4836107cc6107c6600061070a565b916100f9565b118290610726565b6106a1565b919091611089565b565b610804915060203d811161080a575b6107fc8183610047565b8101906106c5565b386107b3565b503d6107f2565b610432565b5190565b600090565b600161082b91016100f9565b90565b634e487b7160e01b600052603260045260246000fd5b9061084e82610816565b81101561085f576020809102010190565b61082e565b61086e90516100f9565b90565b634e487b7160e01b600052601160045260246000fd5b61089661089c919392936100f9565b926100f9565b82039182116108a757565b610871565b6108b59061032c565b90565b6108c1906100f9565b9052565b91906108d9906000602085019401906108b8565b565b6108e86080820151610816565b916108f161081a565b5b806109056108ff866100f9565b916100f9565b1015610b285761098a9061092a600061092360808701518490610844565b510161048d565b610945602061093e60808801518590610844565b5101610864565b6020610958610953846106a1565b6106ad565b6370a082319061097f61096a306106b9565b9261097361001c565b98899485938493610349565b8352600483016106f1565b03915afa8015610b2357610a1694600091610af5575b5090856109c06109ba6109b560008b0161048d565b6100c9565b916100c9565b148015610adb575b600014610a8557856109ed6109e76109e260008b0161048d565b6100c9565b916100c9565b03610a2f575b5080610a08610a02600061070a565b916100f9565b11610a1b575b50505b61081f565b6108f2565b610a2891908590916110f8565b3880610a0e565b8290869091610a7c610a6a610a647fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610a7361001c565b918291826108c5565b0390a3386109f3565b90610a92838784916110f8565b80610aa5610a9f846100f9565b916100f9565b11610ab3575b505050610a11565b610acd610ad39392610ac760008a0161048d565b92610887565b916110f8565b388080610aab565b5081610aef610ae9836100f9565b916100f9565b106109c8565b610b16915060203d8111610b1c575b610b0e8183610047565b8101906106c5565b386109a0565b503d610b04565b610432565b50505050565b610b42610b3d610b4792610707565b6102f5565b6100be565b90565b610b5390610b2e565b90565b610b5f9061032c565b90565b905090565b610b7360008092610b62565b0190565b610b8090610b67565b90565b60018060401b038111610b9f57610b9b602091610027565b0190565b610031565b90610bb6610bb183610b83565b61006e565b918252565b606090565b3d600014610bdd57610bd13d610ba4565b903d6000602084013e5b565b610be5610bbb565b90610bdb565b151590565b610bfc60608201610864565b610c0f610c09600061070a565b916100f9565b11610c19575b5050565b610c2560608201610864565b90610c4d610c47610c426060610c3a306106b9565b319401610864565b6100f9565b916100f9565b10610cfa575b610c91600080610c6a610c65866104a6565b610b56565b84610c7361001c565b9081610c7e81610b77565b03925af1610c8a610bc0565b5015610beb565b610c9b575b610c15565b610ca56000610b4a565b919091610cf0610cde610cd87fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610ce761001c565b918291826108c5565b0390a33880610c96565b610d046000610b4a565b90829091610d50610d3e610d387fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610d4761001c565b918291826108c5565b0390a3610d5c306106b9565b31610c53565b600090565b90565b610d7e610d79610d8392610d67565b6102f5565b61034f565b90565b90602082820312610da057610d9d916000016100ea565b90565b610083565b610dae906102f8565b90565b610dba90610da5565b90565b91929092610dcd6080820161048d565b92610ddb6080840151610816565b94610de4610d62565b91610df160608501610443565b610e04610dfe6001610d6a565b9161034f565b14610fae575b5050610e1461081a565b5b80610e28610e22886100f9565b916100f9565b1015610fa657610ead90610e4d6000610e4660808801518490610844565b510161048d565b610e686020610e6160808901518590610844565b5101610864565b6020610e7b610e76846106a1565b6106ad565b6370a0823190610ea2610e8d306106b9565b92610e9661001c565b98899485938493610349565b8352600483016106f1565b03915afa8015610fa157610ee594600091610f73575b5081610ed7610ed1836100f9565b916100f9565b11610eea575b50505061081f565b610e15565b610ef391610887565b9084610f10610f0a610f056000610b4a565b6100c9565b916100c9565b03610f55575b81610f2a610f24600061070a565b916100f9565b11610f36575b80610edd565b610f4e918891610f4860408901610443565b926115b1565b3880610f30565b90610f6d90610f6386610db1565b90898491926113a9565b90610f16565b610f94915060203d8111610f9a575b610f8c8183610047565b8101906106c5565b38610ec3565b503d610f82565b610432565b505050505050565b610fe6925090610fbf602092610338565b610fdb63a900c652610fcf61001c565b95869485938493610349565b83526004830161041c565b03915afa90811561102f57600091611001575b503880610e0a565b611022915060203d8111611028575b61101a8183610047565b810190610d86565b38610ff9565b503d611010565b610432565b63ffffffff1690565b63ffffffff60e01b1690565b61105d61105861106292611034565b610349565b61103d565b90565b916020611087929493611080604082019660008301906106e4565b01906108b8565b565b906110d06110d5936110c1600494936110a863a9059cbb919391611049565b926110b161001c565b9687946020860190815201611065565b60208201810382520383610047565b61173f565b565b600090565b6110f06110eb6110f592610d67565b6102f5565b6100f9565b90565b919091600461113a61110d63a9059cbb611049565b61112b86869061111b61001c565b9586946020860190815201611065565b60208201810382520382610047565b6111426110d7565b5061114b61081a565b906020600061115861081a565b92828151910182875af1801519611235575b6111749015610beb565b9182156111de575b5050611188575b505050565b9190916111d36111c16111bb7fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b936111ca61001c565b918291826108c5565b0390a3388080611183565b9091506111f46111ee600061070a565b916100f9565b1460001461121b5750803b61121261120c600061070a565b916100f9565b145b388061117c565b61122e61122860016110dc565b916100f9565b1415611214565b9150503d9061117460005191905061116a565b6112519061032c565b90565b61125d816100be565b0361126457565b600080fd5b9050519061127682611254565b565b65ffffffffffff1690565b61128c81611278565b0361129357565b600080fd5b905051906112a582611283565b565b90916060828403126112dd576112da6112c38460008501611269565b936112d18160208601611298565b93604001611298565b90565b610083565b60409061130c6113139496959396611302606084019860008501906106e4565b60208301906106e4565b01906106e4565b565b61132961132461132e926100be565b6102f5565b6100f9565b90565b61134561134061134a926100f9565b6102f5565b6100be565b90565b600091031261135857565b610083565b611366906100be565b9052565b6113a06113a79461139660609498979561138c608086019a60008701906106e4565b60208501906106e4565b604083019061135d565b01906106e4565b565b93926113b361081a565b506113bd85611248565b606063927da1059184906113ec87946113f76113d8306106b9565b6113e061001c565b97889687958695610349565b8552600485016112e2565b03915afa90811561155557600091611527575b5061141361081a565b5080611427611421846100f9565b91611315565b101560001461150157509161143c600061070a565b945b8361145261144c600061070a565b916100f9565b1161145e575b50505050565b61146790611248565b6336c78516929161148061147a306106b9565b95611331565b90823b156114fc576000946114b386926114a89461149c61001c565b998a9889978896610349565b86526004860161136a565b03925af180156114f7576114ca575b808080611458565b6114ea9060003d81116114f0575b6114e28183610047565b81019061134d565b386114c2565b503d6114d8565b610432565b610344565b8061151b61151461152193969496611315565b9591611315565b90610887565b9461143e565b611548915060603d811161154e575b6115408183610047565b8101906112a7565b5061140a565b503d611536565b610432565b91602061157c929493611575604082019660008301906106e4565b01906106e4565b565b6040906115a86115af949695939661159e606084019860008501906106e4565b60208301906106e4565b01906108b8565b565b919290926115c66115c1856106a1565b6106ad565b602063dd62ed3e9185906115f46115dc306106b9565b946115ff6115e861001c565b96879586948594610349565b84526004840161155a565b03915afa9081156116f3576000916116c5575b509161161c61081a565b508261163061162a846100f9565b916100f9565b1015600014611681575090505b8061165161164b600061070a565b916100f9565b1161165c575b505050565b611668611679936106a1565b91611672306106b9565b91926117d2565b388080611657565b61169461168e6001610d6a565b9161034f565b146000146116a2575061163d565b826116c18591926000938493638f87ba6760e01b85526004850161157e565b0390fd5b6116e6915060203d81116116ec575b6116de8183610047565b8101906106c5565b38611612565b503d6116d4565b610432565b5190565b61170581610beb565b0361170c57565b600080fd5b9050519061171e826116fc565b565b9060208282031261173a5761173791600001611711565b90565b610083565b906117529061174d836106ad565b611822565b61175b816116f8565b61176e611768600061070a565b916100f9565b141590816117a7575b5061177f5750565b61178b6117a3916106ad565b6000918291635274afe760e01b8352600483016106f1565b0390fd5b6117cc91506117c69060206117bb826116f8565b818301019101611720565b15610beb565b38611777565b60049261180c611820959361181b93946117f36323b872dd92949192611049565b936117fc61001c565b978895602087019081520161157e565b60208201810382520383610047565b61173f565b565b906118419161182f610bbb565b509061183b600061070a565b91611850565b90565b61184d9061032c565b90565b909161185a610bbb565b5061186430611844565b31611877611871836100f9565b916100f9565b106118a457600080916118a1948491602082019151925af190611898610bc0565b909190916118cc565b90565b6118c86118b030611844565b600091829163cd78605960e01b8352600483016106f1565b0390fd5b906118e0906118d9610bbb565b5015610beb565b6000146118ed575061195a565b6118f6826116f8565b611909611903600061070a565b916100f9565b1480611938575b611918575090565b611934906000918291639996b31560e01b8352600483016106f1565b0390fd5b50803b61194e611948600061070a565b916100f9565b14611910565b60000190565b611963816116f8565b611976611970600061070a565b916100f9565b1160001461198657805190602001fd5b6000630a12f52160e11b81528061199f60048201611954565b0390fdfe
Deployed Bytecode
0x60806040526004361015610013575b610d49565b61001e60003561012d565b8063111980f7146101285780631299d61714610123578063251043bf1461011e5780632c308f52146101195780634f1c807014610114578063526a72aa1461010f57806354fd4d501461010a578063695a461c1461010557806369f7cdc61461010057806381a09d34146100fb5780638616615e146100f657806393a359e9146100f157806396c5c272146100ec578063a900c652146100e7578063ab4b583e146100e2578063cca23bf2146100dd5763fb4035f60361000e57610d11565b610ca8565b610a1d565b6109a2565b61096d565b610915565b6108be565b610835565b61076a565b6106d4565b6105b2565b6104e3565b610405565b6103d1565b610350565b6102d2565b610222565b60e01c90565b60405190565b600080fd5b600080fd5b90565b61014f81610143565b0361015657565b600080fd5b9050359061016882610146565b565b600080fd5b908160a091031261017d5790565b61016a565b151590565b61019081610182565b0361019757565b600080fd5b905035906101a982610187565b565b90916060828403126101fa576101c4836000840161015b565b9260208301359067ffffffffffffffff82116101f5576101e9816101f293860161016f565b9360400161019c565b90565b61013e565b610139565b61020890610143565b9052565b9190610220906000602085019401906101ff565b565b61024a6102396102333660046101ab565b91610fde565b610241610133565b9182918261020c565b0390f35b600080fd5b9060208282031261026d5761026a9160000161015b565b90565b610139565b634e487b7160e01b600052602160045260246000fd5b6005111561029257565b610272565b906102a182610288565b565b6102ac90610297565b90565b6102b8906102a3565b9052565b91906102d0906000602085019401906102af565b565b34610302576102fe6102ed6102e8366004610253565b6110d6565b6102f5610133565b918291826102bc565b0390f35b61024e565b908160409103126103155790565b61016a565b9060208282031261034b57600082013567ffffffffffffffff8111610346576103439201610307565b90565b61013e565b610139565b346103805761037c61036b61036636600461031a565b611101565b610373610133565b9182918261020c565b0390f35b61024e565b9190916040818403126103c65761039f836000830161015b565b92602082013567ffffffffffffffff81116103c1576103be920161016f565b90565b61013e565b610139565b60000190565b34610400576103ea6103e4366004610385565b90611405565b6103f2610133565b806103fc816103cb565b0390f35b61024e565b346104345761041e610418366004610385565b906116ef565b610426610133565b80610430816103cb565b0390f35b61024e565b60018060a01b031690565b61044d90610439565b90565b61045981610444565b0361046057565b600080fd5b9050359061047282610450565b565b919060a0838203126104de5761048d816000850161015b565b92602081013567ffffffffffffffff81116104d957826104ae91830161016f565b926104d66104bf8460408501610465565b936104cd8160608601610465565b9360800161019c565b90565b61013e565b610139565b34610517576105136105026104f9366004610474565b93929092611a17565b61050a610133565b9182918261020c565b0390f35b61024e565b600091031261052757565b610139565b5190565b60209181520190565b60005b83811061054d575050906000910152565b80602091830151818501520161053c565b601f801991011690565b6105876105906020936105959361057e8161052c565b93848093610530565b95869101610539565b61055e565b0190565b6105af9160208201916000818403910152610568565b90565b346105e2576105c236600461051c565b6105de6105cd611b62565b6105d5610133565b91829182610599565b0390f35b61024e565b600080fd5b600080fd5b600080fd5b909182601f830112156106305781359167ffffffffffffffff831161062b57602001926020830284011161062657565b6105f1565b6105ec565b6105e7565b909182601f8301121561066f5781359167ffffffffffffffff831161066a57602001926020830284011161066557565b6105f1565b6105ec565b6105e7565b90916040828403126106cf57600082013567ffffffffffffffff81116106ca57836106a09184016105f6565b929093602082013567ffffffffffffffff81116106c5576106c19201610635565b9091565b61013e565b61013e565b610139565b34610706576106f06106e7366004610674565b92919091611c2b565b6106f8610133565b80610702816103cb565b0390f35b61024e565b60808183031261076557600081013567ffffffffffffffff81116107605782610735918301610307565b9261075d6107468460208501610465565b936107548160408601610465565b9360600161019c565b90565b61013e565b610139565b3461079e5761079a61078961078036600461070b565b92919091611cfa565b610791610133565b9182918261020c565b0390f35b61024e565b60ff1690565b6107b2906107a3565b9052565b6107bf90610444565b9052565b9060808061081d936107dd600082015160008601906107a9565b6107ef602082015160208601906107a9565b610801604082015160408601906107a9565b610813606082015160608601906107a9565b01519101906107b6565b565b919061083390600060a085019401906107c3565b565b346108655761086161085061084b366004610253565b611dfb565b610858610133565b9182918261081f565b0390f35b61024e565b90916060828403126108b957610883836000840161015b565b9260208301359067ffffffffffffffff82116108b4576108a8816108b193860161016f565b93604001610465565b90565b61013e565b610139565b346108ed576108d76108d136600461086a565b91611e7c565b6108df610133565b806108e9816103cb565b0390f35b61024e565b6108fb90610182565b9052565b9190610913906000602085019401906108f2565b565b346109455761094161093061092b36600461031a565b6121a2565b610938610133565b918291826108ff565b0390f35b61024e565b61095390610444565b9052565b919061096b9060006020850194019061094a565b565b3461099d5761099961098861098336600461031a565b612221565b610990610133565b91829182610957565b0390f35b61024e565b346109d2576109ce6109bd6109b8366004610253565b612252565b6109c5610133565b91829182610957565b0390f35b61024e565b9190604083820312610a185760008301359067ffffffffffffffff8211610a1357610a0781610a10938601610307565b9360200161019c565b90565b61013e565b610139565b610a45610a34610a2e3660046109d7565b90612274565b610a3c610133565b9182918261020c565b0390f35b610a5290610143565b90565b90610a5f90610a49565b600052602052604060002090565b60001c90565b60ff1690565b610a85610a8a91610a6d565b610a73565b90565b610a979054610a79565b90565b90610aa4906107a3565b9052565b60081c90565b610aba610abf91610aa8565b610a73565b90565b610acc9054610aae565b90565b60101c90565b610ae1610ae691610acf565b610a73565b90565b610af39054610ad5565b90565b60181c90565b610b08610b0d91610af6565b610a73565b90565b610b1a9054610afc565b90565b60201c90565b60018060a01b031690565b610b3a610b3f91610b1d565b610b23565b90565b610b4c9054610b2e565b90565b90610b5990610444565b9052565b634e487b7160e01b600052604160045260246000fd5b90610b7d9061055e565b810190811067ffffffffffffffff821117610b9757604052565b610b5d565b90610baf610ba8610133565b9283610b73565b565b610bbb60a0610b9c565b90565b90610c3a610c316000610bcf610bb1565b94610be6610bde838301610a8d565b838801610a9a565b610bfd610bf4838301610ac2565b60208801610a9a565b610c14610c0b838301610ae9565b60408801610a9a565b610c2b610c22838301610b10565b60608801610a9a565b01610b42565b60808401610b4f565b565b610c48610c4d91610a6d565b610b23565b90565b610c5a9054610c3c565b90565b610c68906000610a55565b90610c816001610c7a60008501610bbe565b9301610c50565b90565b9160a0610ca6929493610c9f60c082019660008301906107c3565b019061094a565b565b34610cd957610cc0610cbb366004610253565b610c5d565b90610cd5610ccc610133565b92839283610c84565b0390f35b61024e565b604090610d08610d0f9496959396610cfe606084019860008501906101ff565b60208301906101ff565b01906101ff565b565b34610d4457610d40610d2c610d2736600461031a565b6125d9565b610d37939193610133565b93849384610cde565b0390f35b61024e565b600080fd5b600090565b50610d62906020810190610465565b90565b90565b610d7181610d65565b03610d7857565b600080fd5b90503590610d8a82610d68565b565b50610d9b906020810190610d7d565b90565b610da790610d65565b9052565b600080fd5b600080fd5b600080fd5b9035600160200382360303811215610dfb57016020813591019167ffffffffffffffff8211610df6576040820236038313610df157565b610db0565b610dab565b610db5565b60209181520190565b90565b906020610e39610e4193610e30610e266000830183610d53565b60008601906107b6565b82810190610d8c565b910190610d9e565b565b90610e5081604093610e0c565b0190565b5090565b60400190565b91610e6c82610e7292610e00565b92610e09565b90816000905b828210610e86575050505090565b90919293610ea8610ea2600192610e9d8886610e54565b610e43565b95610e58565b920190929192610e78565b610f3f91610f3160a0820192610ed9610ecf6000830183610d53565b60008501906107b6565b610ef3610ee96020830183610d53565b60208501906107b6565b610f0d610f036040830183610d8c565b6040850190610d9e565b610f27610f1d6060830183610d8c565b6060850190610d9e565b6080810190610dba565b916080818503910152610e5e565b90565b610f589160208201916000818403910152610eb3565b90565b60200190565b5190565b90565b610f74610f7991610143565b610f65565b9052565b602081610f8f610f9793839695610f68565b018092610f68565b0190565b610fa490610bbe565b90565b90565b610fbe610fb9610fc392610439565b610fa7565b610439565b90565b610fcf90610faa565b90565b610fdb90610fc6565b90565b92919061109f91610fed610d4e565b5061109561100c61101b84611000610133565b92839160208301610f42565b60208201810382520382610b73565b61102d61102782610f61565b91610f5b565b206110588761104961103d610133565b93849260208401610f7d565b60208201810382520382610b73565b61106a61106482610f61565b91610f5b565b209561108c611085600061107f818b90610a55565b01610f9b565b88906126ca565b8690849161283c565b8592339293612a69565b6110b3826110ac30610fd2565b3190612e5a565b565b600090565b6110ce6110c96110d3926107a3565b610fa7565b610297565b90565b6110f96000806110f26110fe946110eb6110b5565b5082610a55565b0101610a8d565b6110ba565b90565b9061110a610d4e565b50611138611117836125d9565b505092611130600061112a818790610a55565b01610f9b565b849091613093565b565b61114490516107a3565b90565b3561115181610d68565b90565b6004111561115e57565b610272565b9061116d82611154565b565b61117890611163565b90565b90565b61119261118d6111979261117b565b610fa7565b6107a3565b90565b6111ae6111a96111b39261117b565b610fa7565b610439565b90565b6111bf9061119a565b90565b60001b90565b906111d460ff916111c2565b9181191691161790565b6111f26111ed6111f7926107a3565b610fa7565b6107a3565b90565b90565b9061121261120d611219926111de565b6111fa565b82546111c8565b9055565b60081b90565b9061123061ff009161121d565b9181191691161790565b9061124f61124a611256926111de565b6111fa565b8254611223565b9055565b60101b90565b9061126e62ff00009161125a565b9181191691161790565b9061128d611288611294926111de565b6111fa565b8254611260565b9055565b60181b90565b906112ad63ff00000091611298565b9181191691161790565b906112cc6112c76112d3926111de565b6111fa565b825461129e565b9055565b6112e19051610444565b90565b60201b90565b90611300640100000000600160c01b03916112e4565b9181191691161790565b61131390610fc6565b90565b90565b9061132e6113296113359261130a565b611316565b82546112ea565b9055565b906113ac608060006113b29461135c82820161135684880161113a565b906111fd565b61137482820161136e6020880161113a565b9061123a565b61138c8282016113866040880161113a565b90611278565b6113a482820161139e6060880161113a565b906112b7565b0192016112d7565b90611319565b565b906113be91611339565b565b356113ca81610450565b90565b916113f1926113e4604082019360008301906101ff565b6020818403910152610eb3565b90565b6113fc610133565b3d6000823e3d90fd5b9061142161143082611415610133565b92839160208301610f42565b60208201810382520382610b73565b61144261143c82610f61565b91610f5b565b2061146d8361145e611452610133565b93849260208401610f7d565b60208201810382520382610b73565b61147f61147982610f61565b91610f5b565b20916114976000611491818690610a55565b01610f9b565b6114a36000820161113a565b6114be6114b86114b360036102a3565b6107a3565b916107a3565b141580611668575b80611642575b61162257806114e0600061156c930161113a565b6114fb6114f56114f060036102a3565b6107a3565b916107a3565b03611607575b61151761150e600261116f565b60208301610a9a565b61152d611524600061117e565b60408301610a9a565b61154361153a600061117e565b60608301610a9a565b61155961155060006111b6565b60808301610b4f565b6000611566818790610a55565b016113b4565b82611579600084016113c0565b6115b86115a67f0ba6f12b978882904e7444c7a8fcadd2d9f692a6a97aa18e5fb44c3bbc5801239261130a565b926115af610133565b9182918261020c565b0390a2916115c4610133565b916119a483019083821067ffffffffffffffff8311176116025783926115f1926119a4613b7c86396113cd565b03906000f5156115fd57565b6113f4565b610b5d565b61161d61161460046102a3565b60008301610a9a565b611501565b61163e8460009182916332567f1d60e21b83526004830161020c565b0390fd5b504261166161165b61165660408701611147565b610d65565b91610d65565b11156114cc565b506116756000820161113a565b61169061168a61168560046102a3565b6107a3565b916107a3565b14156114c6565b6116a090610faa565b90565b6116ac90611697565b90565b6116b890610fc6565b90565b60e01b90565b905051906116ce82610450565b565b906020828203126116ea576116e7916000016116c1565b90565b610139565b909161170c61171b84611700610133565b92839160208301610f42565b60208201810382520382610b73565b61172d61172782610f61565b91610f5b565b206117588361174961173d610133565b93849260208401610f7d565b60208201810382520382610b73565b61176a61176482610f61565b91610f5b565b20926117b6602061178c6117876117828386016113c0565b6116a3565b6116af565b6399d145b2906117ab889261179f610133565b958694859384936116bb565b83526004830161020c565b03915afa908115611a12576000916119e4575b50926117e160006117db818890610a55565b01610f9b565b846117fd6117f76117f260006111b6565b610444565b91610444565b1415806119b5575b80611986575b61187457858561182c61182661182160006111b6565b610444565b91610444565b146000146118545761185090600091829163dac420a360e01b83526004830161020c565b0390fd5b61187090600091829163313d14a960e11b83526004830161020c565b0390fd5b6118f69061189461188b60039897949596986102a3565b60008301610a9a565b6118aa6118a1600161116f565b60208301610a9a565b6118c06118b7600061117e565b60408301610a9a565b6118d66118cd600061117e565b60608301610a9a565b6118e38360808301610b4f565b60006118f0818890610a55565b016113b4565b83906119376119257f6653a45d3871e4110fa55dac0269f9f93a6d9078d402f7153594e50573d7f0cd9261130a565b9261192e610133565b9182918261020c565b0390a291611943610133565b916119a483019083821067ffffffffffffffff831117611981578392611970926119a4613b7c86396113cd565b03906000f51561197c57565b6113f4565b610b5d565b506119936000820161113a565b6119ae6119a86119a360046102a3565b6107a3565b916107a3565b141561180b565b506119c26000820161113a565b6119dd6119d76119d260036102a3565b6107a3565b916107a3565b1415611805565b611a05915060203d8111611a0b575b6119fd8183610b73565b8101906116d0565b386117c9565b503d6119f3565b6113f4565b9493909192611ad593611a28610d4e565b50611a44611a5385611a38610133565b92839160208301610f42565b60208201810382520382610b73565b611a65611a5f82610f61565b91610f5b565b20611a9088611a81611a75610133565b93849260208401610f7d565b60208201810382520382610b73565b611aa2611a9c82610f61565b91610f5b565b2096611aba6000611ab4818b90610a55565b01610f9b565b90611ac78982889161283c565b9195899192939495966132ee565b565b606090565b67ffffffffffffffff8111611afa57611af660209161055e565b0190565b610b5d565b90611b11611b0c83611adc565b610b9c565b918252565b60007f312e31352e302d32653238376233000000000000000000000000000000000000910152565b611b48600e611aff565b90611b5560208301611b16565b565b611b5f611b3e565b90565b611b6a611ad7565b50611b73611b57565b90565b5090565b5090565b611b92611b8d611b979261117b565b610fa7565b610d65565b90565b6001611ba69101610d65565b90565b634e487b7160e01b600052603260045260246000fd5b9190811015611bcf576020020190565b611ba9565b35611bde81610146565b90565b600080fd5b600080fd5b600080fd5b903590600160a00381360303821215611c07570190565b611be1565b90821015611c26576020611c239202810190611bf0565b90565b611ba9565b93929193611c3a818390611b76565b9384611c58611c52611c4d898890611b7a565b610d65565b91610d65565b03611cc157611c676000611b7e565b5b80611c7b611c7588610d65565b91610d65565b1015611cb857611cb390611cae611c9c611c9786888591611bbf565b611bd4565b611ca88a898591611c0c565b906116ef565b611b9a565b611c68565b50945050505050565b600063512509d360e11b815280611cda600482016103cb565b0390fd5b903590600160c00381360303821215611cf5570190565b611be1565b909392611d9a92611d09610d4e565b50611d12610d4e565b50611d1c836125d9565b50969096611d366000611d30818b90610a55565b01610f9b565b90611d43868a8491613093565b611d66611d5f6020611d59896000810190611cde565b01611147565b8a9061361a565b611d8e611d828a83611d7c8a6020810190611bf0565b9161283c565b92966020810190611bf0565b899192939495966132ee565b565b600090565b600090565b611dae610bb1565b9060208080808086611dbe611d9c565b815201611dc9611d9c565b815201611dd4611d9c565b815201611ddf611d9c565b815201611dea611da1565b81525050565b611df8611da6565b90565b6000611e13611e1992611e0c611df0565b5082610a55565b01610f9b565b90565b903590600160200381360303821215611e5e570180359067ffffffffffffffff8211611e5957602001916040820236038313611e5457565b611beb565b611be6565b611be1565b5090565b9190811015611e77576040020190565b611ba9565b9282611e99611e93611e8e60006111b6565b610444565b91610444565b1461218057611eb9611ec883611ead610133565b92839160208301610f42565b60208201810382520382610b73565b611eda611ed482610f61565b91610f5b565b20611f0585611ef6611eea610133565b93849260208401610f7d565b60208201810382520382610b73565b611f17611f1182610f61565b91610f5b565b20611f2e6000611f28818490610a55565b01610f9b565b94611f3b6000870161113a565b611f56611f50611f4b60036102a3565b6107a3565b916107a3565b141580612151575b8061212b575b61210b57611f726000611b7e565b5b80611f9c611f96611f91611f8b896080810190611e1c565b90611e63565b610d65565b91610d65565b101561200757611fc56000611fbf611fb8886080810190611e1c565b8591611e67565b016113c0565b611fd7611fd188610444565b91610444565b14611fea57611fe590611b9a565b611f73565b600063cd91597b60e01b815280612003600482016103cb565b0390fd5b50919461205d612070929561202861201f600361116f565b60208501610a9a565b61203e612035600061117e565b60408501610a9a565b61205461204b600061117e565b60608501610a9a565b60808301610b4f565b600061206a818790610a55565b016113b4565b8261207d600084016113c0565b6120bc6120aa7f0ba6f12b978882904e7444c7a8fcadd2d9f692a6a97aa18e5fb44c3bbc5801239261130a565b926120b3610133565b9182918261020c565b0390a2916120c8610133565b916119a483019083821067ffffffffffffffff8311176121065783926120f5926119a4613b7c86396113cd565b03906000f51561210157565b6113f4565b610b5d565b6121278260009182916335bd755560e11b83526004830161020c565b0390fd5b5061213860608501611147565b61214b6121456000611b7e565b91610d65565b11611f64565b5061215e6000870161113a565b61217961217361216e60046102a3565b6107a3565b916107a3565b1415611f5e565b600063cd91597b60e01b815280612199600482016103cb565b0390fd5b600090565b6121aa61219d565b506121c460206121be836000810190611cde565b01611147565b6121d66121d046610d65565b91610d65565b03612216578061220e6122036121ee612213946125d9565b506121fd856020810190611bf0565b9161283c565b916020810190611bf0565b613654565b90565b50600090565b600090565b61224961224f9161223061221c565b5061223a816125d9565b50929092916020810190611bf0565b9161283c565b90565b600161226b6122719261226361221c565b506000610a55565b01610c50565b90565b61231a906123039392612285610d4e565b5061228e610d4e565b50612298826125d9565b509590956122ed6122b560006122af818b90610a55565b01610f9b565b6122c0818a906126ca565b6122e36122dc60206122d6896000810190611cde565b01611147565b8a9061361a565b8590899091613093565b86906122fd856020810190611bf0565b9161283c565b61231286936020810190611bf0565b339293612a69565b61232e8261232730610fd2565b3190612e5a565b565b5061233f90602081019061015b565b90565b61234b90610143565b9052565b903560016020038236030381121561239057016020813591019167ffffffffffffffff821161238b57602082023603831361238657565b610db0565b610dab565b610db5565b60209181520190565b90565b90356001602003823603038112156123e257016020813591019167ffffffffffffffff82116123dd5760018202360383136123d857565b610db0565b610dab565b610db5565b60209181520190565b90826000939282370152565b91906124168161240f8161241b956123e7565b80956123f0565b61055e565b0190565b9061247790604061246f6124656060840161244a6124406000890189610d53565b60008701906107b6565b61245760208801886123a1565b9086830360208801526123fc565b9482810190610d8c565b910190610d9e565b90565b906124849161241f565b90565b903560016060038236030381121561249d570190565b610db5565b60200190565b91816124b391612395565b90816124c46020830284019461239e565b92836000925b8484106124da5750505050505090565b90919293949560206125056124ff83856001950388526124fa8b88612487565b61247a565b986124a2565b9401940192949391906124ca565b6125bd916125af6125a460c0830161253b6125316000870187612330565b6000860190612342565b61255561254b6020870187610d8c565b6020860190610d9e565b61256f6125656040870187610d8c565b6040860190610d9e565b61258961257f6060870187610d53565b60608601906107b6565b6125966080860186610dba565b908583036080870152610e5e565b9260a081019061234f565b9160a08185039101526124a8565b90565b6125d69160208201916000818403910152612513565b90565b6125e1610d4e565b506125ea610d4e565b506125f3610d4e565b50612666612675612652612625612634612611866000810190611cde565b612619610133565b928391602083016125c0565b60208201810382520382610b73565b61264661264082610f61565b91610f5b565b20936020810190611bf0565b61265a610133565b92839160208301610f42565b60208201810382520382610b73565b61268761268182610f61565b91610f5b565b20816126b482916126a5612699610133565b93849260208401610f7d565b60208201810382520382610b73565b6126c66126c082610f61565b91610f5b565b2092565b60006126d6910161113a565b6126f16126eb6126e660006102a3565b6107a3565b916107a3565b036126f95750565b6127159060009182916330a4e71560e01b83526004830161020c565b0390fd5b905090565b61274361273a9260209261273181610f61565b94858093612719565b93849101610539565b0190565b6127559061275b939261271e565b9061271e565b90565b905090565b600060ff60f81b910152565b61277b6001809261275e565b61278481612763565b0190565b60601b90565b61279790612788565b90565b6127a39061278e565b90565b6127b26127b791610444565b61279a565b9052565b602093926127e460146127ec946127dc6127d5899661276f565b80926127a6565b018092610f68565b018092610f68565b0190565b6128046127ff61280992610d65565b610fa7565b610d65565b90565b61281861281d91610a6d565b6127f0565b90565b61283461282f61283992610d65565b610fa7565b610439565b90565b61291e90612906612923936128f76129289661285661221c565b506128d061286330610fd2565b93956128aa6119a49161287860208401610b9c565b92808452613b7c602085013961289b61288f610133565b958692602084016113cd565b60208201810382520384610b73565b6128c16128b5610133565b93849260208401612747565b60208201810382520382610b73565b6128e26128dc82610f61565b91610f5b565b206128eb610133565b948593602085016127bb565b60208201810382520382610b73565b61291861291282610f61565b91610f5b565b2061280c565b612820565b610fc6565b90565b91602061294d929493612946604082019660008301906101ff565b019061094a565b565b61295890610faa565b90565b6129649061294f565b90565b61297090610fc6565b90565b600090565b61298190610faa565b90565b61298d90612978565b90565b61299990610fc6565b90565b905051906129a982610d68565b565b906020828203126129c5576129c29160000161299c565b90565b610139565b634e487b7160e01b600052601160045260246000fd5b6129ef6129f591939293610d65565b92610d65565b8203918211612a0057565b6129ca565b916020612a27929493612a206040820196600083019061094a565b019061094a565b565b612a3290610d65565b9052565b604090612a60612a679496959396612a566060840198600085019061094a565b602083019061094a565b0190612a29565b565b9493949291909280337f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d91612aa8612a9f610133565b9283928361292b565b0390a1612ab760608501611147565b612aca612ac46000611b7e565b91610d65565b11612d4b575b50612ae8612ae2846080810190611e1c565b90611e63565b93612af1612973565b5b80612b05612aff88610d65565b91610d65565b1015612d4257612b2e6000612b28612b21886080810190611e1c565b8591611e67565b016113c0565b612b516020612b4b612b44896080810190611e1c565b8691611e67565b01611147565b612b916020612b67612b6285612984565b612990565b6370a0823190612b868992612b7a610133565b958694859384936116bb565b835260048301610957565b03915afa908115612d3d57600091612d0f575b5081612bb8612bb283610d65565b91610d65565b11612bcf575b505050612bca90611b9a565b612af2565b612bd990826129e0565b50612beb612be683612984565b612990565b602063dd62ed3e918890612c19612c0130610fd2565b94612c24612c0d610133565b968795869485946116bb565b845260048401612a05565b03915afa908115612d0a57600091612cdc575b50612c40612973565b5080612c54612c4e84610d65565b91610d65565b1015600014612ca4575090612bca92915b80612c79612c736000611b7e565b91610d65565b11612c87575b829350612bbe565b612c93612c9d92612984565b90878791926137fb565b3880612c7f565b9089600014612cb9575090612bca9291612c65565b86612cd88491926000938493638f87ba6760e01b855260048501612a36565b0390fd5b612cfd915060203d8111612d03575b612cf58183610b73565b8101906129ab565b38612c37565b503d612ceb565b6113f4565b612d30915060203d8111612d36575b612d288183610b73565b8101906129ab565b38612ba4565b503d612d1e565b6113f4565b50945050505050565b34612d69612d63612d5e60608801611147565b610d65565b91610d65565b10612db457506000808080612d85612d808661295b565b612967565b612d9160608901611147565b90828215612dab575bf115612da65738612ad0565b6113f4565b506108fc612d9a565b612dd0906000918291631368c98360e11b83526004830161020c565b0390fd5b612de060008092612719565b0190565b612ded90612dd4565b90565b67ffffffffffffffff8111612e0e57612e0a60209161055e565b0190565b610b5d565b90612e25612e2083612df0565b610b9c565b918252565b606090565b3d600014612e4c57612e403d612e13565b903d6000602084013e5b565b612e54612e2a565b90612e4a565b9080612e6f612e696000611b7e565b91610d65565b11612e79575b5050565b600080612eb892612e91612e8c3361295b565b612967565b90612e9a610133565b9081612ea581612de4565b03925af1612eb1612e2f565b5015610182565b612ec25780612e75565b612ede90600091829163da9a84fd60e01b83526004830161020c565b0390fd5b903590600160200381360303821215612f24570180359067ffffffffffffffff8211612f1f57602001916020820236038313612f1a57565b611beb565b611be6565b611be1565b60209181520190565b91612f4082612f4692612f29565b92610e09565b90816000905b828210612f5a575050505090565b90919293612f7c612f76600192612f718886610e54565b610e43565b95610e58565b920190929192612f4c565b60209181520190565b9181612f9b91612f87565b9081612fac6020830284019461239e565b92836000925b848410612fc25750505050505090565b9091929394956020612fed612fe78385600195038852612fe28b88612487565b61247a565b986124a2565b940194019294939190612fb2565b9791906130909c9a966130789661305261306d979c9e9c6130486130829c9860408f61304161305f9a61303761012084019b60008501906101ff565b6020830190612a29565b0190612a29565b60608d019061094a565b8a830360808c0152612f32565b9187830360a0890152612f90565b9660c0850190612a29565b60e0830190612a29565b610100818503910152612f32565b90565b916130a06000820161113a565b6130bb6130b56130b060036102a3565b6107a3565b916107a3565b14908115613265575b5061324557906130e260006130dc8382810190611cde565b01611bd4565b906130fc60206130f6836000810190611cde565b01611147565b926131166040613110846000810190611cde565b01611147565b93613130606061312a856000810190611cde565b016113c0565b9361324061314f613145866000810190611cde565b6080810190611e1c565b9661316b613161886000810190611cde565b60a0810190612ee2565b9790986131876000613181846020810190611bf0565b016113c0565b986131a0602061319a8582810190611bf0565b016113c0565b9a6131ba60406131b4866020810190611bf0565b01611147565b926131ef6131e56131da60606131d4896020810190611bf0565b01611147565b966020810190611bf0565b6080810190611e1c565b97909661322e6132286132227fd802f2610d0c85b3f19be4413f3cf49de1d4e787edecd538274437a5b9aa648d9f610a49565b9f61130a565b9f61130a565b9f613237610133565b9c8d9c8d612ffb565b0390a4565b613261906000918291635eaf4c6960e01b83526004830161020c565b0390fd5b613272915060000161113a565b61328d61328761328260046102a3565b6107a3565b916107a3565b14386130c4565b90565b6132ab6132a66132b092613294565b610fa7565b6107a3565b90565b906132c460018060a01b03916111c2565b9181191691161790565b906132e36132de6132ea9261130a565b611316565b82546132b3565b9055565b94969590939291956133028585899161384b565b61330d8688906138b7565b6133196000870161113a565b61333461332e61332960006102a3565b6107a3565b916107a3565b146135e4575b613350613347600061116f565b60208801610a9a565b6000146135d25761336e6133646001613297565b5b60408701610a9a565b8061338a61338461337f60006111b6565b610444565b91610444565b14156000146135c0576133aa6133a06001613297565b5b60608701610a9a565b6133b78760808701610b4f565b806133d36133cd6133c860006111b6565b610444565b91610444565b036135a2575b506133f18460006133eb818990610a55565b016113b4565b8483906133fc610133565b916119a483019083821067ffffffffffffffff83111761359d578392613429926119a4613b7c86396113cd565b03906000f5156135985761343f6000840161113a565b61345a61345461344f60026102a3565b6107a3565b916107a3565b146000146134a257505050907f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d9161349c613493610133565b9283928361292b565b0390a15b565b6134ae6000840161113a565b6134c96134c36134be60016102a3565b6107a3565b916107a3565b149182613587575b505060001461354757613507906134f46134eb60026102a3565b60008301610a9a565b6000613501818590610a55565b016113b4565b907f2da42efda5225344c30e729dc0eafc2e56292ac9b9b5c2b16e0e74c86ea5921d9161353e613535610133565b9283928361292b565b0390a15b6134a0565b50907f97cf148f008486c490afd3b522e2398d5039247c7fffe81fcae2a8c6ee6221039161357f613576610133565b9283928361292b565b0390a1613542565b6135919250613654565b38806134d1565b6113f4565b610b5d565b6135ba9060016135b460008990610a55565b016132ce565b386133d9565b6133aa6135cd600061117e565b6133a1565b61336e6135df600061117e565b613365565b80600014613608576136036135f960016102a3565b5b60008801610a9a565b61333a565b61360361361560026102a3565b6135fa565b61362c61362646610d65565b91610d65565b036136345750565b6136509060009182916305c2a22560e21b83526004830161020c565b0390fd5b61365c61219d565b5061367461366e826080810190611e1c565b90611e63565b91803161369461368e61368960608601611147565b610d65565b91610d65565b106137c2576136a36000611b7e565b5b806136b76136b186610d65565b91610d65565b10156137b9576136e060006136da6136d3866080810190611e1c565b8591611e67565b016113c0565b613742602061371861371361370d836137076137008b6080810190611e1c565b8a91611e67565b01611147565b94612984565b612990565b6370a0823190613737879261372b610133565b958694859384936116bb565b835260048301610957565b03915afa9081156137b45761376a9161376491600091613786575b5092610d65565b91610d65565b1061377d5761377890611b9a565b6136a4565b50505050600090565b6137a7915060203d81116137ad575b61379f8183610b73565b8101906129ab565b3861375d565b503d613795565b6113f4565b50505050600190565b505050600090565b63ffffffff1690565b63ffffffff60e01b1690565b6137f36137ee6137f8926137ca565b6116bb565b6137d3565b90565b6004926138356138499593613844939461381c6323b872dd929491926137df565b93613825610133565b9788956020870190815201612a36565b60208201810382520383610b73565b61396d565b565b60606138579101611147565b61386a6138646000611b7e565b91610d65565b11908161389a575b5061387a5750565b61389690600091829163d287282d60e01b83526004830161020c565b0390fd5b9050316138b06138aa6000611b7e565b91610d65565b1138613872565b6138c36000820161113a565b6138de6138d86138d360006102a3565b6107a3565b916107a3565b1415908161390f575b506138ef5750565b61390b9060009182916330a4e71560e01b83526004830161020c565b0390fd5b61391c915060000161113a565b61393761393161392c60016102a3565b6107a3565b916107a3565b1415386138e7565b9050519061394c82610187565b565b90602082820312613968576139659160000161393f565b90565b610139565b906139809061397b83612990565b613a00565b61398981610f61565b61399c6139966000611b7e565b91610d65565b141590816139d5575b506139ad5750565b6139b96139d191612990565b6000918291635274afe760e01b835260048301610957565b0390fd5b6139fa91506139f49060206139e982610f61565b81830101910161394e565b15610182565b386139a5565b90613a1f91613a0d612e2a565b5090613a196000611b7e565b91613a2e565b90565b613a2b90610fc6565b90565b9091613a38612e2a565b50613a4230613a22565b31613a55613a4f83610d65565b91610d65565b10613a825760008091613a7f948491602082019151925af190613a76612e2f565b90919091613aaa565b90565b613aa6613a8e30613a22565b600091829163cd78605960e01b835260048301610957565b0390fd5b90613abe90613ab7612e2a565b5015610182565b600014613acb5750613b32565b613ad482610f61565b613ae7613ae16000611b7e565b91610d65565b1480613b16575b613af6575090565b613b12906000918291639996b31560e01b835260048301610957565b0390fd5b50803b613b2c613b266000611b7e565b91610d65565b14613aee565b613b3b81610f61565b613b4e613b486000611b7e565b91610d65565b11600014613b5e57805190602001fd5b6000630a12f52160e11b815280613b77600482016103cb565b0390fdfe608060405234610017576100116102d3565b906104b2565b610022565b60405190565b600080fd5b601f801991011690565b634e487b7160e01b600052604160045260246000fd5b9061005190610027565b810190811060018060401b0382111761006957604052565b610031565b9061008161007a61001c565b9283610047565b565b600080fd5b600080fd5b90565b6100998161008d565b036100a057565b600080fd5b905051906100b282610090565b565b600080fd5b600080fd5b60018060a01b031690565b6100d2906100be565b90565b6100de816100c9565b036100e557565b600080fd5b905051906100f7826100d5565b565b90565b610105816100f9565b0361010c57565b600080fd5b9050519061011e826100fc565b565b600080fd5b60018060401b03811161013b5760208091020190565b610031565b600080fd5b91906040838203126101815761017a9061015f604061006e565b9361016d82600083016100ea565b6000860152602001610111565b6020830152565b6100b4565b9092919261019b61019682610125565b61006e565b9381855260406020860192028301928184116101da57915b8383106101c05750505050565b60206040916101cf8486610145565b8152019201916101b3565b610140565b9080601f830112156101fd578160206101fa93519101610186565b90565b610120565b91909160a08184031261028a5761021960a061006e565b9261022781600084016100ea565b600085015261023981602084016100ea565b602085015261024b8160408401610111565b604085015261025d8160608401610111565b6060850152608082015160018060401b0381116102855761027e92016101df565b6080830152565b6100b9565b6100b4565b9190916040818403126102ce576102a983600083016100a5565b92602082015160018060401b0381116102c9576102c69201610202565b90565b610088565b610083565b6102f16119a4803803806102e68161006e565b92833981019061028f565b9091565b90565b61030c610307610311926100be565b6102f5565b6100be565b90565b61031d906102f8565b90565b61032990610314565b90565b610335906102f8565b90565b6103419061032c565b90565b600080fd5b60e01b90565b60ff1690565b61035e8161034f565b0361036557565b600080fd5b9050519061037782610355565b565b919060a0838203126103eb576103e49061039360a061006e565b936103a1826000830161036a565b60008601526103b3826020830161036a565b60208601526103c5826040830161036a565b60408601526103d7826060830161036a565b60608601526080016100ea565b6080830152565b6100b4565b9060a08282031261040a5761040791600001610379565b90565b610083565b6104189061008d565b9052565b91906104309060006020850194019061040f565b565b61043a61001c565b3d6000823e3d90fd5b61044d905161034f565b90565b634e487b7160e01b600052602160045260246000fd5b6004111561047057565b610450565b9061047f82610466565b565b61048a90610475565b90565b61049790516100c9565b90565b6104a3906102f8565b90565b6104af9061049a565b90565b906104f56104bf33610320565b9160a06104cb84610338565b6381a09d34906104ea87926104de61001c565b96879485938493610349565b83526004830161041c565b03915afa9283156106905761055a94610555946000948591610662575b509161052060208401610443565b61053a61053461052f88610481565b61034f565b9161034f565b14851461055c579161054e92918492610dbd565b5b0161048d565b6104a6565bff5b505061056a60208201610443565b61058561057f61057a6001610481565b61034f565b9161034f565b1483146105bf576105b9906105a6836105a06080840161048d565b906108db565b6105b3608084920161048d565b90610bf0565b5b61054f565b6105cb60208201610443565b6105e66105e06105db6002610481565b61034f565b9161034f565b1483146106095750610603816105fd84840161048d565b906108db565b5b6105ba565b61061560208201610443565b61063061062a6106256003610481565b61034f565b9161034f565b1461063c575b50610604565b61064b608061065c920161048d565b61065684840161048d565b9061074e565b38610636565b610683915060a03d8111610689575b61067b8183610047565b8101906103f0565b38610512565b503d610671565b610432565b61069e906102f8565b90565b6106aa90610695565b90565b6106b69061032c565b90565b6106c29061032c565b90565b906020828203126106df576106dc91600001610111565b90565b610083565b6106ed906100c9565b9052565b9190610705906000602085019401906106e4565b565b90565b61071e61071961072392610707565b6102f5565b6100f9565b90565b1561072e5750565b61074a9060009182916308a285bb60e21b8352600483016106f1565b0390fd5b90610798916020610766610761836106a1565b6106ad565b6370a082319061078d610778306106b9565b9261078161001c565b97889485938493610349565b8352600483016106f1565b03915afa928315610811576107e1936107d9916000916107e3575b50916107d4836107cc6107c6600061070a565b916100f9565b118290610726565b6106a1565b919091611089565b565b610804915060203d811161080a575b6107fc8183610047565b8101906106c5565b386107b3565b503d6107f2565b610432565b5190565b600090565b600161082b91016100f9565b90565b634e487b7160e01b600052603260045260246000fd5b9061084e82610816565b81101561085f576020809102010190565b61082e565b61086e90516100f9565b90565b634e487b7160e01b600052601160045260246000fd5b61089661089c919392936100f9565b926100f9565b82039182116108a757565b610871565b6108b59061032c565b90565b6108c1906100f9565b9052565b91906108d9906000602085019401906108b8565b565b6108e86080820151610816565b916108f161081a565b5b806109056108ff866100f9565b916100f9565b1015610b285761098a9061092a600061092360808701518490610844565b510161048d565b610945602061093e60808801518590610844565b5101610864565b6020610958610953846106a1565b6106ad565b6370a082319061097f61096a306106b9565b9261097361001c565b98899485938493610349565b8352600483016106f1565b03915afa8015610b2357610a1694600091610af5575b5090856109c06109ba6109b560008b0161048d565b6100c9565b916100c9565b148015610adb575b600014610a8557856109ed6109e76109e260008b0161048d565b6100c9565b916100c9565b03610a2f575b5080610a08610a02600061070a565b916100f9565b11610a1b575b50505b61081f565b6108f2565b610a2891908590916110f8565b3880610a0e565b8290869091610a7c610a6a610a647fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610a7361001c565b918291826108c5565b0390a3386109f3565b90610a92838784916110f8565b80610aa5610a9f846100f9565b916100f9565b11610ab3575b505050610a11565b610acd610ad39392610ac760008a0161048d565b92610887565b916110f8565b388080610aab565b5081610aef610ae9836100f9565b916100f9565b106109c8565b610b16915060203d8111610b1c575b610b0e8183610047565b8101906106c5565b386109a0565b503d610b04565b610432565b50505050565b610b42610b3d610b4792610707565b6102f5565b6100be565b90565b610b5390610b2e565b90565b610b5f9061032c565b90565b905090565b610b7360008092610b62565b0190565b610b8090610b67565b90565b60018060401b038111610b9f57610b9b602091610027565b0190565b610031565b90610bb6610bb183610b83565b61006e565b918252565b606090565b3d600014610bdd57610bd13d610ba4565b903d6000602084013e5b565b610be5610bbb565b90610bdb565b151590565b610bfc60608201610864565b610c0f610c09600061070a565b916100f9565b11610c19575b5050565b610c2560608201610864565b90610c4d610c47610c426060610c3a306106b9565b319401610864565b6100f9565b916100f9565b10610cfa575b610c91600080610c6a610c65866104a6565b610b56565b84610c7361001c565b9081610c7e81610b77565b03925af1610c8a610bc0565b5015610beb565b610c9b575b610c15565b610ca56000610b4a565b919091610cf0610cde610cd87fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610ce761001c565b918291826108c5565b0390a33880610c96565b610d046000610b4a565b90829091610d50610d3e610d387fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b93610d4761001c565b918291826108c5565b0390a3610d5c306106b9565b31610c53565b600090565b90565b610d7e610d79610d8392610d67565b6102f5565b61034f565b90565b90602082820312610da057610d9d916000016100ea565b90565b610083565b610dae906102f8565b90565b610dba90610da5565b90565b91929092610dcd6080820161048d565b92610ddb6080840151610816565b94610de4610d62565b91610df160608501610443565b610e04610dfe6001610d6a565b9161034f565b14610fae575b5050610e1461081a565b5b80610e28610e22886100f9565b916100f9565b1015610fa657610ead90610e4d6000610e4660808801518490610844565b510161048d565b610e686020610e6160808901518590610844565b5101610864565b6020610e7b610e76846106a1565b6106ad565b6370a0823190610ea2610e8d306106b9565b92610e9661001c565b98899485938493610349565b8352600483016106f1565b03915afa8015610fa157610ee594600091610f73575b5081610ed7610ed1836100f9565b916100f9565b11610eea575b50505061081f565b610e15565b610ef391610887565b9084610f10610f0a610f056000610b4a565b6100c9565b916100c9565b03610f55575b81610f2a610f24600061070a565b916100f9565b11610f36575b80610edd565b610f4e918891610f4860408901610443565b926115b1565b3880610f30565b90610f6d90610f6386610db1565b90898491926113a9565b90610f16565b610f94915060203d8111610f9a575b610f8c8183610047565b8101906106c5565b38610ec3565b503d610f82565b610432565b505050505050565b610fe6925090610fbf602092610338565b610fdb63a900c652610fcf61001c565b95869485938493610349565b83526004830161041c565b03915afa90811561102f57600091611001575b503880610e0a565b611022915060203d8111611028575b61101a8183610047565b810190610d86565b38610ff9565b503d611010565b610432565b63ffffffff1690565b63ffffffff60e01b1690565b61105d61105861106292611034565b610349565b61103d565b90565b916020611087929493611080604082019660008301906106e4565b01906108b8565b565b906110d06110d5936110c1600494936110a863a9059cbb919391611049565b926110b161001c565b9687946020860190815201611065565b60208201810382520383610047565b61173f565b565b600090565b6110f06110eb6110f592610d67565b6102f5565b6100f9565b90565b919091600461113a61110d63a9059cbb611049565b61112b86869061111b61001c565b9586946020860190815201611065565b60208201810382520382610047565b6111426110d7565b5061114b61081a565b906020600061115861081a565b92828151910182875af1801519611235575b6111749015610beb565b9182156111de575b5050611188575b505050565b9190916111d36111c16111bb7fdce1598fdc26bc6ef7bef35c4bf92827604fbe4defdcb5c8569c2c8e035acde1936108ac565b936108ac565b936111ca61001c565b918291826108c5565b0390a3388080611183565b9091506111f46111ee600061070a565b916100f9565b1460001461121b5750803b61121261120c600061070a565b916100f9565b145b388061117c565b61122e61122860016110dc565b916100f9565b1415611214565b9150503d9061117460005191905061116a565b6112519061032c565b90565b61125d816100be565b0361126457565b600080fd5b9050519061127682611254565b565b65ffffffffffff1690565b61128c81611278565b0361129357565b600080fd5b905051906112a582611283565b565b90916060828403126112dd576112da6112c38460008501611269565b936112d18160208601611298565b93604001611298565b90565b610083565b60409061130c6113139496959396611302606084019860008501906106e4565b60208301906106e4565b01906106e4565b565b61132961132461132e926100be565b6102f5565b6100f9565b90565b61134561134061134a926100f9565b6102f5565b6100be565b90565b600091031261135857565b610083565b611366906100be565b9052565b6113a06113a79461139660609498979561138c608086019a60008701906106e4565b60208501906106e4565b604083019061135d565b01906106e4565b565b93926113b361081a565b506113bd85611248565b606063927da1059184906113ec87946113f76113d8306106b9565b6113e061001c565b97889687958695610349565b8552600485016112e2565b03915afa90811561155557600091611527575b5061141361081a565b5080611427611421846100f9565b91611315565b101560001461150157509161143c600061070a565b945b8361145261144c600061070a565b916100f9565b1161145e575b50505050565b61146790611248565b6336c78516929161148061147a306106b9565b95611331565b90823b156114fc576000946114b386926114a89461149c61001c565b998a9889978896610349565b86526004860161136a565b03925af180156114f7576114ca575b808080611458565b6114ea9060003d81116114f0575b6114e28183610047565b81019061134d565b386114c2565b503d6114d8565b610432565b610344565b8061151b61151461152193969496611315565b9591611315565b90610887565b9461143e565b611548915060603d811161154e575b6115408183610047565b8101906112a7565b5061140a565b503d611536565b610432565b91602061157c929493611575604082019660008301906106e4565b01906106e4565b565b6040906115a86115af949695939661159e606084019860008501906106e4565b60208301906106e4565b01906108b8565b565b919290926115c66115c1856106a1565b6106ad565b602063dd62ed3e9185906115f46115dc306106b9565b946115ff6115e861001c565b96879586948594610349565b84526004840161155a565b03915afa9081156116f3576000916116c5575b509161161c61081a565b508261163061162a846100f9565b916100f9565b1015600014611681575090505b8061165161164b600061070a565b916100f9565b1161165c575b505050565b611668611679936106a1565b91611672306106b9565b91926117d2565b388080611657565b61169461168e6001610d6a565b9161034f565b146000146116a2575061163d565b826116c18591926000938493638f87ba6760e01b85526004850161157e565b0390fd5b6116e6915060203d81116116ec575b6116de8183610047565b8101906106c5565b38611612565b503d6116d4565b610432565b5190565b61170581610beb565b0361170c57565b600080fd5b9050519061171e826116fc565b565b9060208282031261173a5761173791600001611711565b90565b610083565b906117529061174d836106ad565b611822565b61175b816116f8565b61176e611768600061070a565b916100f9565b141590816117a7575b5061177f5750565b61178b6117a3916106ad565b6000918291635274afe760e01b8352600483016106f1565b0390fd5b6117cc91506117c69060206117bb826116f8565b818301019101611720565b15610beb565b38611777565b60049261180c611820959361181b93946117f36323b872dd92949192611049565b936117fc61001c565b978895602087019081520161157e565b60208201810382520383610047565b61173f565b565b906118419161182f610bbb565b509061183b600061070a565b91611850565b90565b61184d9061032c565b90565b909161185a610bbb565b5061186430611844565b31611877611871836100f9565b916100f9565b106118a457600080916118a1948491602082019151925af190611898610bc0565b909190916118cc565b90565b6118c86118b030611844565b600091829163cd78605960e01b8352600483016106f1565b0390fd5b906118e0906118d9610bbb565b5015610beb565b6000146118ed575061195a565b6118f6826116f8565b611909611903600061070a565b916100f9565b1480611938575b611918575090565b611934906000918291639996b31560e01b8352600483016106f1565b0390fd5b50803b61194e611948600061070a565b916100f9565b14611910565b60000190565b611963816116f8565b611976611970600061070a565b916100f9565b1160001461198657805190602001fd5b6000630a12f52160e11b81528061199f60048201611954565b0390fdfe
Net Worth in USD
Net Worth in MNT
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.