Latest 25 from a total of 142 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Execute | 22425002 | 291 days ago | IN | 0.00030265 ETH | 0.00073887 | ||||
| Execute | 22226669 | 319 days ago | IN | 0.0003578 ETH | 0.00015254 | ||||
| Execute | 22129622 | 333 days ago | IN | 0.00244503 ETH | 0.00013824 | ||||
| Execute | 22129474 | 333 days ago | IN | 0.00026221 ETH | 0.00010993 | ||||
| Execute | 21734286 | 388 days ago | IN | 0.00017945 ETH | 0.00051024 | ||||
| Execute | 21719943 | 390 days ago | IN | 0.00017762 ETH | 0.00093217 | ||||
| Execute | 21712116 | 391 days ago | IN | 0.00016403 ETH | 0.00231444 | ||||
| Execute | 21711813 | 391 days ago | IN | 0.00015853 ETH | 0.00124359 | ||||
| Execute | 21633551 | 402 days ago | IN | 0.00017622 ETH | 0.00147562 | ||||
| Execute | 21537839 | 415 days ago | IN | 0.00349363 ETH | 0.00364226 | ||||
| Execute | 21537775 | 415 days ago | IN | 0.00017052 ETH | 0.0041186 | ||||
| Execute | 21506259 | 420 days ago | IN | 0.00016781 ETH | 0.00103778 | ||||
| Execute | 21489248 | 422 days ago | IN | 0.00001994 ETH | 0.00289856 | ||||
| Execute | 21474096 | 424 days ago | IN | 0.00002638 ETH | 0.00284326 | ||||
| Execute | 21144996 | 470 days ago | IN | 0.00508214 ETH | 0.00463316 | ||||
| Execute | 20730265 | 528 days ago | IN | 0.0002148 ETH | 0.00119561 | ||||
| Execute | 20636010 | 541 days ago | IN | 0.00314984 ETH | 0.00117882 | ||||
| Execute | 20634471 | 541 days ago | IN | 0.00002002 ETH | 0.0016209 | ||||
| Execute | 20600902 | 546 days ago | IN | 0.00288189 ETH | 0.00026903 | ||||
| Execute | 20600087 | 546 days ago | IN | 0.00000161 ETH | 0.00054692 | ||||
| Execute | 20600080 | 546 days ago | IN | 0.00000203 ETH | 0.00052901 | ||||
| Execute | 20551806 | 553 days ago | IN | 0.00021134 ETH | 0.00038654 | ||||
| Execute | 20353076 | 581 days ago | IN | 0.00430763 ETH | 0.00073707 | ||||
| Execute | 20335718 | 583 days ago | IN | 0.00352444 ETH | 0.00415389 | ||||
| Execute | 20333711 | 583 days ago | IN | 0.00144303 ETH | 0.00367841 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Send Message | 22425002 | 291 days ago | 0.00030265 ETH | ||||
| Send Message | 22226669 | 319 days ago | 0.0003578 ETH | ||||
| Send Message | 22129622 | 333 days ago | 0.00244503 ETH | ||||
| Send Message | 22129474 | 333 days ago | 0.00026221 ETH | ||||
| Send Message | 21734286 | 388 days ago | 0.00017945 ETH | ||||
| Send Message | 21719943 | 390 days ago | 0.00017762 ETH | ||||
| Send Message | 21712116 | 391 days ago | 0.00016403 ETH | ||||
| Send Message | 21711813 | 391 days ago | 0.00015853 ETH | ||||
| Send Message | 21633551 | 402 days ago | 0.00017622 ETH | ||||
| Send Message | 21537839 | 415 days ago | 0.00349363 ETH | ||||
| Send Message | 21537775 | 415 days ago | 0.00017052 ETH | ||||
| Send Message | 21506259 | 420 days ago | 0.00016781 ETH | ||||
| Send Message | 21489248 | 422 days ago | 0.00001994 ETH | ||||
| Send Message | 21474096 | 424 days ago | 0.00002638 ETH | ||||
| Send Message | 21144996 | 470 days ago | 0.00508214 ETH | ||||
| Transfer | 20948174 | 498 days ago | 0.50715634 ETH | ||||
| Transfer | 20948174 | 498 days ago | 0.50715634 ETH | ||||
| Send Message | 20730265 | 528 days ago | 0.0002148 ETH | ||||
| Send Message | 20636010 | 541 days ago | 0.00314984 ETH | ||||
| Send Message | 20634471 | 541 days ago | 0.00002002 ETH | ||||
| Send Message | 20600902 | 546 days ago | 0.00288189 ETH | ||||
| Send Message | 20600087 | 546 days ago | 0.00000161 ETH | ||||
| Send Message | 20600080 | 546 days ago | 0.00000203 ETH | ||||
| Send Message | 20551806 | 553 days ago | 0.00021134 ETH | ||||
| Send Message | 20353076 | 581 days ago | 0.00430763 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ActionExecutor
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ReentrancyGuard } from '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import { IActionDataStructures } from './interfaces/IActionDataStructures.sol';
import { IGateway } from './crosschain/interfaces/IGateway.sol';
import { IGatewayClient } from './crosschain/interfaces/IGatewayClient.sol';
import { IRegistry } from './interfaces/IRegistry.sol';
import { ISettings } from './interfaces/ISettings.sol';
import { ITokenMint } from './interfaces/ITokenMint.sol';
import { IVariableBalanceRecords } from './interfaces/IVariableBalanceRecords.sol';
import { IVault } from './interfaces/IVault.sol';
import { BalanceManagement } from './BalanceManagement.sol';
import { CallerGuard } from './CallerGuard.sol';
import { Pausable } from './Pausable.sol';
import { SystemVersionId } from './SystemVersionId.sol';
import { TokenMintError, ZeroAddressError } from './Errors.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './helpers/DecimalsHelper.sol' as DecimalsHelper;
import './helpers/GasReserveHelper.sol' as GasReserveHelper;
import './helpers/RefundHelper.sol' as RefundHelper;
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
/**
* @title ActionExecutor
* @notice The main contract for cross-chain swaps
*/
contract ActionExecutor is
SystemVersionId,
Pausable,
ReentrancyGuard,
CallerGuard,
BalanceManagement,
IGatewayClient,
ISettings,
IActionDataStructures
{
/**
* @notice Source gateway context structure
* @param vault The source vault
* @param assetAmount The source vault asset amount
*/
struct SourceGatewayContext {
IVault vault;
uint256 assetAmount;
}
/**
* @dev The contract for action settings
*/
IRegistry public registry;
/**
* @dev The contract for variable balance storage
*/
IVariableBalanceRecords public variableBalanceRecords;
uint256 private lastActionId = block.chainid * 1e7 + 555 ** 2;
SourceGatewayContext private sourceGatewayContext;
/**
* @notice Emitted when source chain action is performed
* @param actionId The ID of the action
* @param targetChainId The ID of the target chain
* @param sourceSender The address of the user on the source chain
* @param targetRecipient The address of the recipient on the target chain
* @param gatewayType The type of cross-chain gateway
* @param sourceToken The address of the input token on the source chain
* @param targetToken The address of the output token on the target chain
* @param amount The amount of the vault asset used for the action, with decimals set to 18
* @param fee The fee amount, measured in vault asset with decimals set to 18
* @param timestamp The timestamp of the action (in seconds)
*/
event ActionSource(
uint256 indexed actionId,
uint256 indexed targetChainId,
address indexed sourceSender,
address targetRecipient,
uint256 gatewayType,
address sourceToken,
address targetToken,
uint256 amount,
uint256 fee,
uint256 timestamp
);
/**
* @notice Emitted when target chain action is performed
* @param actionId The ID of the action
* @param sourceChainId The ID of the source chain
* @param isSuccess The status of the action execution
* @param timestamp The timestamp of the action (in seconds)
*/
event ActionTarget(
uint256 indexed actionId,
uint256 indexed sourceChainId,
bool indexed isSuccess,
uint256 timestamp
);
/**
* @notice Emitted when single-chain action is performed
* @param actionId The ID of the action
* @param sender The address of the user
* @param recipient The address of the recipient
* @param fromToken The address of the input token
* @param toToken The address of the output token
* @param fromAmount The input token amount
* @param toAmount The output token amount
* @param toTokenFee The fee amount, measured in the output token
* @param timestamp The timestamp of the action (in seconds)
*/
event ActionLocal(
uint256 indexed actionId,
address indexed sender,
address recipient,
address fromToken,
address toToken,
uint256 fromAmount,
uint256 toAmount,
uint256 toTokenFee,
uint256 timestamp
);
/**
* @notice Emitted for source chain and single-chain actions when user's funds processing is completed
* @param actionId The ID of the action
* @param isLocal The action type flag, is true for single-chain actions
* @param sender The address of the user
* @param routerType The type of the swap router
* @param fromTokenAddress The address of the swap input token
* @param toTokenAddress The address of the swap output token
* @param fromAmount The input token amount
* @param resultAmount The swap result token amount
*/
event SourceProcessed(
uint256 indexed actionId,
bool indexed isLocal,
address indexed sender,
uint256 routerType,
address fromTokenAddress,
address toTokenAddress,
uint256 fromAmount,
uint256 resultAmount
);
/**
* @notice Emitted for target chain actions when the user's funds processing is completed
* @param actionId The ID of the action
* @param recipient The address of the recipient
* @param routerType The type of the swap router
* @param fromTokenAddress The address of the swap input token
* @param toTokenAddress The address of the swap output token
* @param fromAmount The input token amount
* @param resultAmount The swap result token amount
*/
event TargetProcessed(
uint256 indexed actionId,
address indexed recipient,
uint256 routerType,
address fromTokenAddress,
address toTokenAddress,
uint256 fromAmount,
uint256 resultAmount
);
/**
* @notice Emitted when the variable balance is allocated on the target chain
* @param actionId The ID of the action
* @param recipient The address of the variable balance recipient
* @param vaultType The type of the corresponding vault
* @param amount The allocated variable balance amount
*/
event VariableBalanceAllocated(
uint256 indexed actionId,
address indexed recipient,
uint256 vaultType,
uint256 amount
);
/**
* @notice Emitted when the Registry contract address is updated
* @param registryAddress The address of the Registry contract
*/
event SetRegistry(address indexed registryAddress);
/**
* @notice Emitted when the VariableBalanceRecords contract address is updated
* @param recordsAddress The address of the VariableBalanceRecords contract
*/
event SetVariableBalanceRecords(address indexed recordsAddress);
/**
* @notice Emitted when the caller is not a registered cross-chain gateway
*/
error OnlyGatewayError();
/**
* @notice Emitted when the call is not from the current contract
*/
error OnlySelfError();
/**
* @notice Emitted when a cross-chain swap is attempted with the target chain ID matching the current chain
*/
error SameChainIdError();
/**
* @notice Emitted when a single-chain swap is attempted with the same token as input and output
*/
error SameTokenError();
/**
* @notice Emitted when the native token value of the transaction does not correspond to the swap amount
*/
error NativeTokenValueError();
/**
* @notice Emitted when the requested cross-chain gateway type is not set
*/
error GatewayNotSetError();
/**
* @notice Emitted when the requested swap router type is not set
*/
error RouterNotSetError();
/**
* @notice Emitted when the requested vault type is not set
*/
error VaultNotSetError();
/**
* @notice Emitted when the provided call value is not sufficient for the cross-chain message sending
*/
error MessageFeeError();
/**
* @notice Emitted when the swap amount is greater than the allowed maximum
*/
error SwapAmountMaxError();
/**
* @notice Emitted when the swap amount is less than the allowed minimum
*/
error SwapAmountMinError();
/**
* @notice Emitted when the swap process results in an error
*/
error SwapError();
/**
* @notice Emitted when there is no matching target swap info option
*/
error TargetSwapInfoError();
/**
* @notice Emitted when the variable balance swap token does not match the vault asset
*/
error VariableBalanceSwapTokenError();
/**
* @notice Emitted when the variable balance swap amount does not match the balance value
*/
error VariableBalanceSwapAmountError();
/**
* @dev Modifier to check if the caller is a registered cross-chain gateway
*/
modifier onlyGateway() {
if (!registry.isGatewayAddress(msg.sender)) {
revert OnlyGatewayError();
}
_;
}
/**
* @dev Modifier to check if the caller is the current contract
*/
modifier onlySelf() {
if (msg.sender != address(this)) {
revert OnlySelfError();
}
_;
}
/**
* @notice Deploys the ActionExecutor contract
* @param _registry The address of the action settings registry contract
* @param _variableBalanceRecords The address of the variable balance records contract
* @param _actionIdOffset The initial offset of the action ID value
* @param _owner The address of the initial owner of the contract
* @param _managers The addresses of initial managers of the contract
* @param _addOwnerToManagers The flag to optionally add the owner to the list of managers
*/
constructor(
IRegistry _registry,
IVariableBalanceRecords _variableBalanceRecords,
uint256 _actionIdOffset,
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) {
_setRegistry(_registry);
_setVariableBalanceRecords(_variableBalanceRecords);
lastActionId += _actionIdOffset;
_initRoles(_owner, _managers, _addOwnerToManagers);
}
/**
* @notice The standard "receive" function
* @dev Is payable to allow receiving native token funds from a target swap router
*/
receive() external payable {}
/**
* @notice Sets the address of the action settings registry contract
* @param _registry The address of the action settings registry contract
*/
function setRegistry(IRegistry _registry) external onlyManager {
_setRegistry(_registry);
}
/**
* @notice Executes a single-chain action
* @param _localAction The parameters of the action
*/
function executeLocal(
LocalAction calldata _localAction
) external payable whenNotPaused nonReentrant checkCaller returns (uint256 actionId) {
return _executeLocal(_localAction, false);
}
/**
* @notice Executes a cross-chain action
* @param _action The parameters of the action
*/
function execute(
Action calldata _action
) external payable whenNotPaused nonReentrant checkCaller returns (uint256 actionId) {
if (_action.targetChainId == block.chainid) {
revert SameChainIdError();
}
// For cross-chain swaps of the native token,
// the value of the transaction should be greater or equal to the swap amount
if (
_action.sourceTokenAddress == Constants.NATIVE_TOKEN_ADDRESS &&
msg.value < _action.sourceSwapInfo.fromAmount
) {
revert NativeTokenValueError();
}
uint256 initialBalance = address(this).balance - msg.value;
lastActionId++;
actionId = lastActionId;
SourceSettings memory settings = registry.sourceSettings(
msg.sender,
_action.targetChainId,
_action.gatewayType,
_action.sourceSwapInfo.routerType,
_action.vaultType
);
if (settings.vault == address(0)) {
revert VaultNotSetError();
}
address vaultAsset = IVault(settings.vault).asset();
(uint256 processedAmount, uint256 nativeTokenSpent) = _processSource(
actionId,
false,
_action.sourceTokenAddress,
vaultAsset,
_action.sourceSwapInfo,
settings.router,
settings.routerTransfer,
false
);
uint256 targetVaultAmountMax = _calculateVaultAmount(
settings.sourceVaultDecimals,
settings.targetVaultDecimals,
processedAmount,
true,
settings.systemFee,
settings.isWhitelist
);
SwapInfo memory targetSwapInfo;
uint256 targetOptionsLength = _action.targetSwapInfoOptions.length;
if (targetOptionsLength == 0) {
targetSwapInfo = SwapInfo({
fromAmount: targetVaultAmountMax,
routerType: uint256(0),
routerData: new bytes(0)
});
} else {
for (uint256 index; index < targetOptionsLength; index++) {
SwapInfo memory targetSwapInfoOption = _action.targetSwapInfoOptions[index];
if (targetSwapInfoOption.fromAmount <= targetVaultAmountMax) {
targetSwapInfo = targetSwapInfoOption;
break;
}
}
if (targetSwapInfo.fromAmount == 0) {
revert TargetSwapInfoError();
}
}
uint256 sourceVaultAmount = DecimalsHelper.convertDecimals(
settings.targetVaultDecimals,
settings.sourceVaultDecimals,
targetSwapInfo.fromAmount
);
uint256 normalizedAmount = DecimalsHelper.convertDecimals(
settings.sourceVaultDecimals,
Constants.DECIMALS_DEFAULT,
sourceVaultAmount
);
if (!settings.isWhitelist) {
_checkSwapAmountLimits(
normalizedAmount,
settings.swapAmountMin,
settings.swapAmountMax
);
}
// - - - Transfer to vault - - -
TransferHelper.safeTransfer(vaultAsset, settings.vault, sourceVaultAmount);
// - - -
bytes memory targetMessageData = abi.encode(
TargetMessage({
actionId: actionId,
sourceSender: msg.sender,
vaultType: _action.vaultType,
targetTokenAddress: _action.targetTokenAddress,
targetSwapInfo: targetSwapInfo,
targetRecipient: _action.targetRecipient == address(0)
? msg.sender
: _action.targetRecipient
})
);
_sendMessage(
settings,
_action,
targetMessageData,
msg.value - nativeTokenSpent,
sourceVaultAmount
);
// - - - System fee transfer - - -
uint256 systemFeeAmount = processedAmount - sourceVaultAmount;
if (systemFeeAmount > 0 && settings.feeCollector != address(0)) {
TransferHelper.safeTransfer(vaultAsset, settings.feeCollector, systemFeeAmount);
}
// - - -
// - - - Extra balance transfer - - -
RefundHelper.refundExtraBalance(address(this), initialBalance, payable(msg.sender));
// - - -
_emitActionSourceEvent(
actionId,
_action,
normalizedAmount,
DecimalsHelper.convertDecimals(
settings.sourceVaultDecimals,
Constants.DECIMALS_DEFAULT,
systemFeeAmount
)
);
}
/**
* @notice Variable token claim by user's variable balance
* @param _vaultType The type of the variable balance vault
*/
function claimVariableToken(
uint256 _vaultType
) external whenNotPaused nonReentrant checkCaller {
_processVariableBalanceRepayment(_vaultType, false, _blankLocalAction());
}
/**
* @notice Vault asset claim by user's variable balance
* @param _vaultType The type of the variable balance vault
*/
function convertVariableBalanceToVaultAsset(
uint256 _vaultType
) external whenNotPaused nonReentrant checkCaller {
_processVariableBalanceRepayment(_vaultType, true, _blankLocalAction());
}
/**
* @notice Vault asset claim by user's variable balance, with subsequent swap
* @param _vaultType The type of the variable balance vault
* @param _localAction The local swap action structure
*/
function convertVariableBalanceWithSwap(
uint256 _vaultType,
LocalAction calldata _localAction
) external whenNotPaused nonReentrant checkCaller {
_processVariableBalanceRepayment(_vaultType, true, _localAction);
}
/**
* @notice Cross-chain message handler on the target chain
* @dev The function is called by cross-chain gateways
* @param _messageSourceChainId The ID of the message source chain
* @param _payloadData The content of the cross-chain message
*/
function handleExecutionPayload(
uint256 _messageSourceChainId,
bytes calldata _payloadData
) external whenNotPaused onlyGateway {
TargetMessage memory targetMessage = abi.decode(_payloadData, (TargetMessage));
TargetSettings memory settings = registry.targetSettings(
targetMessage.vaultType,
targetMessage.targetSwapInfo.routerType
);
bool selfCallSuccess;
(bool hasGasReserve, uint256 gasAllowed) = GasReserveHelper.checkGasReserve(
settings.gasReserve
);
if (hasGasReserve) {
try this.selfCallTarget{ gas: gasAllowed }(settings, targetMessage) {
selfCallSuccess = true;
} catch {}
}
if (!selfCallSuccess) {
_targetAllocateVariableBalance(targetMessage);
}
emit ActionTarget(
targetMessage.actionId,
_messageSourceChainId,
selfCallSuccess,
block.timestamp
);
}
/**
* @notice Controllable processing of the target chain logic
* @dev Is called by the current contract to enable error handling
* @param _settings Target action settings
* @param _targetMessage The content of the cross-chain message
*/
function selfCallTarget(
TargetSettings calldata _settings,
TargetMessage calldata _targetMessage
) external onlySelf {
if (_settings.vault == address(0)) {
revert VaultNotSetError();
}
// - - - Transfer from vault - - -
address assetAddress = IVault(_settings.vault).requestAsset(
_targetMessage.targetSwapInfo.fromAmount,
address(this),
false
);
// - - -
_processTarget(
_settings,
_targetMessage.actionId,
assetAddress,
_targetMessage.targetTokenAddress,
_targetMessage.targetSwapInfo,
_targetMessage.targetRecipient
);
}
function getSourceGatewayContext() external view returns (IVault vault, uint256 assetAmount) {
vault = sourceGatewayContext.vault;
assetAmount = sourceGatewayContext.assetAmount;
}
/**
* @notice Cross-chain message fee estimation
* @param _gatewayType The type of the cross-chain gateway
* @param _targetChainId The ID of the target chain
* @param _targetRouterDataOptions The array of transaction data options for the target chain
* @param _gatewaySettings The settings specific to the selected cross-chain gateway
*/
function messageFeeEstimate(
uint256 _gatewayType,
uint256 _targetChainId,
bytes[] calldata _targetRouterDataOptions,
bytes calldata _gatewaySettings
) external view returns (uint256) {
if (_targetChainId == block.chainid) {
return 0;
}
MessageFeeEstimateSettings memory settings = registry.messageFeeEstimateSettings(
_gatewayType
);
if (settings.gateway == address(0)) {
revert GatewayNotSetError();
}
uint256 result = 0;
if (_targetRouterDataOptions.length == 0) {
result = IGateway(settings.gateway).messageFee(
_targetChainId,
_blankMessage(new bytes(0)),
_gatewaySettings
);
} else {
for (uint256 index; index < _targetRouterDataOptions.length; index++) {
bytes memory messageData = _blankMessage(_targetRouterDataOptions[index]);
uint256 value = IGateway(settings.gateway).messageFee(
_targetChainId,
messageData,
_gatewaySettings
);
if (value > result) {
result = value;
}
}
}
return result;
}
/**
* @notice Swap result amount for single-chain actions, taking the system fee into account
* @param _fromAmount The amount before the calculation
* @param _isForward The direction of the calculation
*/
function calculateLocalAmount(
uint256 _fromAmount,
bool _isForward
) external view returns (uint256 result) {
LocalAmountCalculationSettings memory settings = registry.localAmountCalculationSettings(
msg.sender
);
return
_calculateLocalAmount(
_fromAmount,
_isForward,
settings.systemFeeLocal,
settings.isWhitelist
);
}
/**
* @notice Swap result amount for cross-chain actions, taking the system fee into account
* @param _vaultType The type of the vault
* @param _fromChainId The ID of the source chain
* @param _toChainId The ID of the target chain
* @param _fromAmount The amount before the calculation
* @param _isForward The direction of the calculation
*/
function calculateVaultAmount(
uint256 _vaultType,
uint256 _fromChainId,
uint256 _toChainId,
uint256 _fromAmount,
bool _isForward
) external view returns (uint256 result) {
VaultAmountCalculationSettings memory settings = registry.vaultAmountCalculationSettings(
msg.sender,
_vaultType,
_fromChainId,
_toChainId
);
return
_calculateVaultAmount(
settings.fromDecimals,
settings.toDecimals,
_fromAmount,
_isForward,
settings.systemFee,
settings.isWhitelist
);
}
/**
* @notice The variable balance of the account
* @param _account The address of the variable balance owner
* @param _vaultType The type of the vault
*/
function variableBalance(address _account, uint256 _vaultType) external view returns (uint256) {
return variableBalanceRecords.getAccountBalance(_account, _vaultType);
}
/**
* @notice Swap result amount for single-chain actions from variable balance
* @param _fromAmount The amount before the calculation
*/
function calculateLocalAmountFromVariableBalance(
uint256 _fromAmount,
bool /*_isForward*/
) external pure returns (uint256 result) {
return _fromAmount;
}
function _executeLocal(
LocalAction memory _localAction,
bool _fromVariableBalance
) private returns (uint256 actionId) {
if (_localAction.fromTokenAddress == _localAction.toTokenAddress) {
revert SameTokenError();
}
// For single-chain swaps of the native token,
// the value of the transaction should be equal to the swap amount
if (
_localAction.fromTokenAddress == Constants.NATIVE_TOKEN_ADDRESS &&
msg.value != _localAction.swapInfo.fromAmount
) {
revert NativeTokenValueError();
}
uint256 initialBalance = address(this).balance - msg.value;
lastActionId++;
actionId = lastActionId;
LocalSettings memory settings = registry.localSettings(
msg.sender,
_localAction.swapInfo.routerType
);
(uint256 processedAmount, ) = _processSource(
actionId,
true,
_localAction.fromTokenAddress,
_localAction.toTokenAddress,
_localAction.swapInfo,
settings.router,
settings.routerTransfer,
_fromVariableBalance
);
address recipient = _localAction.recipient == address(0)
? msg.sender
: _localAction.recipient;
uint256 recipientAmount = _fromVariableBalance
? processedAmount
: _calculateLocalAmount(
processedAmount,
true,
settings.systemFeeLocal,
settings.isWhitelist
);
if (_localAction.toTokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(recipient, recipientAmount);
} else {
TransferHelper.safeTransfer(_localAction.toTokenAddress, recipient, recipientAmount);
}
// - - - System fee transfer - - -
uint256 systemFeeAmount = processedAmount - recipientAmount;
if (systemFeeAmount > 0) {
address feeCollector = settings.feeCollectorLocal;
if (feeCollector != address(0)) {
if (_localAction.toTokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(feeCollector, systemFeeAmount);
} else {
TransferHelper.safeTransfer(
_localAction.toTokenAddress,
feeCollector,
systemFeeAmount
);
}
} else if (_localAction.toTokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
initialBalance += systemFeeAmount; // Keep at the contract address
}
}
// - - -
// - - - Extra balance transfer - - -
RefundHelper.refundExtraBalance(address(this), initialBalance, payable(msg.sender));
// - - -
emit ActionLocal(
actionId,
msg.sender,
recipient,
_localAction.fromTokenAddress,
_localAction.toTokenAddress,
_localAction.swapInfo.fromAmount,
recipientAmount,
systemFeeAmount,
block.timestamp
);
}
function _processSource(
uint256 _actionId,
bool _isLocal,
address _fromTokenAddress,
address _toTokenAddress,
SwapInfo memory _sourceSwapInfo,
address _routerAddress,
address _routerTransferAddress,
bool _fromVariableBalance
) private returns (uint256 resultAmount, uint256 nativeTokenSpent) {
uint256 toTokenBalanceBefore = tokenBalance(_toTokenAddress);
if (_fromTokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
if (_routerAddress == address(0)) {
revert RouterNotSetError();
}
// - - - Source swap (native token) - - -
(bool routerCallSuccess, ) = payable(_routerAddress).call{
value: _sourceSwapInfo.fromAmount
}(_sourceSwapInfo.routerData);
if (!routerCallSuccess) {
revert SwapError();
}
// - - -
nativeTokenSpent = _sourceSwapInfo.fromAmount;
} else {
if (!_fromVariableBalance) {
TransferHelper.safeTransferFrom(
_fromTokenAddress,
msg.sender,
address(this),
_sourceSwapInfo.fromAmount
);
}
if (_fromTokenAddress != _toTokenAddress) {
if (_routerAddress == address(0)) {
revert RouterNotSetError();
}
// - - - Source swap (non-native token) - - -
TransferHelper.safeApprove(
_fromTokenAddress,
_routerTransferAddress,
_sourceSwapInfo.fromAmount
);
(bool routerCallSuccess, ) = _routerAddress.call(_sourceSwapInfo.routerData);
if (!routerCallSuccess) {
revert SwapError();
}
TransferHelper.safeApprove(_fromTokenAddress, _routerTransferAddress, 0);
// - - -
}
nativeTokenSpent = 0;
}
resultAmount = tokenBalance(_toTokenAddress) - toTokenBalanceBefore;
emit SourceProcessed(
_actionId,
_isLocal,
msg.sender,
_sourceSwapInfo.routerType,
_fromTokenAddress,
_toTokenAddress,
_sourceSwapInfo.fromAmount,
resultAmount
);
}
function _processTarget(
TargetSettings memory settings,
uint256 _actionId,
address _fromTokenAddress,
address _toTokenAddress,
SwapInfo memory _targetSwapInfo,
address _targetRecipient
) private {
uint256 resultAmount;
if (_toTokenAddress == _fromTokenAddress) {
resultAmount = _targetSwapInfo.fromAmount;
} else {
if (settings.router == address(0)) {
revert RouterNotSetError();
}
uint256 toTokenBalanceBefore = tokenBalance(_toTokenAddress);
// - - - Target swap - - -
TransferHelper.safeApprove(
_fromTokenAddress,
settings.routerTransfer,
_targetSwapInfo.fromAmount
);
(bool success, ) = settings.router.call(_targetSwapInfo.routerData);
if (!success) {
revert SwapError();
}
TransferHelper.safeApprove(_fromTokenAddress, settings.routerTransfer, 0);
// - - -
resultAmount = tokenBalance(_toTokenAddress) - toTokenBalanceBefore;
}
if (_toTokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(_targetRecipient, resultAmount);
} else {
TransferHelper.safeTransfer(_toTokenAddress, _targetRecipient, resultAmount);
}
emit TargetProcessed(
_actionId,
_targetRecipient,
_targetSwapInfo.routerType,
_fromTokenAddress,
_toTokenAddress,
_targetSwapInfo.fromAmount,
resultAmount
);
}
function _targetAllocateVariableBalance(TargetMessage memory _targetMessage) private {
address tokenRecipient = _targetMessage.targetRecipient;
uint256 vaultType = _targetMessage.vaultType;
uint256 tokenAmount = _targetMessage.targetSwapInfo.fromAmount;
variableBalanceRecords.increaseBalance(tokenRecipient, vaultType, tokenAmount);
emit VariableBalanceAllocated(
_targetMessage.actionId,
tokenRecipient,
vaultType,
tokenAmount
);
}
function _processVariableBalanceRepayment(
uint256 _vaultType,
bool _convertToVaultAsset,
LocalAction memory _localAction
) private {
VariableBalanceRepaymentSettings memory settings = registry
.variableBalanceRepaymentSettings(_vaultType);
if (settings.vault == address(0)) {
revert VaultNotSetError();
}
uint256 tokenAmount = variableBalanceRecords.getAccountBalance(msg.sender, _vaultType);
variableBalanceRecords.clearBalance(msg.sender, _vaultType);
if (tokenAmount > 0) {
if (_convertToVaultAsset) {
if (_localAction.fromTokenAddress == address(0)) {
IVault(settings.vault).requestAsset(tokenAmount, msg.sender, true);
} else {
if (_localAction.fromTokenAddress != IVault(settings.vault).asset()) {
revert VariableBalanceSwapTokenError();
}
if (_localAction.swapInfo.fromAmount != tokenAmount) {
revert VariableBalanceSwapAmountError();
}
IVault(settings.vault).requestAsset(tokenAmount, address(this), true);
_executeLocal(_localAction, true);
}
} else {
address variableTokenAddress = IVault(settings.vault).checkVariableTokenState();
bool mintSuccess = ITokenMint(variableTokenAddress).mint(msg.sender, tokenAmount);
if (!mintSuccess) {
revert TokenMintError();
}
}
}
}
function _setRegistry(IRegistry _registry) private {
AddressHelper.requireContract(address(_registry));
registry = _registry;
emit SetRegistry(address(_registry));
}
function _setVariableBalanceRecords(IVariableBalanceRecords _variableBalanceRecords) private {
AddressHelper.requireContract(address(_variableBalanceRecords));
variableBalanceRecords = _variableBalanceRecords;
emit SetVariableBalanceRecords(address(_variableBalanceRecords));
}
function _sendMessage(
SourceSettings memory _settings,
Action calldata _action,
bytes memory _messageData,
uint256 _availableValue,
uint256 _assetAmount
) private {
if (_settings.gateway == address(0)) {
revert GatewayNotSetError();
}
uint256 messageFee = IGateway(_settings.gateway).messageFee(
_action.targetChainId,
_messageData,
_action.gatewaySettings
);
if (_availableValue < messageFee) {
revert MessageFeeError();
}
sourceGatewayContext = SourceGatewayContext({
vault: IVault(_settings.vault),
assetAmount: _assetAmount
});
IGateway(_settings.gateway).sendMessage{ value: messageFee }(
_action.targetChainId,
_messageData,
_action.gatewaySettings
);
delete sourceGatewayContext;
}
function _emitActionSourceEvent(
uint256 _actionId,
Action calldata _action,
uint256 _amount,
uint256 _fee
) private {
emit ActionSource(
_actionId,
_action.targetChainId,
msg.sender,
_action.targetRecipient,
_action.gatewayType,
_action.sourceTokenAddress,
_action.targetTokenAddress,
_amount,
_fee,
block.timestamp
);
}
function _checkSwapAmountLimits(
uint256 _normalizedAmount,
uint256 _swapAmountMin,
uint256 _swapAmountMax
) private pure {
if (_normalizedAmount < _swapAmountMin) {
revert SwapAmountMinError();
}
if (_normalizedAmount > _swapAmountMax) {
revert SwapAmountMaxError();
}
}
function _calculateLocalAmount(
uint256 _fromAmount,
bool _isForward,
uint256 _systemFeeLocal,
bool _isWhitelist
) private pure returns (uint256 result) {
if (_isWhitelist || _systemFeeLocal == 0) {
return _fromAmount;
}
return
_isForward
? (_fromAmount * (Constants.MILLIPERCENT_FACTOR - _systemFeeLocal)) /
Constants.MILLIPERCENT_FACTOR
: (_fromAmount * Constants.MILLIPERCENT_FACTOR) /
(Constants.MILLIPERCENT_FACTOR - _systemFeeLocal);
}
function _calculateVaultAmount(
uint256 _fromDecimals,
uint256 _toDecimals,
uint256 _fromAmount,
bool _isForward,
uint256 _systemFee,
bool _isWhitelist
) private pure returns (uint256 result) {
bool isZeroFee = _isWhitelist || _systemFee == 0;
uint256 amountToConvert = (!_isForward || isZeroFee)
? _fromAmount
: (_fromAmount * (Constants.MILLIPERCENT_FACTOR - _systemFee)) /
Constants.MILLIPERCENT_FACTOR;
uint256 convertedAmount = DecimalsHelper.convertDecimals(
_fromDecimals,
_toDecimals,
amountToConvert
);
result = (_isForward || isZeroFee)
? convertedAmount
: (convertedAmount * Constants.MILLIPERCENT_FACTOR) /
(Constants.MILLIPERCENT_FACTOR - _systemFee);
}
function _blankMessage(bytes memory _targetRouterData) private pure returns (bytes memory) {
bytes memory messageData = abi.encode(
TargetMessage({
actionId: uint256(0),
sourceSender: address(0),
vaultType: uint256(0),
targetTokenAddress: address(0),
targetSwapInfo: SwapInfo({
fromAmount: uint256(0),
routerType: uint256(0),
routerData: _targetRouterData
}),
targetRecipient: address(0)
})
);
return messageData;
}
function _blankLocalAction() private pure returns (LocalAction memory) {
return
LocalAction({
fromTokenAddress: address(0),
toTokenAddress: address(0),
swapInfo: SwapInfo({ fromAmount: 0, routerType: 0, routerData: '' }),
recipient: address(0)
});
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ITokenBalance } from './interfaces/ITokenBalance.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/TransferHelper.sol' as TransferHelper;
import './Constants.sol' as Constants;
/**
* @title BalanceManagement
* @notice Base contract for the withdrawal of tokens, except for reserved ones
*/
abstract contract BalanceManagement is ManagerRole {
/**
* @notice Emitted when the specified token is reserved
*/
error ReservedTokenError();
/**
* @notice Performs the withdrawal of tokens, except for reserved ones
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @param _tokenAmount The amount of the token
*/
function cleanup(address _tokenAddress, uint256 _tokenAmount) external onlyManager {
if (isReservedToken(_tokenAddress)) {
revert ReservedTokenError();
}
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
TransferHelper.safeTransferNative(msg.sender, _tokenAmount);
} else {
TransferHelper.safeTransfer(_tokenAddress, msg.sender, _tokenAmount);
}
}
/**
* @notice Getter of the token balance of the current contract
* @dev Use the "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" address for the native token
* @param _tokenAddress The address of the token
* @return The token balance of the current contract
*/
function tokenBalance(address _tokenAddress) public view returns (uint256) {
if (_tokenAddress == Constants.NATIVE_TOKEN_ADDRESS) {
return address(this).balance;
} else {
return ITokenBalance(_tokenAddress).balanceOf(address(this));
}
}
/**
* @notice Getter of the reserved token flag
* @dev Override to add reserved token addresses
* @param _tokenAddress The address of the token
* @return The reserved token flag
*/
function isReservedToken(address _tokenAddress) public view virtual returns (bool) {
// The function returns false by default.
// The explicit return statement is omitted to avoid the unused parameter warning.
// See https://github.com/ethereum/solidity/issues/5295
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ManagerRole } from './roles/ManagerRole.sol';
import './helpers/AddressHelper.sol' as AddressHelper;
import './Constants.sol' as Constants;
import './DataStructures.sol' as DataStructures;
/**
* @title CallerGuard
* @notice Base contract to control access from other contracts
*/
abstract contract CallerGuard is ManagerRole {
/**
* @dev Caller guard mode enumeration
*/
enum CallerGuardMode {
ContractForbidden,
ContractList,
ContractAllowed
}
/**
* @dev Caller guard mode value
*/
CallerGuardMode public callerGuardMode = CallerGuardMode.ContractForbidden;
/**
* @dev Registered contract list for "ContractList" mode
*/
address[] public listedCallerGuardContractList;
/**
* @dev Registered contract list indices for "ContractList" mode
*/
mapping(address /*account*/ => DataStructures.OptionalValue /*index*/)
public listedCallerGuardContractIndexMap;
/**
* @notice Emitted when the caller guard mode is set
* @param callerGuardMode The caller guard mode
*/
event SetCallerGuardMode(CallerGuardMode indexed callerGuardMode);
/**
* @notice Emitted when a registered contract for "ContractList" mode is added or removed
* @param contractAddress The contract address
* @param isListed The registered contract list inclusion flag
*/
event SetListedCallerGuardContract(address indexed contractAddress, bool indexed isListed);
/**
* @notice Emitted when the caller is not allowed to perform the intended action
*/
error CallerGuardError(address caller);
/**
* @dev Modifier to check if the caller is allowed to perform the intended action
*/
modifier checkCaller() {
if (msg.sender != tx.origin) {
bool condition = (callerGuardMode == CallerGuardMode.ContractAllowed ||
(callerGuardMode == CallerGuardMode.ContractList &&
isListedCallerGuardContract(msg.sender)));
if (!condition) {
revert CallerGuardError(msg.sender);
}
}
_;
}
/**
* @notice Sets the caller guard mode
* @param _callerGuardMode The caller guard mode
*/
function setCallerGuardMode(CallerGuardMode _callerGuardMode) external onlyManager {
callerGuardMode = _callerGuardMode;
emit SetCallerGuardMode(_callerGuardMode);
}
/**
* @notice Updates the list of registered contracts for the "ContractList" mode
* @param _items The addresses and flags for the contracts
*/
function setListedCallerGuardContracts(
DataStructures.AccountToFlag[] calldata _items
) external onlyManager {
for (uint256 index; index < _items.length; index++) {
DataStructures.AccountToFlag calldata item = _items[index];
if (item.flag) {
AddressHelper.requireContract(item.account);
}
DataStructures.uniqueAddressListUpdate(
listedCallerGuardContractList,
listedCallerGuardContractIndexMap,
item.account,
item.flag,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
emit SetListedCallerGuardContract(item.account, item.flag);
}
}
/**
* @notice Getter of the registered contract count
* @return The registered contract count
*/
function listedCallerGuardContractCount() external view returns (uint256) {
return listedCallerGuardContractList.length;
}
/**
* @notice Getter of the complete list of registered contracts
* @return The complete list of registered contracts
*/
function fullListedCallerGuardContractList() external view returns (address[] memory) {
return listedCallerGuardContractList;
}
/**
* @notice Getter of a listed contract flag
* @param _account The contract address
* @return The listed contract flag
*/
function isListedCallerGuardContract(address _account) public view returns (bool) {
return listedCallerGuardContractIndexMap[_account].isSet;
}
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; /** * @dev The default token decimals value */ uint256 constant DECIMALS_DEFAULT = 18; /** * @dev The maximum uint256 value for swap amount limit settings */ uint256 constant INFINITY = type(uint256).max; /** * @dev The default limit of account list size */ uint256 constant LIST_SIZE_LIMIT_DEFAULT = 100; /** * @dev The limit of swap router list size */ uint256 constant LIST_SIZE_LIMIT_ROUTERS = 200; /** * @dev The factor for percentage settings. Example: 100 is 0.1% */ uint256 constant MILLIPERCENT_FACTOR = 100_000; /** * @dev The de facto standard address to denote the native token */ address constant NATIVE_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title IGateway
* @notice Cross-chain gateway interface
*/
interface IGateway {
/**
* @notice Send a cross-chain message
* @param _targetChainId The message target chain ID
* @param _message The message content
* @param _settings The gateway-specific settings
*/
function sendMessage(
uint256 _targetChainId,
bytes calldata _message,
bytes calldata _settings
) external payable;
/**
* @notice Cross-chain message fee estimation
* @param _targetChainId The ID of the target chain
* @param _message The message content
* @param _settings The gateway-specific settings
*/
function messageFee(
uint256 _targetChainId,
bytes calldata _message,
bytes calldata _settings
) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { IVault } from '../../interfaces/IVault.sol';
/**
* @title IGatewayClient
* @notice Cross-chain gateway client interface
*/
interface IGatewayClient {
/**
* @notice The standard "receive" function
*/
receive() external payable;
/**
* @notice Cross-chain message handler on the target chain
* @dev The function is called by cross-chain gateways
* @param _messageSourceChainId The ID of the message source chain
* @param _payloadData The content of the cross-chain message
*/
function handleExecutionPayload(
uint256 _messageSourceChainId,
bytes calldata _payloadData
) external;
/**
* @notice Getter of the source gateway context
* @return vault The source vault
* @return assetAmount The source vault asset amount
*/
function getSourceGatewayContext() external view returns (IVault vault, uint256 assetAmount);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Optional value structure
* @dev Is used in mappings to allow zero values
* @param isSet Value presence flag
* @param value Numeric value
*/
struct OptionalValue {
bool isSet;
uint256 value;
}
/**
* @notice Key-to-value structure
* @dev Is used as an array parameter item to perform multiple key-value settings
* @param key Numeric key
* @param value Numeric value
*/
struct KeyToValue {
uint256 key;
uint256 value;
}
/**
* @notice Key-to-value structure for address values
* @dev Is used as an array parameter item to perform multiple key-value settings with address values
* @param key Numeric key
* @param value Address value
*/
struct KeyToAddressValue {
uint256 key;
address value;
}
/**
* @notice Address-to-flag structure
* @dev Is used as an array parameter item to perform multiple settings
* @param account Account address
* @param flag Flag value
*/
struct AccountToFlag {
address account;
bool flag;
}
/**
* @notice Emitted when a list exceeds the size limit
*/
error ListSizeLimitError();
/**
* @notice Sets or updates a value in a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @param _value The address value
* @param _sizeLimit The map and list size limit
* @return isNewKey True if the key was just added, otherwise false
*/
function combinedMapSet(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key,
address _value,
uint256 _sizeLimit
) returns (bool isNewKey) {
isNewKey = !_keyIndexMap[_key].isSet;
if (isNewKey) {
uniqueListAdd(_keyList, _keyIndexMap, _key, _sizeLimit);
}
_map[_key] = _value;
}
/**
* @notice Removes a value from a combined map (a mapping with a key list and key index mapping)
* @param _map The mapping reference
* @param _keyList The key list reference
* @param _keyIndexMap The key list index mapping reference
* @param _key The numeric key
* @return isChanged True if the combined map was changed, otherwise false
*/
function combinedMapRemove(
mapping(uint256 => address) storage _map,
uint256[] storage _keyList,
mapping(uint256 => OptionalValue) storage _keyIndexMap,
uint256 _key
) returns (bool isChanged) {
isChanged = _keyIndexMap[_key].isSet;
if (isChanged) {
delete _map[_key];
uniqueListRemove(_keyList, _keyIndexMap, _key);
}
}
/**
* @notice Adds a value to a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListAdd(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The numeric value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueListRemove(
uint256[] storage _list,
mapping(uint256 => OptionalValue) storage _indexMap,
uint256 _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
uint256 lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds a value to a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListAdd(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
uint256 _sizeLimit
) returns (bool isChanged) {
isChanged = !_indexMap[_value].isSet;
if (isChanged) {
if (_list.length >= _sizeLimit) {
revert ListSizeLimitError();
}
_indexMap[_value] = OptionalValue(true, _list.length);
_list.push(_value);
}
}
/**
* @notice Removes a value from a unique address value list (a list with value index mapping)
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListRemove(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value
) returns (bool isChanged) {
OptionalValue storage indexItem = _indexMap[_value];
isChanged = indexItem.isSet;
if (isChanged) {
uint256 itemIndex = indexItem.value;
uint256 lastIndex = _list.length - 1;
if (itemIndex != lastIndex) {
address lastValue = _list[lastIndex];
_list[itemIndex] = lastValue;
_indexMap[lastValue].value = itemIndex;
}
_list.pop();
delete _indexMap[_value];
}
}
/**
* @notice Adds or removes a value to/from a unique address value list (a list with value index mapping)
* @dev The list size limit is checked on items adding only
* @param _list The list reference
* @param _indexMap The value index mapping reference
* @param _value The address value
* @param _flag The value inclusion flag
* @param _sizeLimit The list size limit
* @return isChanged True if the list was changed, otherwise false
*/
function uniqueAddressListUpdate(
address[] storage _list,
mapping(address => OptionalValue) storage _indexMap,
address _value,
bool _flag,
uint256 _sizeLimit
) returns (bool isChanged) {
return
_flag
? uniqueAddressListAdd(_list, _indexMap, _value, _sizeLimit)
: uniqueAddressListRemove(_list, _indexMap, _value);
}// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.19; /** * @notice Emitted when an attempt to burn a token fails */ error TokenBurnError(); /** * @notice Emitted when an attempt to mint a token fails */ error TokenMintError(); /** * @notice Emitted when a zero address is specified where it is not allowed */ error ZeroAddressError();
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Emitted when the account is not a contract
* @param account The account address
*/
error NonContractAddressError(address account);
/**
* @notice Function to check if the account is a contract
* @return The account contract status flag
*/
function isContract(address _account) view returns (bool) {
return _account.code.length > 0;
}
/**
* @notice Function to require an account to be a contract
*/
function requireContract(address _account) view {
if (!isContract(_account)) {
revert NonContractAddressError(_account);
}
}
/**
* @notice Function to require an account to be a contract or a zero address
*/
function requireContractOrZeroAddress(address _account) view {
if (_account != address(0)) {
requireContract(_account);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Function to perform decimals conversion
* @param _fromDecimals Source value decimals
* @param _toDecimals Target value decimals
* @param _fromAmount Source value
* @return Target value
*/
function convertDecimals(
uint256 _fromDecimals,
uint256 _toDecimals,
uint256 _fromAmount
) pure returns (uint256) {
if (_toDecimals == _fromDecimals) {
return _fromAmount;
} else if (_toDecimals > _fromDecimals) {
return _fromAmount * 10 ** (_toDecimals - _fromDecimals);
} else {
return _fromAmount / 10 ** (_fromDecimals - _toDecimals);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Function to check if the available gas matches the specified gas reserve value
* @param _gasReserve Gas reserve value
* @return hasGasReserve Flag of gas reserve availability
* @return gasAllowed The remaining gas quantity taking the reserve into account
*/
function checkGasReserve(
uint256 _gasReserve
) view returns (bool hasGasReserve, uint256 gasAllowed) {
uint256 gasLeft = gasleft();
hasGasReserve = gasLeft >= _gasReserve;
gasAllowed = hasGasReserve ? gasLeft - _gasReserve : 0;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import './TransferHelper.sol' as TransferHelper;
/**
* @notice Refunds the extra balance of the native token
* @dev Reverts on subtraction if the actual balance is less than expected
* @param _self The address of the executing contract
* @param _expectedBalance The expected native token balance value
* @param _to The refund receiver's address
*/
function refundExtraBalance(address _self, uint256 _expectedBalance, address payable _to) {
uint256 extraBalance = _self.balance - _expectedBalance;
if (extraBalance > 0) {
TransferHelper.safeTransferNative(_to, extraBalance);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @notice Emitted when an approval action fails
*/
error SafeApproveError();
/**
* @notice Emitted when a transfer action fails
*/
error SafeTransferError();
/**
* @notice Emitted when a transferFrom action fails
*/
error SafeTransferFromError();
/**
* @notice Emitted when a transfer of the native token fails
*/
error SafeTransferNativeError();
/**
* @notice Safely approve the token to the account
* @param _token The token address
* @param _to The token approval recipient address
* @param _value The token approval amount
*/
function safeApprove(address _token, address _to, uint256 _value) {
// 0x095ea7b3 is the selector for "approve(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x095ea7b3, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeApproveError();
}
}
/**
* @notice Safely transfer the token to the account
* @param _token The token address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransfer(address _token, address _to, uint256 _value) {
// 0xa9059cbb is the selector for "transfer(address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0xa9059cbb, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferError();
}
}
/**
* @notice Safely transfer the token between the accounts
* @param _token The token address
* @param _from The token transfer source address
* @param _to The token transfer recipient address
* @param _value The token transfer amount
*/
function safeTransferFrom(address _token, address _from, address _to, uint256 _value) {
// 0x23b872dd is the selector for "transferFrom(address,address,uint256)"
(bool success, bytes memory data) = _token.call(
abi.encodeWithSelector(0x23b872dd, _from, _to, _value)
);
bool condition = success && (data.length == 0 || abi.decode(data, (bool)));
if (!condition) {
revert SafeTransferFromError();
}
}
/**
* @notice Safely transfer the native token to the account
* @param _to The native token transfer recipient address
* @param _value The native token transfer amount
*/
function safeTransferNative(address _to, uint256 _value) {
(bool success, ) = _to.call{ value: _value }(new bytes(0));
if (!success) {
revert SafeTransferNativeError();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title IActionDataStructures
* @notice Action data structure declarations
*/
interface IActionDataStructures {
/**
* @notice Single-chain action data structure
* @param fromTokenAddress The address of the input token
* @param toTokenAddress The address of the output token
* @param swapInfo The data for the single-chain swap
* @param recipient The address of the recipient
*/
struct LocalAction {
address fromTokenAddress;
address toTokenAddress;
SwapInfo swapInfo;
address recipient;
}
/**
* @notice Cross-chain action data structure
* @param gatewayType The numeric type of the cross-chain gateway
* @param vaultType The numeric type of the vault
* @param sourceTokenAddress The address of the input token on the source chain
* @param sourceSwapInfo The data for the source chain swap
* @param targetChainId The action target chain ID
* @param targetTokenAddress The address of the output token on the destination chain
* @param targetSwapInfoOptions The list of data options for the target chain swap
* @param targetRecipient The address of the recipient on the target chain
* @param gatewaySettings The gateway-specific settings data
*/
struct Action {
uint256 gatewayType;
uint256 vaultType;
address sourceTokenAddress;
SwapInfo sourceSwapInfo;
uint256 targetChainId;
address targetTokenAddress;
SwapInfo[] targetSwapInfoOptions;
address targetRecipient;
bytes gatewaySettings;
}
/**
* @notice Token swap data structure
* @param fromAmount The quantity of the token
* @param routerType The numeric type of the swap router
* @param routerData The data for the swap router call
*/
struct SwapInfo {
uint256 fromAmount;
uint256 routerType;
bytes routerData;
}
/**
* @notice Cross-chain message data structure
* @param actionId The unique identifier of the cross-chain action
* @param sourceSender The address of the sender on the source chain
* @param vaultType The numeric type of the vault
* @param targetTokenAddress The address of the output token on the target chain
* @param targetSwapInfo The data for the target chain swap
* @param targetRecipient The address of the recipient on the target chain
*/
struct TargetMessage {
uint256 actionId;
address sourceSender;
uint256 vaultType;
address targetTokenAddress;
SwapInfo targetSwapInfo;
address targetRecipient;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { ISettings } from './ISettings.sol';
interface IRegistry is ISettings {
/**
* @notice Getter of the registered gateway flag by the account address
* @param _account The account address
* @return The registered gateway flag
*/
function isGatewayAddress(address _account) external view returns (bool);
/**
* @notice Settings for a single-chain swap
* @param _caller The user's account address
* @param _routerType The type of the swap router
* @return Settings for a single-chain swap
*/
function localSettings(
address _caller,
uint256 _routerType
) external view returns (LocalSettings memory);
/**
* @notice Getter of source chain settings for a cross-chain swap
* @param _caller The user's account address
* @param _targetChainId The target chain ID
* @param _gatewayType The type of the cross-chain gateway
* @param _routerType The type of the swap router
* @param _vaultType The type of the vault
* @return Source chain settings for a cross-chain swap
*/
function sourceSettings(
address _caller,
uint256 _targetChainId,
uint256 _gatewayType,
uint256 _routerType,
uint256 _vaultType
) external view returns (SourceSettings memory);
/**
* @notice Getter of target chain settings for a cross-chain swap
* @param _vaultType The type of the vault
* @param _routerType The type of the swap router
* @return Target chain settings for a cross-chain swap
*/
function targetSettings(
uint256 _vaultType,
uint256 _routerType
) external view returns (TargetSettings memory);
/**
* @notice Getter of variable balance repayment settings
* @param _vaultType The type of the vault
* @return Variable balance repayment settings
*/
function variableBalanceRepaymentSettings(
uint256 _vaultType
) external view returns (VariableBalanceRepaymentSettings memory);
/**
* @notice Getter of cross-chain message fee estimation settings
* @param _gatewayType The type of the cross-chain gateway
* @return Cross-chain message fee estimation settings
*/
function messageFeeEstimateSettings(
uint256 _gatewayType
) external view returns (MessageFeeEstimateSettings memory);
/**
* @notice Getter of swap result calculation settings for a single-chain swap
* @param _caller The user's account address
* @return Swap result calculation settings for a single-chain swap
*/
function localAmountCalculationSettings(
address _caller
) external view returns (LocalAmountCalculationSettings memory);
/**
* @notice Getter of swap result calculation settings for a cross-chain swap
* @param _caller The user's account address
* @param _vaultType The type of the vault
* @param _fromChainId The ID of the swap source chain
* @param _toChainId The ID of the swap target chain
* @return Swap result calculation settings for a cross-chain swap
*/
function vaultAmountCalculationSettings(
address _caller,
uint256 _vaultType,
uint256 _fromChainId,
uint256 _toChainId
) external view returns (VaultAmountCalculationSettings memory);
/**
* @notice Getter of amount limits in USD for cross-chain swaps
* @param _vaultType The type of the vault
* @return min Minimum cross-chain swap amount in USD, with decimals = 18
* @return max Maximum cross-chain swap amount in USD, with decimals = 18
*/
function swapAmountLimits(uint256 _vaultType) external view returns (uint256 min, uint256 max);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ISettings
* @notice Settings data structure declarations
*/
interface ISettings {
/**
* @notice Settings for a single-chain swap
* @param router The swap router contract address
* @param routerTransfer The swap router transfer contract address
* @param systemFeeLocal The system fee value in milli-percent, e.g., 100 is 0.1%
* @param feeCollectorLocal The address of the single-chain action fee collector
* @param isWhitelist The whitelist flag
*/
struct LocalSettings {
address router;
address routerTransfer;
uint256 systemFeeLocal;
address feeCollectorLocal;
bool isWhitelist;
}
/**
* @notice Source chain settings for a cross-chain swap
* @param gateway The cross-chain gateway contract address
* @param router The swap router contract address
* @param routerTransfer The swap router transfer contract address
* @param vault The vault contract address
* @param sourceVaultDecimals The value of the vault decimals on the source chain
* @param targetVaultDecimals The value of the vault decimals on the target chain
* @param systemFee The system fee value in milli-percent, e.g., 100 is 0.1%
* @param feeCollector The address of the cross-chain action fee collector
* @param isWhitelist The whitelist flag
* @param swapAmountMin The minimum cross-chain swap amount in USD, with decimals = 18
* @param swapAmountMax The maximum cross-chain swap amount in USD, with decimals = 18
*/
struct SourceSettings {
address gateway;
address router;
address routerTransfer;
address vault;
uint256 sourceVaultDecimals;
uint256 targetVaultDecimals;
uint256 systemFee;
address feeCollector;
bool isWhitelist;
uint256 swapAmountMin;
uint256 swapAmountMax;
}
/**
* @notice Target chain settings for a cross-chain swap
* @param router The swap router contract address
* @param routerTransfer The swap router transfer contract address
* @param vault The vault contract address
* @param gasReserve The target chain gas reserve value
*/
struct TargetSettings {
address router;
address routerTransfer;
address vault;
uint256 gasReserve;
}
/**
* @notice Variable balance repayment settings
* @param vault The vault contract address
*/
struct VariableBalanceRepaymentSettings {
address vault;
}
/**
* @notice Cross-chain message fee estimation settings
* @param gateway The cross-chain gateway contract address
*/
struct MessageFeeEstimateSettings {
address gateway;
}
/**
* @notice Swap result calculation settings for a single-chain swap
* @param systemFee The system fee value in milli-percent, e.g., 100 is 0.1%
* @param isWhitelist The whitelist flag
*/
struct LocalAmountCalculationSettings {
uint256 systemFeeLocal;
bool isWhitelist;
}
/**
* @notice Swap result calculation settings for a cross-chain swap
* @param fromDecimals The value of the vault decimals on the source chain
* @param toDecimals The value of the vault decimals on the target chain
* @param systemFee The system fee value in milli-percent, e.g., 100 is 0.1%
* @param isWhitelist The whitelist flag
*/
struct VaultAmountCalculationSettings {
uint256 fromDecimals;
uint256 toDecimals;
uint256 systemFee;
bool isWhitelist;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenBalance
* @notice Token balance interface
*/
interface ITokenBalance {
/**
* @notice Getter of the token balance by the account
* @param _account The account address
* @return Token balance
*/
function balanceOf(address _account) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title ITokenMint
* @notice Token minting interface
*/
interface ITokenMint {
/**
* @notice Mints tokens to the account, increasing the total supply
* @param _to The token receiver account address
* @param _amount The number of tokens to mint
* @return Token burning success status
*/
function mint(address _to, uint256 _amount) external returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title IVariableBalanceRecords
* @notice Variable balance records interface
*/
interface IVariableBalanceRecords {
/**
* @notice Increases the variable balance for the account
* @param _account The account address
* @param _vaultType The vault type
* @param _amount The amount by which to increase the variable balance
*/
function increaseBalance(address _account, uint256 _vaultType, uint256 _amount) external;
/**
* @notice Clears the variable balance for the account
* @param _account The account address
* @param _vaultType The vault type
*/
function clearBalance(address _account, uint256 _vaultType) external;
/**
* @notice Getter of the variable balance by the account
* @param _account The account address
* @param _vaultType The vault type
*/
function getAccountBalance(
address _account,
uint256 _vaultType
) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title IVault
* @notice Vault interface
*/
interface IVault {
/**
* @notice The getter of the vault asset address
*/
function asset() external view returns (address);
/**
* @notice Checks the status of the variable token and balance actions and the variable token address
* @return The address of the variable token
*/
function checkVariableTokenState() external view returns (address);
/**
* @notice Requests the vault asset tokens
* @param _amount The amount of the vault asset tokens
* @param _to The address of the vault asset tokens receiver
* @param _forVariableBalance True if the request is made for a variable balance repayment, otherwise false
* @return assetAddress The address of the vault asset token
*/
function requestAsset(
uint256 _amount,
address _to,
bool _forVariableBalance
) external returns (address assetAddress);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Pausable as PausableBase } from '@openzeppelin/contracts/security/Pausable.sol';
import { ManagerRole } from './roles/ManagerRole.sol';
/**
* @title Pausable
* @notice Base contract that implements the emergency pause mechanism
*/
abstract contract Pausable is PausableBase, ManagerRole {
/**
* @notice Enter pause state
*/
function pause() external onlyManager whenNotPaused {
_pause();
}
/**
* @notice Exit pause state
*/
function unpause() external onlyManager whenPaused {
_unpause();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import { Ownable } from '@openzeppelin/contracts/access/Ownable.sol';
import { RoleBearers } from './RoleBearers.sol';
/**
* @title ManagerRole
* @notice Base contract that implements the Manager role.
* The manager role is a high-permission role for core team members only.
* Managers can set vaults and routers addresses, fees, cross-chain protocols,
* and other parameters for Interchain (cross-chain) swaps and single-network swaps.
* Please note, the manager role is unique for every contract,
* hence different addresses may be assigned as managers for different contracts.
*/
abstract contract ManagerRole is Ownable, RoleBearers {
bytes32 private constant ROLE_KEY = keccak256('Manager');
/**
* @notice Emitted when the Manager role status for the account is updated
* @param account The account address
* @param value The Manager role status flag
*/
event SetManager(address indexed account, bool indexed value);
/**
* @notice Emitted when the Manager role status for the account is renounced
* @param account The account address
*/
event RenounceManagerRole(address indexed account);
/**
* @notice Emitted when the caller is not a Manager role bearer
*/
error OnlyManagerError();
/**
* @dev Modifier to check if the caller is a Manager role bearer
*/
modifier onlyManager() {
if (!isManager(msg.sender)) {
revert OnlyManagerError();
}
_;
}
/**
* @notice Updates the Manager role status for the account
* @param _account The account address
* @param _value The Manager role status flag
*/
function setManager(address _account, bool _value) public onlyOwner {
_setRoleBearer(ROLE_KEY, _account, _value);
emit SetManager(_account, _value);
}
/**
* @notice Renounces the Manager role
*/
function renounceManagerRole() external onlyManager {
_setRoleBearer(ROLE_KEY, msg.sender, false);
emit RenounceManagerRole(msg.sender);
}
/**
* @notice Getter of the Manager role bearer count
* @return The Manager role bearer count
*/
function managerCount() external view returns (uint256) {
return _roleBearerCount(ROLE_KEY);
}
/**
* @notice Getter of the complete list of the Manager role bearers
* @return The complete list of the Manager role bearers
*/
function fullManagerList() external view returns (address[] memory) {
return _fullRoleBearerList(ROLE_KEY);
}
/**
* @notice Getter of the Manager role bearer status
* @param _account The account address
*/
function isManager(address _account) public view returns (bool) {
return _isRoleBearer(ROLE_KEY, _account);
}
function _initRoles(
address _owner,
address[] memory _managers,
bool _addOwnerToManagers
) internal {
address ownerAddress = _owner == address(0) ? msg.sender : _owner;
for (uint256 index; index < _managers.length; index++) {
setManager(_managers[index], true);
}
if (_addOwnerToManagers && !isManager(ownerAddress)) {
setManager(ownerAddress, true);
}
if (ownerAddress != msg.sender) {
transferOwnership(ownerAddress);
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
import '../Constants.sol' as Constants;
import '../DataStructures.sol' as DataStructures;
/**
* @title RoleBearers
* @notice Base contract that implements role-based access control
* @dev A custom implementation providing full role bearer lists
*/
abstract contract RoleBearers {
mapping(bytes32 /*roleKey*/ => address[] /*roleBearers*/) private roleBearerTable;
mapping(bytes32 /*roleKey*/ => mapping(address /*account*/ => DataStructures.OptionalValue /*status*/))
private roleBearerIndexTable;
function _setRoleBearer(bytes32 _roleKey, address _account, bool _value) internal {
DataStructures.uniqueAddressListUpdate(
roleBearerTable[_roleKey],
roleBearerIndexTable[_roleKey],
_account,
_value,
Constants.LIST_SIZE_LIMIT_DEFAULT
);
}
function _isRoleBearer(bytes32 _roleKey, address _account) internal view returns (bool) {
return roleBearerIndexTable[_roleKey][_account].isSet;
}
function _roleBearerCount(bytes32 _roleKey) internal view returns (uint256) {
return roleBearerTable[_roleKey].length;
}
function _fullRoleBearerList(bytes32 _roleKey) internal view returns (address[] memory) {
return roleBearerTable[_roleKey];
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.19;
/**
* @title SystemVersionId
* @notice Base contract providing the system version identifier
*/
abstract contract SystemVersionId {
/**
* @dev The system version identifier
*/
uint256 public constant SYSTEM_VERSION_ID = uint256(keccak256('Circle CCTP - 2023-06-24'));
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IRegistry","name":"_registry","type":"address"},{"internalType":"contract IVariableBalanceRecords","name":"_variableBalanceRecords","type":"address"},{"internalType":"uint256","name":"_actionIdOffset","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address[]","name":"_managers","type":"address[]"},{"internalType":"bool","name":"_addOwnerToManagers","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerGuardError","type":"error"},{"inputs":[],"name":"GatewayNotSetError","type":"error"},{"inputs":[],"name":"ListSizeLimitError","type":"error"},{"inputs":[],"name":"MessageFeeError","type":"error"},{"inputs":[],"name":"NativeTokenValueError","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NonContractAddressError","type":"error"},{"inputs":[],"name":"OnlyGatewayError","type":"error"},{"inputs":[],"name":"OnlyManagerError","type":"error"},{"inputs":[],"name":"OnlySelfError","type":"error"},{"inputs":[],"name":"ReservedTokenError","type":"error"},{"inputs":[],"name":"RouterNotSetError","type":"error"},{"inputs":[],"name":"SafeApproveError","type":"error"},{"inputs":[],"name":"SafeTransferError","type":"error"},{"inputs":[],"name":"SafeTransferFromError","type":"error"},{"inputs":[],"name":"SafeTransferNativeError","type":"error"},{"inputs":[],"name":"SameChainIdError","type":"error"},{"inputs":[],"name":"SameTokenError","type":"error"},{"inputs":[],"name":"SwapAmountMaxError","type":"error"},{"inputs":[],"name":"SwapAmountMinError","type":"error"},{"inputs":[],"name":"SwapError","type":"error"},{"inputs":[],"name":"TargetSwapInfoError","type":"error"},{"inputs":[],"name":"TokenMintError","type":"error"},{"inputs":[],"name":"VariableBalanceSwapAmountError","type":"error"},{"inputs":[],"name":"VariableBalanceSwapTokenError","type":"error"},{"inputs":[],"name":"VaultNotSetError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"fromToken","type":"address"},{"indexed":false,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ActionLocal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"targetChainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"sourceSender","type":"address"},{"indexed":false,"internalType":"address","name":"targetRecipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"gatewayType","type":"uint256"},{"indexed":false,"internalType":"address","name":"sourceToken","type":"address"},{"indexed":false,"internalType":"address","name":"targetToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ActionSource","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"sourceChainId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isSuccess","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ActionTarget","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"RenounceManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum CallerGuard.CallerGuardMode","name":"callerGuardMode","type":"uint8"}],"name":"SetCallerGuardMode","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":true,"internalType":"bool","name":"isListed","type":"bool"}],"name":"SetListedCallerGuardContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"value","type":"bool"}],"name":"SetManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registryAddress","type":"address"}],"name":"SetRegistry","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recordsAddress","type":"address"}],"name":"SetVariableBalanceRecords","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"bool","name":"isLocal","type":"bool"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"routerType","type":"uint256"},{"indexed":false,"internalType":"address","name":"fromTokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"toTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"resultAmount","type":"uint256"}],"name":"SourceProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"routerType","type":"uint256"},{"indexed":false,"internalType":"address","name":"fromTokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"toTokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"resultAmount","type":"uint256"}],"name":"TargetProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"actionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"vaultType","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VariableBalanceAllocated","type":"event"},{"inputs":[],"name":"SYSTEM_VERSION_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"bool","name":"_isForward","type":"bool"}],"name":"calculateLocalAmount","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"name":"calculateLocalAmountFromVariableBalance","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultType","type":"uint256"},{"internalType":"uint256","name":"_fromChainId","type":"uint256"},{"internalType":"uint256","name":"_toChainId","type":"uint256"},{"internalType":"uint256","name":"_fromAmount","type":"uint256"},{"internalType":"bool","name":"_isForward","type":"bool"}],"name":"calculateVaultAmount","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callerGuardMode","outputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultType","type":"uint256"}],"name":"claimVariableToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"cleanup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultType","type":"uint256"}],"name":"convertVariableBalanceToVaultAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultType","type":"uint256"},{"components":[{"internalType":"address","name":"fromTokenAddress","type":"address"},{"internalType":"address","name":"toTokenAddress","type":"address"},{"components":[{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"routerType","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"}],"internalType":"struct IActionDataStructures.SwapInfo","name":"swapInfo","type":"tuple"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IActionDataStructures.LocalAction","name":"_localAction","type":"tuple"}],"name":"convertVariableBalanceWithSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"gatewayType","type":"uint256"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"address","name":"sourceTokenAddress","type":"address"},{"components":[{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"routerType","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"}],"internalType":"struct IActionDataStructures.SwapInfo","name":"sourceSwapInfo","type":"tuple"},{"internalType":"uint256","name":"targetChainId","type":"uint256"},{"internalType":"address","name":"targetTokenAddress","type":"address"},{"components":[{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"routerType","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"}],"internalType":"struct IActionDataStructures.SwapInfo[]","name":"targetSwapInfoOptions","type":"tuple[]"},{"internalType":"address","name":"targetRecipient","type":"address"},{"internalType":"bytes","name":"gatewaySettings","type":"bytes"}],"internalType":"struct IActionDataStructures.Action","name":"_action","type":"tuple"}],"name":"execute","outputs":[{"internalType":"uint256","name":"actionId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"fromTokenAddress","type":"address"},{"internalType":"address","name":"toTokenAddress","type":"address"},{"components":[{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"routerType","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"}],"internalType":"struct IActionDataStructures.SwapInfo","name":"swapInfo","type":"tuple"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IActionDataStructures.LocalAction","name":"_localAction","type":"tuple"}],"name":"executeLocal","outputs":[{"internalType":"uint256","name":"actionId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fullListedCallerGuardContractList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullManagerList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSourceGatewayContext","outputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"uint256","name":"assetAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_messageSourceChainId","type":"uint256"},{"internalType":"bytes","name":"_payloadData","type":"bytes"}],"name":"handleExecutionPayload","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isListedCallerGuardContract","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"listedCallerGuardContractCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"listedCallerGuardContractIndexMap","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"listedCallerGuardContractList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gatewayType","type":"uint256"},{"internalType":"uint256","name":"_targetChainId","type":"uint256"},{"internalType":"bytes[]","name":"_targetRouterDataOptions","type":"bytes[]"},{"internalType":"bytes","name":"_gatewaySettings","type":"bytes"}],"name":"messageFeeEstimate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"routerTransfer","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"gasReserve","type":"uint256"}],"internalType":"struct ISettings.TargetSettings","name":"_settings","type":"tuple"},{"components":[{"internalType":"uint256","name":"actionId","type":"uint256"},{"internalType":"address","name":"sourceSender","type":"address"},{"internalType":"uint256","name":"vaultType","type":"uint256"},{"internalType":"address","name":"targetTokenAddress","type":"address"},{"components":[{"internalType":"uint256","name":"fromAmount","type":"uint256"},{"internalType":"uint256","name":"routerType","type":"uint256"},{"internalType":"bytes","name":"routerData","type":"bytes"}],"internalType":"struct IActionDataStructures.SwapInfo","name":"targetSwapInfo","type":"tuple"},{"internalType":"address","name":"targetRecipient","type":"address"}],"internalType":"struct IActionDataStructures.TargetMessage","name":"_targetMessage","type":"tuple"}],"name":"selfCallTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum CallerGuard.CallerGuardMode","name":"_callerGuardMode","type":"uint8"}],"name":"setCallerGuardMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bool","name":"flag","type":"bool"}],"internalType":"struct AccountToFlag[]","name":"_items","type":"tuple[]"}],"name":"setListedCallerGuardContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_value","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRegistry","name":"_registry","type":"address"}],"name":"setRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_vaultType","type":"uint256"}],"name":"variableBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"variableBalanceRecords","outputs":[{"internalType":"contract IVariableBalanceRecords","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040526004805460ff191690556200001d4662989680620006a6565b6200002c906204b339620006c0565b6009553480156200003c57600080fd5b5060405162005021380380620050218339810160408190526200005f9162000725565b6000805460ff191690556200007433620000c2565b600160035562000084866200011b565b6200008f8562000170565b8360096000828254620000a39190620006c0565b90915550620000b69050838383620001c5565b505050505050620008b4565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b62000126816200027f565b600780546001600160a01b0319166001600160a01b0383169081179091556040517f278c70ced5f3e0e5eeb385b5ff9cb735748ba00a625147e66065ed48fc1562cd90600090a250565b6200017b816200027f565b600880546001600160a01b0319166001600160a01b0383169081179091556040517fd3f42b09987a9b16fb77c8731fc1acfc8c124f7fac825d558856665ae1f68f5990600090a250565b60006001600160a01b03841615620001de5783620001e0565b335b905060005b835181101562000233576200021e84828151811062000208576200020862000856565b60200260200101516001620002bb60201b60201c565b806200022a816200086c565b915050620001e5565b508180156200024a575062000248816200032e565b155b156200025d576200025d816001620002bb565b6001600160a01b03811633146200027957620002798162000370565b50505050565b6001600160a01b0381163b620002b857604051638c50d7cd60e01b81526001600160a01b03821660048201526024015b60405180910390fd5b50565b620002c5620003ec565b620002f27f6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6f838362000450565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff165b92915050565b6200037a620003ec565b6001600160a01b038116620003e15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401620002af565b620002b881620000c2565b6000546001600160a01b036101009091041633146200044e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401620002af565b565b60008381526001602090815260408083206002909252909120620002799190848460646000826200048e5762000488868686620004a6565b6200049c565b6200049c86868685620005db565b9695505050505050565b6001600160a01b0381166000908152602083905260409020805460ff16908115620005d35760018082015486549091600091620004e4919062000888565b90508082146200057857600087828154811062000505576200050562000856565b9060005260206000200160009054906101000a90046001600160a01b03169050808884815481106200053b576200053b62000856565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806200058b576200058b6200089e565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015620006885784548211620006215760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b03881660008181528a83529586209451855460ff1916901515178555915193830193909355885491820189558884529190922090910180546001600160a01b03191690911790555b949350505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176200036a576200036a62000690565b808201808211156200036a576200036a62000690565b6001600160a01b0381168114620002b857600080fd5b8051620006f981620006d6565b919050565b634e487b7160e01b600052604160045260246000fd5b80518015158114620006f957600080fd5b60008060008060008060c087890312156200073f57600080fd5b86516200074c81620006d6565b809650506020808801516200076181620006d6565b604089015160608a015191975095506200077b81620006d6565b60808901519094506001600160401b03808211156200079957600080fd5b818a0191508a601f830112620007ae57600080fd5b815181811115620007c357620007c3620006fe565b8060051b604051601f19603f83011681018181108582111715620007eb57620007eb620006fe565b60405291825284820192508381018501918d8311156200080a57600080fd5b938501935b8285101562000833576200082385620006ec565b845293850193928501926200080f565b8097505050505050506200084a60a0880162000714565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b60006001820162000881576200088162000690565b5060010190565b818103818111156200036a576200036a62000690565b634e487b7160e01b600052603160045260246000fd5b61475d80620008c46000396000f3fe6080604052600436106102345760003560e01c80637734095e1161012e578063c2c518e1116100ab578063f3ae24151161006f578063f3ae2415146106fc578063f41621671461071c578063f6b3fe1d1461073c578063f977350c1461075c578063fe14e8c31461077c57600080fd5b8063c2c518e114610673578063e3725b1514610688578063e74c5a251461069d578063eedc966a146106bc578063f2fde38b146106dc57600080fd5b80638da5cb5b116100f25780638da5cb5b146105dd5780639f48768514610600578063a5e90eee14610613578063a91ee0dc14610633578063b20f56391461065357600080fd5b80637734095e1461053d5780637b1039991461055d5780637b25b4d414610595578063819bc4b9146105b55780638456cb59146105c857600080fd5b806338d9e86f116101bc5780635c975abb116101805780635c975abb146104b4578063607ab5e5146104cc578063655a79e0146104f35780636b56a69114610513578063715018a61461052857600080fd5b806338d9e86f1461041e5780633d5439a51461043e5780633f4ba83a1461045e578063440d72481461047357806348db6d771461049457600080fd5b80631351b8f0116102035780631351b8f01461031857806317daf0b41461033a57806330261be01461036a57806330eb1278146103ad578063341328c5146103cd57600080fd5b806304e535e214610240578063052756511461026b578063093f0e2714610299578063103b7397146102cd57600080fd5b3661023b57005b600080fd5b34801561024c57600080fd5b5061025561079c565b604051610262919061380a565b60405180910390f35b34801561027757600080fd5b5061028b610286366004613865565b6107fe565b604051908152602001610262565b3480156102a557600080fd5b5061028b7f5391aee72d8c7a0be2c29e25e2dff78c1031b115905af6093591f9742b1fbcc981565b3480156102d957600080fd5b5060008051602061470883398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a5461028b565b34801561032457600080fd5b506103386103333660046138ca565b6108b4565b005b34801561034657600080fd5b5061035a610355366004613925565b610962565b6040519015158152602001610262565b34801561037657600080fd5b5061038e600a54600b546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610262565b3480156103b957600080fd5b506103386103c8366004613942565b610980565b3480156103d957600080fd5b506104076103e8366004613925565b6006602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610262565b34801561042a57600080fd5b5061028b610439366004613942565b6109e0565b34801561044a57600080fd5b5061033861045936600461396e565b610a5f565b34801561046a57600080fd5b50610338610b01565b34801561047f57600080fd5b5061035a61048e366004613925565b50600090565b3480156104a057600080fd5b506103386104af36600461396e565b610b39565b3480156104c057600080fd5b5060005460ff1661035a565b3480156104d857600080fd5b506004546104e69060ff1681565b604051610262919061399d565b3480156104ff57600080fd5b5061033861050e366004613a0d565b610bce565b34801561051f57600080fd5b5060055461028b565b34801561053457600080fd5b50610338610dc8565b34801561054957600080fd5b50610338610558366004613a58565b610dda565b34801561056957600080fd5b5060075461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610262565b3480156105a157600080fd5b5061057d6105b036600461396e565b610f25565b61028b6105c3366004613aad565b610f4f565b3480156105d457600080fd5b50610338611527565b3480156105e957600080fd5b5060005461010090046001600160a01b031661057d565b61028b61060e366004613ae8565b61155d565b34801561061f57600080fd5b5061033861062e366004613b1c565b611605565b34801561063f57600080fd5b5061033861064e366004613925565b611662565b34801561065f57600080fd5b5061028b61066e366004613b4a565b611691565b34801561067f57600080fd5b506103386118f7565b34801561069457600080fd5b50610255611964565b3480156106a957600080fd5b5061028b6106b8366004613bfd565b5090565b3480156106c857600080fd5b5061028b6106d7366004613925565b61197d565b3480156106e857600080fd5b506103386106f7366004613925565b611a13565b34801561070857600080fd5b5061035a610717366004613925565b611a89565b34801561072857600080fd5b5061028b610737366004613bfd565b611ac9565b34801561074857600080fd5b5060085461057d906001600160a01b031681565b34801561076857600080fd5b50610338610777366004613c22565b611b57565b34801561078857600080fd5b50610338610797366004613c43565b611bdf565b606060058054806020026020016040519081016040528092919081815260200182805480156107f457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107d6575b5050505050905090565b600754604051631771177960e11b815233600482015260248101879052604481018690526064810185905260009182916001600160a01b0390911690632ee22ef290608401608060405180830381865afa158015610860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108849190613d97565b90506108a481600001518260200151868685604001518660600151611ceb565b979650505050505050565b905090565b6108bc611d8a565b6108c4611dd0565b333214610940576000600260045460ff1660028111156108e6576108e6613987565b14806109175750600160045460ff16600281111561090657610906613987565b148015610917575061091733610962565b90508061093e57604051630fa0970d60e11b81523360048201526024015b60405180910390fd5b505b61095482600161094f84613e95565b611e29565b61095e6001600355565b5050565b6001600160a01b031660009081526006602052604090205460ff1690565b61098933611a89565b6109a657604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038316016109d55761095e3382612289565b61095e823383612317565b600854604051638758e33960e01b81526001600160a01b038481166004830152602482018490526000921690638758e33990604401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190613f13565b90505b92915050565b610a67611d8a565b610a6f611dd0565b333214610ae6576000600260045460ff166002811115610a9157610a91613987565b1480610ac25750600160045460ff166002811115610ab157610ab1613987565b148015610ac25750610ac233610962565b905080610ae457604051630fa0970d60e11b8152336004820152602401610935565b505b610af481600161094f612409565b610afe6001600355565b50565b610b0a33611a89565b610b2757604051637c3ea23f60e01b815260040160405180910390fd5b610b2f612480565b610b376124c9565b565b610b41611d8a565b610b49611dd0565b333214610bc0576000600260045460ff166002811115610b6b57610b6b613987565b1480610b9c5750600160045460ff166002811115610b8b57610b8b613987565b148015610b9c5750610b9c33610962565b905080610bbe57604051630fa0970d60e11b8152336004820152602401610935565b505b610af481600061094f612409565b610bd6611d8a565b6007546040516307f9220960e41b81523360048201526001600160a01b0390911690637f92209090602401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c429190613f2c565b610c5f57604051635d3da26d60e01b815260040160405180910390fd5b6000610c6d82840184613f49565b60075460408083015160808401516020015191516308f59d7960e21b81529394506000936001600160a01b03909316926323d675e492610cb99291600401918252602082015260400190565b608060405180830381865afa158015610cd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfa9190614011565b90506000806000610d0e846060015161251b565b915091508115610d7557604051633b9a04af60e11b81523090637734095e908390610d3f9088908a90600401614149565b600060405180830381600088803b158015610d5957600080fd5b5087f193505050508015610d6b575060015b15610d7557600192505b82610d8357610d8385612547565b8451604051428152841515918a917fc678724853e8a8ed1f6ed64e9efc05afa8c6826d63a2c42e33fbd4697ff458459060200160405180910390a45050505050505050565b610dd0612616565b610b376000612676565b333014610dfa576040516328a2ea3b60e01b815260040160405180910390fd5b6000610e0c6060840160408501613925565b6001600160a01b031603610e3357604051630b24de4b60e01b815260040160405180910390fd5b6000610e456060840160408501613925565b6001600160a01b0316634b15b2a9610e60608085018561418f565b60405160e083901b6001600160e01b031916815290356004820152306024820152600060448201526064016020604051808303816000875af1158015610eaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ece91906141af565b9050610f20610ee2368590038501856141cc565b833583610ef56080870160608801613925565b610f02608088018861418f565b610f0b9061422c565b610f1b60c0890160a08a01613925565b6126cf565b505050565b60058181548110610f3557600080fd5b6000918252602090912001546001600160a01b0316905081565b6000610f59611d8a565b610f61611dd0565b333214610fd8576000600260045460ff166002811115610f8357610f83613987565b1480610fb45750600160045460ff166002811115610fa357610fa3613987565b148015610fb45750610fb433610962565b905080610fd657604051630fa0970d60e11b8152336004820152602401610935565b505b46826080013503610ffc5760405163785a29dd60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6110216060840160408501613925565b6001600160a01b0316148015611043575061103f606083018361418f565b3534105b1561106157604051637dd7aa2160e01b815260040160405180910390fd5b600061106d344761424e565b60098054919250600061107f83614261565b90915550506009546007549092506000906001600160a01b031663322f243233608087013587356110b360608a018a61418f565b6040516001600160e01b031960e087901b1681526001600160a01b039094166004850152602484019290925260448301526020908101356064830152870135608482015260a40161016060405180830381865afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061427a565b60608101519091506001600160a01b031661116a57604051630b24de4b60e01b815260040160405180910390fd5b600081606001516001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d291906141af565b905060008061121486826111ec60608b0160408c01613925565b866111fa60608d018d61418f565b6112039061422c565b89602001518a604001516000612898565b91509150600061123a85608001518660a001518560018960c001518a6101000151611ceb565b905061126060405180606001604052806000815260200160008152602001606081525090565b600061126f60c08b018b614333565b90509050806000036112e05760405180606001604052808481526020016000815260200160006001600160401b038111156112ac576112ac613cb7565b6040519080825280601f01601f1916602001820160405280156112d6576020820181803683370190505b509052915061136f565b60005b8181101561134c5760006112fa60c08d018d614333565b8381811061130a5761130a61437c565b905060200281019061131c919061418f565b6113259061422c565b90508481600001511161133957925061134c565b508061134481614261565b9150506112e3565b50815160000361136f57604051637755fda760e01b815260040160405180910390fd5b60006113888860a0015189608001518560000151612b21565b9050600061139c8960800151601284612b21565b90508861010001516113bd576113bd818a61012001518b6101400151612b85565b6113cc888a6060015184612317565b60006040518060c001604052808d8152602001336001600160a01b031681526020018e6020013581526020018e60a001602081019061140b9190613925565b6001600160a01b0316815260200186815260200160006001600160a01b03168f60e001602081019061143d9190613925565b6001600160a01b031614611463578e60e001602081019061145e9190613925565b611465565b335b6001600160a01b031690526040516114809190602001614392565b60408051601f1981840301815291905290506114a88a8e836114a28b3461424e565b87612bc7565b60006114b4848a61424e565b90506000811180156114d2575060e08b01516001600160a01b031615155b156114e6576114e68a8c60e0015183612317565b6114f1308d33612d61565b61150c8d8f856115078f60800151601287612b21565b612d8f565b5050505050505050505050506115226001600355565b919050565b61153033611a89565b61154d57604051637c3ea23f60e01b815260040160405180910390fd5b611555611d8a565b610b37612e37565b6000611567611d8a565b61156f611dd0565b3332146115e6576000600260045460ff16600281111561159157611591613987565b14806115c25750600160045460ff1660028111156115b1576115b1613987565b1480156115c257506115c233610962565b9050806115e457604051630fa0970d60e11b8152336004820152602401610935565b505b6115f96115f283613e95565b6000612e74565b90506115226001600355565b61160d612616565b61162660008051602061470883398151915283836131b9565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b61166b33611a89565b61168857604051637c3ea23f60e01b815260040160405180910390fd5b610afe816131e0565b60004686036116a2575060006118ed565b6007546040516318fa0c2360e21b8152600481018990526000916001600160a01b0316906363e8308c90602401602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906143f4565b80519091506001600160a01b031661173b5760405163ba8ec24160e01b815260040160405180910390fd5b60008581036117db5781516040805160008152602081019091526001600160a01b039091169063aa4fc83d908a9061177290613233565b88886040518563ffffffff1660e01b81526004016117939493929190614410565b602060405180830381865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190613f13565b90506118e9565b60005b868110156118e75760006118498989848181106117fd576117fd61437c565b905060200281019061180f919061445d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323392505050565b9050600084600001516001600160a01b031663aa4fc83d8c848b8b6040518563ffffffff1660e01b81526004016118839493929190614410565b602060405180830381865afa1580156118a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c49190613f13565b9050838111156118d2578093505b505080806118df90614261565b9150506117de565b505b9150505b9695505050505050565b61190033611a89565b61191d57604051637c3ea23f60e01b815260040160405180910390fd5b6119376000805160206147088339815191523360006131b9565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b60606108af6000805160206147088339815191526132c7565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038316016119ab575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156119ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190613f13565b611a1b612616565b6001600160a01b038116611a805760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610935565b610afe81612676565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16610a59565b600754604051631a5a276d60e31b815233600482015260009182916001600160a01b039091169063d2d13b68906024016040805180830381865afa158015611b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3991906144a3565b9050611b4f848483600001518460200151613333565b949350505050565b611b6033611a89565b611b7d57604051637c3ea23f60e01b815260040160405180910390fd5b6004805482919060ff19166001836002811115611b9c57611b9c613987565b0217905550806002811115611bb357611bb3613987565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b611be833611a89565b611c0557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610f205736838383818110611c2357611c2361437c565b9050604002019050806020016020810190611c3e91906144f8565b15611c5857611c58611c536020830183613925565b6133a4565b611c8360056006611c6c6020850185613925565b611c7c60408601602087016144f8565b60646133d7565b50611c9460408201602083016144f8565b1515611ca36020830183613925565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a35080611ce381614261565b915050611c08565b6000808280611cf8575083155b90506000851580611d065750815b611d3157620186a0611d18868261424e565b611d229089614515565b611d2c919061452c565b611d33565b865b90506000611d428a8a84612b21565b90508680611d4d5750825b611d7a57611d5e86620186a061424e565b611d6b620186a083614515565b611d75919061452c565b611d7c565b805b9a9950505050505050505050565b60005460ff1615610b375760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610935565b600260035403611e225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610935565b6002600355565b60075460405163154d267d60e21b8152600481018590526000916001600160a01b03169063553499f490602401602060405180830381865afa158015611e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9791906143f4565b80519091506001600160a01b0316611ec257604051630b24de4b60e01b815260040160405180910390fd5b600854604051638758e33960e01b8152336004820152602481018690526000916001600160a01b031690638758e33990604401602060405180830381865afa158015611f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f369190613f13565b6008546040516227421b60e61b8152336004820152602481018890529192506001600160a01b0316906309d086c090604401600060405180830381600087803b158015611f8257600080fd5b505af1158015611f96573d6000803e3d6000fd5b5050505060008111156122825783156121805782516001600160a01b0316612039578151604051634b15b2a960e01b815260048101839052336024820152600160448201526001600160a01b0390911690634b15b2a9906064016020604051808303816000875af115801561200f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203391906141af565b50612282565b81600001516001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209f91906141af565b6001600160a01b031683600001516001600160a01b0316146120d4576040516308bdb4f360e11b815260040160405180910390fd5b60408301515181146120f9576040516363782bc160e01b815260040160405180910390fd5b8151604051634b15b2a960e01b815260048101839052306024820152600160448201526001600160a01b0390911690634b15b2a9906064016020604051808303816000875af1158015612150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217491906141af565b50612033836001612e74565b600082600001516001600160a01b0316632c966a346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e891906141af565b6040516340c10f1960e01b8152336004820152602481018490529091506000906001600160a01b038316906340c10f19906044016020604051808303816000875af115801561223b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225f9190613f2c565b90508061227f576040516320aaed5f60e21b815260040160405180910390fd5b50505b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040516122b3919061454e565b60006040518083038185875af1925050503d80600081146122f0576040519150601f19603f3d011682016040523d82523d6000602084013e6122f5565b606091505b5050905080610f2057604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691612373919061454e565b6000604051808303816000865af19150503d80600081146123b0576040519150601f19603f3d011682016040523d82523d6000602084013e6123b5565b606091505b509150915060008280156123e15750815115806123e15750818060200190518101906123e19190613f2c565b90508061240157604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b6124116137ae565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b031681526020016040518060600160405280600081526020016000815260200160405180602001604052806000815250815250815260200160006001600160a01b0316815250905090565b60005460ff16610b375760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610935565b6124d1612480565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60008060005a90508381101592508261253557600061253f565b61253f848261424e565b915050915091565b60a08101516040808301516080840151516008549251631e9f7a9b60e01b81526001600160a01b03808616600483015260248201849052604482018390529293919290911690631e9f7a9b90606401600060405180830381600087803b1580156125b057600080fd5b505af11580156125c4573d6000803e3d6000fd5b5050855160408051868152602081018690526001600160a01b03881694509192507fb9e12bbbbed208a973bc1ec9604e1f6d7f4b91b193fc2e1150df974b7d16635b910160405180910390a350505050565b6000546001600160a01b03610100909104163314610b375760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610935565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6000846001600160a01b0316846001600160a01b0316036126f2575081516127e9565b86516001600160a01b031661271a5760405163ebb12eb360e01b815260040160405180910390fd5b60006127258561197d565b905061273a86896020015186600001516133fa565b600088600001516001600160a01b0316856040015160405161275c919061454e565b6000604051808303816000865af19150503d8060008114612799576040519150601f19603f3d011682016040523d82523d6000602084013e61279e565b606091505b50509050806127c057604051633e1f5ce560e11b815260040160405180910390fd5b6127d0878a6020015160006133fa565b816127da8761197d565b6127e4919061424e565b925050505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0385160161281d576128188282612289565b612828565b612828848383612317565b6020808401518451604080519283526001600160a01b0389811694840194909452878416908301526060820152608081018390529083169087907f26e7a43f3221294fff6b57719103b3bfdeb1c06dac5c3973de3e55932e7c1b3b9060a00160405180910390a350505050505050565b60008060006128a68861197d565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038a1601612985576001600160a01b0386166128f45760405163ebb12eb360e01b815260040160405180910390fd5b6000866001600160a01b031688600001518960400151604051612917919061454e565b60006040518083038185875af1925050503d8060008114612954576040519150601f19603f3d011682016040523d82523d6000602084013e612959565b606091505b505090508061297b57604051633e1f5ce560e11b815260040160405180910390fd5b5086519150612a7e565b8361299a5761299a8933308a600001516134e4565b876001600160a01b0316896001600160a01b031614612a79576001600160a01b0386166129da5760405163ebb12eb360e01b815260040160405180910390fd5b6129e9898689600001516133fa565b6000866001600160a01b03168860400151604051612a07919061454e565b6000604051808303816000865af19150503d8060008114612a44576040519150601f19603f3d011682016040523d82523d6000602084013e612a49565b606091505b5050905080612a6b57604051633e1f5ce560e11b815260040160405180910390fd5b612a778a8760006133fa565b505b600091505b80612a888961197d565b612a92919061424e565b9250336001600160a01b03168a15158c7f580273492d266e8e27b4253a13c46e1c74823e94794f9ad186ca8fe8b109e3ef8a602001518d8d8d600001518a604051612b0b9594939291909485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b60405180910390a4509850989650505050505050565b6000838303612b31575080612b7e565b83831115612b5f57612b43848461424e565b612b4e90600a614644565b612b589083614515565b9050612b7e565b612b69838561424e565b612b7490600a614644565b612b58908361452c565b9392505050565b81831015612ba657604051632220ee1360e11b815260040160405180910390fd5b80831115610f205760405163341cc20160e21b815260040160405180910390fd5b84516001600160a01b0316612bef5760405163ba8ec24160e01b815260040160405180910390fd5b84516000906001600160a01b031663aa4fc83d608087013586612c166101008a018a61445d565b6040518563ffffffff1660e01b8152600401612c359493929190614410565b602060405180830381865afa158015612c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c769190613f13565b905080831015612c9857604051625a4bb360e21b815260040160405180910390fd5b6040805180820190915260608701516001600160a01b039081168083526020909201849052600a80546001600160a01b031916909217909155600b839055865116636ea9cec982608088013587612cf36101008b018b61445d565b6040518663ffffffff1660e01b8152600401612d129493929190614410565b6000604051808303818588803b158015612d2b57600080fd5b505af1158015612d3f573d6000803e3d6000fd5b5050600a80546001600160a01b031916905550506000600b5550505050505050565b6000612d77836001600160a01b0386163161424e565b90508015612d8957612d898282612289565b50505050565b336080840135857fc2ad425216cf8ac56ecd38af0315ed35266cb6771f34fc27e1f0cde1a5b3eb6a612dc8610100880160e08901613925565b8735612dda60608a0160408b01613925565b612dea60c08b0160a08c01613925565b604080516001600160a01b03958616815260208101949094529184168383015290921660608201526080810188905260a081018790524260c082015290519081900360e00190a450505050565b612e3f611d8a565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124fe3390565b600082602001516001600160a01b031683600001516001600160a01b031603612eb057604051633b0e2de560e21b815260040160405180910390fd5b82516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015612ee257506040830151513414155b15612f0057604051637dd7aa2160e01b815260040160405180910390fd5b6000612f0c344761424e565b600980549192506000612f1e83614261565b90915550506009546007546040868101516020015190516379b6eb2760e11b815233600482015260248101919091529193506000916001600160a01b039091169063f36dd64e9060440160a060405180830381865afa158015612f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa99190614650565b90506000612fd2846001886000015189602001518a60400151876000015188602001518c612898565b5060608701519091506000906001600160a01b031615612ff6578660600151612ff8565b335b905060008661301b5761301683600186604001518760800151613333565b61301d565b825b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031688602001516001600160a01b03160361305f5761305a8282612289565b61306e565b61306e88602001518383612317565b600061307a828561424e565b905080156131255760608501516001600160a01b038116156130e55773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03168a602001516001600160a01b0316036130d6576130d18183612289565b613123565b6130d18a602001518284612317565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03168a602001516001600160a01b0316036131235761312082886146de565b96505b505b613130308733612d61565b88516020808b01516040808d01515181516001600160a01b03808a16825295861694810194909452939091169082015260608101919091526080810183905260a081018290524260c0820152339088907f64f803250cc450b9c5e2cef3ac4c82370f41b8c1e5692f4067b6b96d2430bfcb9060e00160405180910390a350505050505092915050565b60008381526001602090815260408083206002909252909120612d899190848460646133d7565b6131e9816133a4565b600780546001600160a01b0319166001600160a01b0383169081179091556040517f278c70ced5f3e0e5eeb385b5ff9cb735748ba00a625147e66065ed48fc1562cd90600090a250565b606060006040518060c001604052806000815260200160006001600160a01b031681526020016000815260200160006001600160a01b031681526020016040518060600160405280600081526020016000815260200186815250815260200160006001600160a01b03168152506040516020016132b09190614392565b60408051601f198184030181529190529392505050565b60008181526001602090815260409182902080548351818402810184019094528084526060939283018282801561332757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613309575b50505050509050919050565b6000818061333f575082155b1561334b575083611b4f565b836133795761335d83620186a061424e565b61336a620186a087614515565b613374919061452c565b61339b565b620186a0613387848261424e565b6133919087614515565b61339b919061452c565b95945050505050565b6001600160a01b0381163b610afe57604051638c50d7cd60e01b81526001600160a01b0382166004820152602401610935565b6000826133ee576133e98686866135d6565b6118ed565b6118ed868686856136fe565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1790529151600092839290871691613456919061454e565b6000604051808303816000865af19150503d8060008114613493576040519150601f19603f3d011682016040523d82523d6000602084013e613498565b606091505b509150915060008280156134c45750815115806134c45750818060200190518101906134c49190613f2c565b9050806124015760405163b45d44e760e01b815260040160405180910390fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613548919061454e565b6000604051808303816000865af19150503d8060008114613585576040519150601f19603f3d011682016040523d82523d6000602084013e61358a565b606091505b509150915060008280156135b65750815115806135b65750818060200190518101906135b69190613f2c565b90508061227f57604051632d9d5b4160e01b815260040160405180910390fd5b6001600160a01b0381166000908152602083905260409020805460ff169081156136f65760018082015486549091600091613611919061424e565b905080821461369e57600087828154811061362e5761362e61437c565b9060005260206000200160009054906101000a90046001600160a01b03169050808884815481106136615761366161437c565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806136ae576136ae6146f1565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015611b4f57845482116137425760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b031681526020016137fd60405180606001604052806000815260200160008152602001606081525090565b8152600060209091015290565b6020808252825182820181905260009190848201906040850190845b8181101561384b5783516001600160a01b031683529284019291840191600101613826565b50909695505050505050565b8015158114610afe57600080fd5b600080600080600060a0868803121561387d57600080fd5b8535945060208601359350604086013592506060860135915060808601356138a481613857565b809150509295509295909350565b6000608082840312156138c457600080fd5b50919050565b600080604083850312156138dd57600080fd5b8235915060208301356001600160401b038111156138fa57600080fd5b613906858286016138b2565b9150509250929050565b6001600160a01b0381168114610afe57600080fd5b60006020828403121561393757600080fd5b8135612b7e81613910565b6000806040838503121561395557600080fd5b823561396081613910565b946020939093013593505050565b60006020828403121561398057600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600383106139bf57634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f8401126139d757600080fd5b5081356001600160401b038111156139ee57600080fd5b602083019150836020828501011115613a0657600080fd5b9250929050565b600080600060408486031215613a2257600080fd5b8335925060208401356001600160401b03811115613a3f57600080fd5b613a4b868287016139c5565b9497909650939450505050565b60008060a08385031215613a6b57600080fd5b613a7584846138b2565b915060808301356001600160401b03811115613a9057600080fd5b830160c08186031215613aa257600080fd5b809150509250929050565b600060208284031215613abf57600080fd5b81356001600160401b03811115613ad557600080fd5b82016101208185031215612b7e57600080fd5b600060208284031215613afa57600080fd5b81356001600160401b03811115613b1057600080fd5b611b4f848285016138b2565b60008060408385031215613b2f57600080fd5b8235613b3a81613910565b91506020830135613aa281613857565b60008060008060008060808789031215613b6357600080fd5b863595506020870135945060408701356001600160401b0380821115613b8857600080fd5b818901915089601f830112613b9c57600080fd5b813581811115613bab57600080fd5b8a60208260051b8501011115613bc057600080fd5b602083019650809550506060890135915080821115613bde57600080fd5b50613beb89828a016139c5565b979a9699509497509295939492505050565b60008060408385031215613c1057600080fd5b823591506020830135613aa281613857565b600060208284031215613c3457600080fd5b813560038110612b7e57600080fd5b60008060208385031215613c5657600080fd5b82356001600160401b0380821115613c6d57600080fd5b818501915085601f830112613c8157600080fd5b813581811115613c9057600080fd5b8660208260061b8501011115613ca557600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613cef57613cef613cb7565b60405290565b604051606081016001600160401b0381118282101715613cef57613cef613cb7565b60405160c081016001600160401b0381118282101715613cef57613cef613cb7565b60405161016081016001600160401b0381118282101715613cef57613cef613cb7565b604051601f8201601f191681016001600160401b0381118282101715613d8457613d84613cb7565b604052919050565b805161152281613857565b600060808284031215613da957600080fd5b613db1613ccd565b8251815260208301516020820152604083015160408201526060830151613dd781613857565b60608201529392505050565b600060608284031215613df557600080fd5b613dfd613cf5565b9050813581526020808301358183015260408301356001600160401b0380821115613e2757600080fd5b818501915085601f830112613e3b57600080fd5b813581811115613e4d57613e4d613cb7565b613e5f601f8201601f19168501613d5c565b91508082528684828501011115613e7557600080fd5b808484018584013760008482840101525080604085015250505092915050565b600060808236031215613ea757600080fd5b613eaf613ccd565b8235613eba81613910565b81526020830135613eca81613910565b602082015260408301356001600160401b03811115613ee857600080fd5b613ef436828601613de3565b6040830152506060830135613f0881613910565b606082015292915050565b600060208284031215613f2557600080fd5b5051919050565b600060208284031215613f3e57600080fd5b8151612b7e81613857565b600060208284031215613f5b57600080fd5b81356001600160401b0380821115613f7257600080fd5b9083019060c08286031215613f8657600080fd5b613f8e613d17565b823581526020830135613fa081613910565b6020820152604083810135908201526060830135613fbd81613910565b6060820152608083013582811115613fd457600080fd5b613fe087828601613de3565b60808301525060a08301359250613ff683613910565b60a0810192909252509392505050565b805161152281613910565b60006080828403121561402357600080fd5b61402b613ccd565b825161403681613910565b8152602083015161404681613910565b6020820152604083015161405981613910565b60408201526060928301519281019290925250919050565b60005b8381101561408c578181015183820152602001614074565b50506000910152565b600081518084526140ad816020860160208601614071565b601f01601f19169290920160200192915050565b805182526000602082015160018060a01b038082166020860152604084015160408601528060608501511660608601525050608082015160c06080850152805160c0850152602081015160e085015260408101519050606061010085015261412d610120850182614095565b905060a08301516136f660a08601826001600160a01b03169052565b600060018060a01b03808551168352806020860151166020840152806040860151166040840152506060840151606083015260a06080830152611b4f60a08301846140c1565b60008235605e198336030181126141a557600080fd5b9190910192915050565b6000602082840312156141c157600080fd5b8151612b7e81613910565b6000608082840312156141de57600080fd5b6141e6613ccd565b82356141f181613910565b8152602083013561420181613910565b6020820152604083013561421481613910565b60408201526060928301359281019290925250919050565b6000610a593683613de3565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a5957610a59614238565b60006001820161427357614273614238565b5060010190565b6000610160828403121561428d57600080fd5b614295613d39565b61429e83614006565b81526142ac60208401614006565b60208201526142bd60408401614006565b60408201526142ce60608401614006565b60608201526080830151608082015260a083015160a082015260c083015160c08201526142fd60e08401614006565b60e0820152610100614310818501613d8c565b908201526101208381015190820152610140928301519281019290925250919050565b6000808335601e1984360301811261434a57600080fd5b8301803591506001600160401b0382111561436457600080fd5b6020019150600581901b3603821315613a0657600080fd5b634e487b7160e01b600052603260045260246000fd5b602081526000610a5660208301846140c1565b6000602082840312156143b757600080fd5b604051602081018181106001600160401b03821117156143d9576143d9613cb7565b806040525080915082516143ec81613910565b905292915050565b60006020828403121561440657600080fd5b610a5683836143a5565b8481526060602082015260006144296060830186614095565b8281036040840152838152838560208301376000602085830101526020601f19601f86011682010191505095945050505050565b6000808335601e1984360301811261447457600080fd5b8301803591506001600160401b0382111561448e57600080fd5b602001915036819003821315613a0657600080fd5b6000604082840312156144b557600080fd5b604051604081018181106001600160401b03821117156144d7576144d7613cb7565b6040528251815260208301516144ec81613857565b60208201529392505050565b60006020828403121561450a57600080fd5b8135612b7e81613857565b8082028115828204841417610a5957610a59614238565b60008261454957634e487b7160e01b600052601260045260246000fd5b500490565b600082516141a5818460208701614071565b600181815b8085111561459b57816000190482111561458157614581614238565b8085161561458e57918102915b93841c9390800290614565565b509250929050565b6000826145b257506001610a59565b816145bf57506000610a59565b81600181146145d557600281146145df576145fb565b6001915050610a59565b60ff8411156145f0576145f0614238565b50506001821b610a59565b5060208310610133831016604e8410600b841016171561461e575081810a610a59565b6146288383614560565b806000190482111561463c5761463c614238565b029392505050565b6000610a5683836145a3565b600060a0828403121561466257600080fd5b60405160a081018181106001600160401b038211171561468457614684613cb7565b604052825161469281613910565b815260208301516146a281613910565b60208201526040838101519082015260608301516146bf81613910565b606082015260808301516146d281613857565b60808201529392505050565b80820180821115610a5957610a59614238565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220bf8fe89df48fd06e15a1680f4a63c9c22e8ce51bf8f24d24d0b346382636907564736f6c6343000813003300000000000000000000000000c90e949f95ffead18e35c1fac84327f2ea9fdb00000000000000000000000056b7b130b2dfca12820184515839bdad5c649fc900000000000000000000000000000000000000000000000000000000004c4b4000000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78
Deployed Bytecode
0x6080604052600436106102345760003560e01c80637734095e1161012e578063c2c518e1116100ab578063f3ae24151161006f578063f3ae2415146106fc578063f41621671461071c578063f6b3fe1d1461073c578063f977350c1461075c578063fe14e8c31461077c57600080fd5b8063c2c518e114610673578063e3725b1514610688578063e74c5a251461069d578063eedc966a146106bc578063f2fde38b146106dc57600080fd5b80638da5cb5b116100f25780638da5cb5b146105dd5780639f48768514610600578063a5e90eee14610613578063a91ee0dc14610633578063b20f56391461065357600080fd5b80637734095e1461053d5780637b1039991461055d5780637b25b4d414610595578063819bc4b9146105b55780638456cb59146105c857600080fd5b806338d9e86f116101bc5780635c975abb116101805780635c975abb146104b4578063607ab5e5146104cc578063655a79e0146104f35780636b56a69114610513578063715018a61461052857600080fd5b806338d9e86f1461041e5780633d5439a51461043e5780633f4ba83a1461045e578063440d72481461047357806348db6d771461049457600080fd5b80631351b8f0116102035780631351b8f01461031857806317daf0b41461033a57806330261be01461036a57806330eb1278146103ad578063341328c5146103cd57600080fd5b806304e535e214610240578063052756511461026b578063093f0e2714610299578063103b7397146102cd57600080fd5b3661023b57005b600080fd5b34801561024c57600080fd5b5061025561079c565b604051610262919061380a565b60405180910390f35b34801561027757600080fd5b5061028b610286366004613865565b6107fe565b604051908152602001610262565b3480156102a557600080fd5b5061028b7f5391aee72d8c7a0be2c29e25e2dff78c1031b115905af6093591f9742b1fbcc981565b3480156102d957600080fd5b5060008051602061470883398151915260005260016020527f3c2285c553468ca8f30447b24bb463c127f1b840e23a0cafa23caa79d906669a5461028b565b34801561032457600080fd5b506103386103333660046138ca565b6108b4565b005b34801561034657600080fd5b5061035a610355366004613925565b610962565b6040519015158152602001610262565b34801561037657600080fd5b5061038e600a54600b546001600160a01b0390911691565b604080516001600160a01b039093168352602083019190915201610262565b3480156103b957600080fd5b506103386103c8366004613942565b610980565b3480156103d957600080fd5b506104076103e8366004613925565b6006602052600090815260409020805460019091015460ff9091169082565b604080519215158352602083019190915201610262565b34801561042a57600080fd5b5061028b610439366004613942565b6109e0565b34801561044a57600080fd5b5061033861045936600461396e565b610a5f565b34801561046a57600080fd5b50610338610b01565b34801561047f57600080fd5b5061035a61048e366004613925565b50600090565b3480156104a057600080fd5b506103386104af36600461396e565b610b39565b3480156104c057600080fd5b5060005460ff1661035a565b3480156104d857600080fd5b506004546104e69060ff1681565b604051610262919061399d565b3480156104ff57600080fd5b5061033861050e366004613a0d565b610bce565b34801561051f57600080fd5b5060055461028b565b34801561053457600080fd5b50610338610dc8565b34801561054957600080fd5b50610338610558366004613a58565b610dda565b34801561056957600080fd5b5060075461057d906001600160a01b031681565b6040516001600160a01b039091168152602001610262565b3480156105a157600080fd5b5061057d6105b036600461396e565b610f25565b61028b6105c3366004613aad565b610f4f565b3480156105d457600080fd5b50610338611527565b3480156105e957600080fd5b5060005461010090046001600160a01b031661057d565b61028b61060e366004613ae8565b61155d565b34801561061f57600080fd5b5061033861062e366004613b1c565b611605565b34801561063f57600080fd5b5061033861064e366004613925565b611662565b34801561065f57600080fd5b5061028b61066e366004613b4a565b611691565b34801561067f57600080fd5b506103386118f7565b34801561069457600080fd5b50610255611964565b3480156106a957600080fd5b5061028b6106b8366004613bfd565b5090565b3480156106c857600080fd5b5061028b6106d7366004613925565b61197d565b3480156106e857600080fd5b506103386106f7366004613925565b611a13565b34801561070857600080fd5b5061035a610717366004613925565b611a89565b34801561072857600080fd5b5061028b610737366004613bfd565b611ac9565b34801561074857600080fd5b5060085461057d906001600160a01b031681565b34801561076857600080fd5b50610338610777366004613c22565b611b57565b34801561078857600080fd5b50610338610797366004613c43565b611bdf565b606060058054806020026020016040519081016040528092919081815260200182805480156107f457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107d6575b5050505050905090565b600754604051631771177960e11b815233600482015260248101879052604481018690526064810185905260009182916001600160a01b0390911690632ee22ef290608401608060405180830381865afa158015610860573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108849190613d97565b90506108a481600001518260200151868685604001518660600151611ceb565b979650505050505050565b905090565b6108bc611d8a565b6108c4611dd0565b333214610940576000600260045460ff1660028111156108e6576108e6613987565b14806109175750600160045460ff16600281111561090657610906613987565b148015610917575061091733610962565b90508061093e57604051630fa0970d60e11b81523360048201526024015b60405180910390fd5b505b61095482600161094f84613e95565b611e29565b61095e6001600355565b5050565b6001600160a01b031660009081526006602052604090205460ff1690565b61098933611a89565b6109a657604051637c3ea23f60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038316016109d55761095e3382612289565b61095e823383612317565b600854604051638758e33960e01b81526001600160a01b038481166004830152602482018490526000921690638758e33990604401602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a569190613f13565b90505b92915050565b610a67611d8a565b610a6f611dd0565b333214610ae6576000600260045460ff166002811115610a9157610a91613987565b1480610ac25750600160045460ff166002811115610ab157610ab1613987565b148015610ac25750610ac233610962565b905080610ae457604051630fa0970d60e11b8152336004820152602401610935565b505b610af481600161094f612409565b610afe6001600355565b50565b610b0a33611a89565b610b2757604051637c3ea23f60e01b815260040160405180910390fd5b610b2f612480565b610b376124c9565b565b610b41611d8a565b610b49611dd0565b333214610bc0576000600260045460ff166002811115610b6b57610b6b613987565b1480610b9c5750600160045460ff166002811115610b8b57610b8b613987565b148015610b9c5750610b9c33610962565b905080610bbe57604051630fa0970d60e11b8152336004820152602401610935565b505b610af481600061094f612409565b610bd6611d8a565b6007546040516307f9220960e41b81523360048201526001600160a01b0390911690637f92209090602401602060405180830381865afa158015610c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c429190613f2c565b610c5f57604051635d3da26d60e01b815260040160405180910390fd5b6000610c6d82840184613f49565b60075460408083015160808401516020015191516308f59d7960e21b81529394506000936001600160a01b03909316926323d675e492610cb99291600401918252602082015260400190565b608060405180830381865afa158015610cd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfa9190614011565b90506000806000610d0e846060015161251b565b915091508115610d7557604051633b9a04af60e11b81523090637734095e908390610d3f9088908a90600401614149565b600060405180830381600088803b158015610d5957600080fd5b5087f193505050508015610d6b575060015b15610d7557600192505b82610d8357610d8385612547565b8451604051428152841515918a917fc678724853e8a8ed1f6ed64e9efc05afa8c6826d63a2c42e33fbd4697ff458459060200160405180910390a45050505050505050565b610dd0612616565b610b376000612676565b333014610dfa576040516328a2ea3b60e01b815260040160405180910390fd5b6000610e0c6060840160408501613925565b6001600160a01b031603610e3357604051630b24de4b60e01b815260040160405180910390fd5b6000610e456060840160408501613925565b6001600160a01b0316634b15b2a9610e60608085018561418f565b60405160e083901b6001600160e01b031916815290356004820152306024820152600060448201526064016020604051808303816000875af1158015610eaa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ece91906141af565b9050610f20610ee2368590038501856141cc565b833583610ef56080870160608801613925565b610f02608088018861418f565b610f0b9061422c565b610f1b60c0890160a08a01613925565b6126cf565b505050565b60058181548110610f3557600080fd5b6000918252602090912001546001600160a01b0316905081565b6000610f59611d8a565b610f61611dd0565b333214610fd8576000600260045460ff166002811115610f8357610f83613987565b1480610fb45750600160045460ff166002811115610fa357610fa3613987565b148015610fb45750610fb433610962565b905080610fd657604051630fa0970d60e11b8152336004820152602401610935565b505b46826080013503610ffc5760405163785a29dd60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6110216060840160408501613925565b6001600160a01b0316148015611043575061103f606083018361418f565b3534105b1561106157604051637dd7aa2160e01b815260040160405180910390fd5b600061106d344761424e565b60098054919250600061107f83614261565b90915550506009546007549092506000906001600160a01b031663322f243233608087013587356110b360608a018a61418f565b6040516001600160e01b031960e087901b1681526001600160a01b039094166004850152602484019290925260448301526020908101356064830152870135608482015260a40161016060405180830381865afa158015611118573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061113c919061427a565b60608101519091506001600160a01b031661116a57604051630b24de4b60e01b815260040160405180910390fd5b600081606001516001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d291906141af565b905060008061121486826111ec60608b0160408c01613925565b866111fa60608d018d61418f565b6112039061422c565b89602001518a604001516000612898565b91509150600061123a85608001518660a001518560018960c001518a6101000151611ceb565b905061126060405180606001604052806000815260200160008152602001606081525090565b600061126f60c08b018b614333565b90509050806000036112e05760405180606001604052808481526020016000815260200160006001600160401b038111156112ac576112ac613cb7565b6040519080825280601f01601f1916602001820160405280156112d6576020820181803683370190505b509052915061136f565b60005b8181101561134c5760006112fa60c08d018d614333565b8381811061130a5761130a61437c565b905060200281019061131c919061418f565b6113259061422c565b90508481600001511161133957925061134c565b508061134481614261565b9150506112e3565b50815160000361136f57604051637755fda760e01b815260040160405180910390fd5b60006113888860a0015189608001518560000151612b21565b9050600061139c8960800151601284612b21565b90508861010001516113bd576113bd818a61012001518b6101400151612b85565b6113cc888a6060015184612317565b60006040518060c001604052808d8152602001336001600160a01b031681526020018e6020013581526020018e60a001602081019061140b9190613925565b6001600160a01b0316815260200186815260200160006001600160a01b03168f60e001602081019061143d9190613925565b6001600160a01b031614611463578e60e001602081019061145e9190613925565b611465565b335b6001600160a01b031690526040516114809190602001614392565b60408051601f1981840301815291905290506114a88a8e836114a28b3461424e565b87612bc7565b60006114b4848a61424e565b90506000811180156114d2575060e08b01516001600160a01b031615155b156114e6576114e68a8c60e0015183612317565b6114f1308d33612d61565b61150c8d8f856115078f60800151601287612b21565b612d8f565b5050505050505050505050506115226001600355565b919050565b61153033611a89565b61154d57604051637c3ea23f60e01b815260040160405180910390fd5b611555611d8a565b610b37612e37565b6000611567611d8a565b61156f611dd0565b3332146115e6576000600260045460ff16600281111561159157611591613987565b14806115c25750600160045460ff1660028111156115b1576115b1613987565b1480156115c257506115c233610962565b9050806115e457604051630fa0970d60e11b8152336004820152602401610935565b505b6115f96115f283613e95565b6000612e74565b90506115226001600355565b61160d612616565b61162660008051602061470883398151915283836131b9565b604051811515906001600160a01b038416907fbe9474bb3e78da7e315cdffa5cfa30b767fcc95bbf44a6197da60228eea1028690600090a35050565b61166b33611a89565b61168857604051637c3ea23f60e01b815260040160405180910390fd5b610afe816131e0565b60004686036116a2575060006118ed565b6007546040516318fa0c2360e21b8152600481018990526000916001600160a01b0316906363e8308c90602401602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906143f4565b80519091506001600160a01b031661173b5760405163ba8ec24160e01b815260040160405180910390fd5b60008581036117db5781516040805160008152602081019091526001600160a01b039091169063aa4fc83d908a9061177290613233565b88886040518563ffffffff1660e01b81526004016117939493929190614410565b602060405180830381865afa1580156117b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d49190613f13565b90506118e9565b60005b868110156118e75760006118498989848181106117fd576117fd61437c565b905060200281019061180f919061445d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061323392505050565b9050600084600001516001600160a01b031663aa4fc83d8c848b8b6040518563ffffffff1660e01b81526004016118839493929190614410565b602060405180830381865afa1580156118a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c49190613f13565b9050838111156118d2578093505b505080806118df90614261565b9150506117de565b505b9150505b9695505050505050565b61190033611a89565b61191d57604051637c3ea23f60e01b815260040160405180910390fd5b6119376000805160206147088339815191523360006131b9565b60405133907f6cc2c67081f55c2fffb7c008fa995fbbf890f48c7c16fba93d8220f00dc84cc590600090a2565b60606108af6000805160206147088339815191526132c7565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038316016119ab575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa1580156119ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a599190613f13565b611a1b612616565b6001600160a01b038116611a805760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610935565b610afe81612676565b6001600160a01b03811660009081527f260b29b219d450563ddb0e5ca806bdadb1e125f7e8c506de0443797dd7122728602052604081205460ff16610a59565b600754604051631a5a276d60e31b815233600482015260009182916001600160a01b039091169063d2d13b68906024016040805180830381865afa158015611b15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3991906144a3565b9050611b4f848483600001518460200151613333565b949350505050565b611b6033611a89565b611b7d57604051637c3ea23f60e01b815260040160405180910390fd5b6004805482919060ff19166001836002811115611b9c57611b9c613987565b0217905550806002811115611bb357611bb3613987565b6040517f332a9f1d3bd9b0f7abbd95838fed6b417589632d0eb33f2d8ae6e2aa17178efd90600090a250565b611be833611a89565b611c0557604051637c3ea23f60e01b815260040160405180910390fd5b60005b81811015610f205736838383818110611c2357611c2361437c565b9050604002019050806020016020810190611c3e91906144f8565b15611c5857611c58611c536020830183613925565b6133a4565b611c8360056006611c6c6020850185613925565b611c7c60408601602087016144f8565b60646133d7565b50611c9460408201602083016144f8565b1515611ca36020830183613925565b6001600160a01b03167f1470aed653fa8a8ce4c7b2f41287634199f7ec3c4f5fd0ace97d82cf006beec360405160405180910390a35080611ce381614261565b915050611c08565b6000808280611cf8575083155b90506000851580611d065750815b611d3157620186a0611d18868261424e565b611d229089614515565b611d2c919061452c565b611d33565b865b90506000611d428a8a84612b21565b90508680611d4d5750825b611d7a57611d5e86620186a061424e565b611d6b620186a083614515565b611d75919061452c565b611d7c565b805b9a9950505050505050505050565b60005460ff1615610b375760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610935565b600260035403611e225760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610935565b6002600355565b60075460405163154d267d60e21b8152600481018590526000916001600160a01b03169063553499f490602401602060405180830381865afa158015611e73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e9791906143f4565b80519091506001600160a01b0316611ec257604051630b24de4b60e01b815260040160405180910390fd5b600854604051638758e33960e01b8152336004820152602481018690526000916001600160a01b031690638758e33990604401602060405180830381865afa158015611f12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f369190613f13565b6008546040516227421b60e61b8152336004820152602481018890529192506001600160a01b0316906309d086c090604401600060405180830381600087803b158015611f8257600080fd5b505af1158015611f96573d6000803e3d6000fd5b5050505060008111156122825783156121805782516001600160a01b0316612039578151604051634b15b2a960e01b815260048101839052336024820152600160448201526001600160a01b0390911690634b15b2a9906064016020604051808303816000875af115801561200f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061203391906141af565b50612282565b81600001516001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061209f91906141af565b6001600160a01b031683600001516001600160a01b0316146120d4576040516308bdb4f360e11b815260040160405180910390fd5b60408301515181146120f9576040516363782bc160e01b815260040160405180910390fd5b8151604051634b15b2a960e01b815260048101839052306024820152600160448201526001600160a01b0390911690634b15b2a9906064016020604051808303816000875af1158015612150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217491906141af565b50612033836001612e74565b600082600001516001600160a01b0316632c966a346040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e891906141af565b6040516340c10f1960e01b8152336004820152602481018490529091506000906001600160a01b038316906340c10f19906044016020604051808303816000875af115801561223b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225f9190613f2c565b90508061227f576040516320aaed5f60e21b815260040160405180910390fd5b50505b5050505050565b604080516000808252602082019092526001600160a01b0384169083906040516122b3919061454e565b60006040518083038185875af1925050503d80600081146122f0576040519150601f19603f3d011682016040523d82523d6000602084013e6122f5565b606091505b5050905080610f2057604051632e05b05360e21b815260040160405180910390fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691612373919061454e565b6000604051808303816000865af19150503d80600081146123b0576040519150601f19603f3d011682016040523d82523d6000602084013e6123b5565b606091505b509150915060008280156123e15750815115806123e15750818060200190518101906123e19190613f2c565b90508061240157604051632fdb1b7f60e11b815260040160405180910390fd5b505050505050565b6124116137ae565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b031681526020016040518060600160405280600081526020016000815260200160405180602001604052806000815250815250815260200160006001600160a01b0316815250905090565b60005460ff16610b375760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610935565b6124d1612480565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60008060005a90508381101592508261253557600061253f565b61253f848261424e565b915050915091565b60a08101516040808301516080840151516008549251631e9f7a9b60e01b81526001600160a01b03808616600483015260248201849052604482018390529293919290911690631e9f7a9b90606401600060405180830381600087803b1580156125b057600080fd5b505af11580156125c4573d6000803e3d6000fd5b5050855160408051868152602081018690526001600160a01b03881694509192507fb9e12bbbbed208a973bc1ec9604e1f6d7f4b91b193fc2e1150df974b7d16635b910160405180910390a350505050565b6000546001600160a01b03610100909104163314610b375760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610935565b600080546001600160a01b03838116610100818102610100600160a81b0319851617855560405193049190911692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35050565b6000846001600160a01b0316846001600160a01b0316036126f2575081516127e9565b86516001600160a01b031661271a5760405163ebb12eb360e01b815260040160405180910390fd5b60006127258561197d565b905061273a86896020015186600001516133fa565b600088600001516001600160a01b0316856040015160405161275c919061454e565b6000604051808303816000865af19150503d8060008114612799576040519150601f19603f3d011682016040523d82523d6000602084013e61279e565b606091505b50509050806127c057604051633e1f5ce560e11b815260040160405180910390fd5b6127d0878a6020015160006133fa565b816127da8761197d565b6127e4919061424e565b925050505b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0385160161281d576128188282612289565b612828565b612828848383612317565b6020808401518451604080519283526001600160a01b0389811694840194909452878416908301526060820152608081018390529083169087907f26e7a43f3221294fff6b57719103b3bfdeb1c06dac5c3973de3e55932e7c1b3b9060a00160405180910390a350505050505050565b60008060006128a68861197d565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038a1601612985576001600160a01b0386166128f45760405163ebb12eb360e01b815260040160405180910390fd5b6000866001600160a01b031688600001518960400151604051612917919061454e565b60006040518083038185875af1925050503d8060008114612954576040519150601f19603f3d011682016040523d82523d6000602084013e612959565b606091505b505090508061297b57604051633e1f5ce560e11b815260040160405180910390fd5b5086519150612a7e565b8361299a5761299a8933308a600001516134e4565b876001600160a01b0316896001600160a01b031614612a79576001600160a01b0386166129da5760405163ebb12eb360e01b815260040160405180910390fd5b6129e9898689600001516133fa565b6000866001600160a01b03168860400151604051612a07919061454e565b6000604051808303816000865af19150503d8060008114612a44576040519150601f19603f3d011682016040523d82523d6000602084013e612a49565b606091505b5050905080612a6b57604051633e1f5ce560e11b815260040160405180910390fd5b612a778a8760006133fa565b505b600091505b80612a888961197d565b612a92919061424e565b9250336001600160a01b03168a15158c7f580273492d266e8e27b4253a13c46e1c74823e94794f9ad186ca8fe8b109e3ef8a602001518d8d8d600001518a604051612b0b9594939291909485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b60405180910390a4509850989650505050505050565b6000838303612b31575080612b7e565b83831115612b5f57612b43848461424e565b612b4e90600a614644565b612b589083614515565b9050612b7e565b612b69838561424e565b612b7490600a614644565b612b58908361452c565b9392505050565b81831015612ba657604051632220ee1360e11b815260040160405180910390fd5b80831115610f205760405163341cc20160e21b815260040160405180910390fd5b84516001600160a01b0316612bef5760405163ba8ec24160e01b815260040160405180910390fd5b84516000906001600160a01b031663aa4fc83d608087013586612c166101008a018a61445d565b6040518563ffffffff1660e01b8152600401612c359493929190614410565b602060405180830381865afa158015612c52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c769190613f13565b905080831015612c9857604051625a4bb360e21b815260040160405180910390fd5b6040805180820190915260608701516001600160a01b039081168083526020909201849052600a80546001600160a01b031916909217909155600b839055865116636ea9cec982608088013587612cf36101008b018b61445d565b6040518663ffffffff1660e01b8152600401612d129493929190614410565b6000604051808303818588803b158015612d2b57600080fd5b505af1158015612d3f573d6000803e3d6000fd5b5050600a80546001600160a01b031916905550506000600b5550505050505050565b6000612d77836001600160a01b0386163161424e565b90508015612d8957612d898282612289565b50505050565b336080840135857fc2ad425216cf8ac56ecd38af0315ed35266cb6771f34fc27e1f0cde1a5b3eb6a612dc8610100880160e08901613925565b8735612dda60608a0160408b01613925565b612dea60c08b0160a08c01613925565b604080516001600160a01b03958616815260208101949094529184168383015290921660608201526080810188905260a081018790524260c082015290519081900360e00190a450505050565b612e3f611d8a565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586124fe3390565b600082602001516001600160a01b031683600001516001600160a01b031603612eb057604051633b0e2de560e21b815260040160405180910390fd5b82516001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015612ee257506040830151513414155b15612f0057604051637dd7aa2160e01b815260040160405180910390fd5b6000612f0c344761424e565b600980549192506000612f1e83614261565b90915550506009546007546040868101516020015190516379b6eb2760e11b815233600482015260248101919091529193506000916001600160a01b039091169063f36dd64e9060440160a060405180830381865afa158015612f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa99190614650565b90506000612fd2846001886000015189602001518a60400151876000015188602001518c612898565b5060608701519091506000906001600160a01b031615612ff6578660600151612ff8565b335b905060008661301b5761301683600186604001518760800151613333565b61301d565b825b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b031688602001516001600160a01b03160361305f5761305a8282612289565b61306e565b61306e88602001518383612317565b600061307a828561424e565b905080156131255760608501516001600160a01b038116156130e55773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03168a602001516001600160a01b0316036130d6576130d18183612289565b613123565b6130d18a602001518284612317565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03168a602001516001600160a01b0316036131235761312082886146de565b96505b505b613130308733612d61565b88516020808b01516040808d01515181516001600160a01b03808a16825295861694810194909452939091169082015260608101919091526080810183905260a081018290524260c0820152339088907f64f803250cc450b9c5e2cef3ac4c82370f41b8c1e5692f4067b6b96d2430bfcb9060e00160405180910390a350505050505092915050565b60008381526001602090815260408083206002909252909120612d899190848460646133d7565b6131e9816133a4565b600780546001600160a01b0319166001600160a01b0383169081179091556040517f278c70ced5f3e0e5eeb385b5ff9cb735748ba00a625147e66065ed48fc1562cd90600090a250565b606060006040518060c001604052806000815260200160006001600160a01b031681526020016000815260200160006001600160a01b031681526020016040518060600160405280600081526020016000815260200186815250815260200160006001600160a01b03168152506040516020016132b09190614392565b60408051601f198184030181529190529392505050565b60008181526001602090815260409182902080548351818402810184019094528084526060939283018282801561332757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613309575b50505050509050919050565b6000818061333f575082155b1561334b575083611b4f565b836133795761335d83620186a061424e565b61336a620186a087614515565b613374919061452c565b61339b565b620186a0613387848261424e565b6133919087614515565b61339b919061452c565b95945050505050565b6001600160a01b0381163b610afe57604051638c50d7cd60e01b81526001600160a01b0382166004820152602401610935565b6000826133ee576133e98686866135d6565b6118ed565b6118ed868686856136fe565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b1790529151600092839290871691613456919061454e565b6000604051808303816000865af19150503d8060008114613493576040519150601f19603f3d011682016040523d82523d6000602084013e613498565b606091505b509150915060008280156134c45750815115806134c45750818060200190518101906134c49190613f2c565b9050806124015760405163b45d44e760e01b815260040160405180910390fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691613548919061454e565b6000604051808303816000865af19150503d8060008114613585576040519150601f19603f3d011682016040523d82523d6000602084013e61358a565b606091505b509150915060008280156135b65750815115806135b65750818060200190518101906135b69190613f2c565b90508061227f57604051632d9d5b4160e01b815260040160405180910390fd5b6001600160a01b0381166000908152602083905260409020805460ff169081156136f65760018082015486549091600091613611919061424e565b905080821461369e57600087828154811061362e5761362e61437c565b9060005260206000200160009054906101000a90046001600160a01b03169050808884815481106136615761366161437c565b600091825260208083209190910180546001600160a01b0319166001600160a01b0394851617905592909116815290879052604090206001018290555b868054806136ae576136ae6146f1565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038716825287905260408120805460ff191681556001015550505b509392505050565b6001600160a01b03821660009081526020849052604090205460ff16158015611b4f57845482116137425760405163b1655e3360e01b815260040160405180910390fd5b6040805180820182526001808252875460208084019182526001600160a01b039790971660008181529888529388209251835460ff19169015151783555191810191909155865490810187559585529290932090930180546001600160a01b0319169091179055919050565b604051806080016040528060006001600160a01b0316815260200160006001600160a01b031681526020016137fd60405180606001604052806000815260200160008152602001606081525090565b8152600060209091015290565b6020808252825182820181905260009190848201906040850190845b8181101561384b5783516001600160a01b031683529284019291840191600101613826565b50909695505050505050565b8015158114610afe57600080fd5b600080600080600060a0868803121561387d57600080fd5b8535945060208601359350604086013592506060860135915060808601356138a481613857565b809150509295509295909350565b6000608082840312156138c457600080fd5b50919050565b600080604083850312156138dd57600080fd5b8235915060208301356001600160401b038111156138fa57600080fd5b613906858286016138b2565b9150509250929050565b6001600160a01b0381168114610afe57600080fd5b60006020828403121561393757600080fd5b8135612b7e81613910565b6000806040838503121561395557600080fd5b823561396081613910565b946020939093013593505050565b60006020828403121561398057600080fd5b5035919050565b634e487b7160e01b600052602160045260246000fd5b60208101600383106139bf57634e487b7160e01b600052602160045260246000fd5b91905290565b60008083601f8401126139d757600080fd5b5081356001600160401b038111156139ee57600080fd5b602083019150836020828501011115613a0657600080fd5b9250929050565b600080600060408486031215613a2257600080fd5b8335925060208401356001600160401b03811115613a3f57600080fd5b613a4b868287016139c5565b9497909650939450505050565b60008060a08385031215613a6b57600080fd5b613a7584846138b2565b915060808301356001600160401b03811115613a9057600080fd5b830160c08186031215613aa257600080fd5b809150509250929050565b600060208284031215613abf57600080fd5b81356001600160401b03811115613ad557600080fd5b82016101208185031215612b7e57600080fd5b600060208284031215613afa57600080fd5b81356001600160401b03811115613b1057600080fd5b611b4f848285016138b2565b60008060408385031215613b2f57600080fd5b8235613b3a81613910565b91506020830135613aa281613857565b60008060008060008060808789031215613b6357600080fd5b863595506020870135945060408701356001600160401b0380821115613b8857600080fd5b818901915089601f830112613b9c57600080fd5b813581811115613bab57600080fd5b8a60208260051b8501011115613bc057600080fd5b602083019650809550506060890135915080821115613bde57600080fd5b50613beb89828a016139c5565b979a9699509497509295939492505050565b60008060408385031215613c1057600080fd5b823591506020830135613aa281613857565b600060208284031215613c3457600080fd5b813560038110612b7e57600080fd5b60008060208385031215613c5657600080fd5b82356001600160401b0380821115613c6d57600080fd5b818501915085601f830112613c8157600080fd5b813581811115613c9057600080fd5b8660208260061b8501011115613ca557600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613cef57613cef613cb7565b60405290565b604051606081016001600160401b0381118282101715613cef57613cef613cb7565b60405160c081016001600160401b0381118282101715613cef57613cef613cb7565b60405161016081016001600160401b0381118282101715613cef57613cef613cb7565b604051601f8201601f191681016001600160401b0381118282101715613d8457613d84613cb7565b604052919050565b805161152281613857565b600060808284031215613da957600080fd5b613db1613ccd565b8251815260208301516020820152604083015160408201526060830151613dd781613857565b60608201529392505050565b600060608284031215613df557600080fd5b613dfd613cf5565b9050813581526020808301358183015260408301356001600160401b0380821115613e2757600080fd5b818501915085601f830112613e3b57600080fd5b813581811115613e4d57613e4d613cb7565b613e5f601f8201601f19168501613d5c565b91508082528684828501011115613e7557600080fd5b808484018584013760008482840101525080604085015250505092915050565b600060808236031215613ea757600080fd5b613eaf613ccd565b8235613eba81613910565b81526020830135613eca81613910565b602082015260408301356001600160401b03811115613ee857600080fd5b613ef436828601613de3565b6040830152506060830135613f0881613910565b606082015292915050565b600060208284031215613f2557600080fd5b5051919050565b600060208284031215613f3e57600080fd5b8151612b7e81613857565b600060208284031215613f5b57600080fd5b81356001600160401b0380821115613f7257600080fd5b9083019060c08286031215613f8657600080fd5b613f8e613d17565b823581526020830135613fa081613910565b6020820152604083810135908201526060830135613fbd81613910565b6060820152608083013582811115613fd457600080fd5b613fe087828601613de3565b60808301525060a08301359250613ff683613910565b60a0810192909252509392505050565b805161152281613910565b60006080828403121561402357600080fd5b61402b613ccd565b825161403681613910565b8152602083015161404681613910565b6020820152604083015161405981613910565b60408201526060928301519281019290925250919050565b60005b8381101561408c578181015183820152602001614074565b50506000910152565b600081518084526140ad816020860160208601614071565b601f01601f19169290920160200192915050565b805182526000602082015160018060a01b038082166020860152604084015160408601528060608501511660608601525050608082015160c06080850152805160c0850152602081015160e085015260408101519050606061010085015261412d610120850182614095565b905060a08301516136f660a08601826001600160a01b03169052565b600060018060a01b03808551168352806020860151166020840152806040860151166040840152506060840151606083015260a06080830152611b4f60a08301846140c1565b60008235605e198336030181126141a557600080fd5b9190910192915050565b6000602082840312156141c157600080fd5b8151612b7e81613910565b6000608082840312156141de57600080fd5b6141e6613ccd565b82356141f181613910565b8152602083013561420181613910565b6020820152604083013561421481613910565b60408201526060928301359281019290925250919050565b6000610a593683613de3565b634e487b7160e01b600052601160045260246000fd5b81810381811115610a5957610a59614238565b60006001820161427357614273614238565b5060010190565b6000610160828403121561428d57600080fd5b614295613d39565b61429e83614006565b81526142ac60208401614006565b60208201526142bd60408401614006565b60408201526142ce60608401614006565b60608201526080830151608082015260a083015160a082015260c083015160c08201526142fd60e08401614006565b60e0820152610100614310818501613d8c565b908201526101208381015190820152610140928301519281019290925250919050565b6000808335601e1984360301811261434a57600080fd5b8301803591506001600160401b0382111561436457600080fd5b6020019150600581901b3603821315613a0657600080fd5b634e487b7160e01b600052603260045260246000fd5b602081526000610a5660208301846140c1565b6000602082840312156143b757600080fd5b604051602081018181106001600160401b03821117156143d9576143d9613cb7565b806040525080915082516143ec81613910565b905292915050565b60006020828403121561440657600080fd5b610a5683836143a5565b8481526060602082015260006144296060830186614095565b8281036040840152838152838560208301376000602085830101526020601f19601f86011682010191505095945050505050565b6000808335601e1984360301811261447457600080fd5b8301803591506001600160401b0382111561448e57600080fd5b602001915036819003821315613a0657600080fd5b6000604082840312156144b557600080fd5b604051604081018181106001600160401b03821117156144d7576144d7613cb7565b6040528251815260208301516144ec81613857565b60208201529392505050565b60006020828403121561450a57600080fd5b8135612b7e81613857565b8082028115828204841417610a5957610a59614238565b60008261454957634e487b7160e01b600052601260045260246000fd5b500490565b600082516141a5818460208701614071565b600181815b8085111561459b57816000190482111561458157614581614238565b8085161561458e57918102915b93841c9390800290614565565b509250929050565b6000826145b257506001610a59565b816145bf57506000610a59565b81600181146145d557600281146145df576145fb565b6001915050610a59565b60ff8411156145f0576145f0614238565b50506001821b610a59565b5060208310610133831016604e8410600b841016171561461e575081810a610a59565b6146288383614560565b806000190482111561463c5761463c614238565b029392505050565b6000610a5683836145a3565b600060a0828403121561466257600080fd5b60405160a081018181106001600160401b038211171561468457614684613cb7565b604052825161469281613910565b815260208301516146a281613910565b60208201526040838101519082015260608301516146bf81613910565b606082015260808301516146d281613857565b60808201529392505050565b80820180821115610a5957610a59614238565b634e487b7160e01b600052603160045260246000fdfe6d439300980e333f0256d64be2c9f67e86f4493ce25f82498d6db7f4be3d9e6fa2646970667358221220bf8fe89df48fd06e15a1680f4a63c9c22e8ce51bf8f24d24d0b346382636907564736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000c90e949f95ffead18e35c1fac84327f2ea9fdb00000000000000000000000056b7b130b2dfca12820184515839bdad5c649fc900000000000000000000000000000000000000000000000000000000004c4b4000000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78
-----Decoded View---------------
Arg [0] : _registry (address): 0x00C90E949f95FfEad18E35C1Fac84327F2eA9FDb
Arg [1] : _variableBalanceRecords (address): 0x56B7b130b2dFca12820184515839bDaD5c649fC9
Arg [2] : _actionIdOffset (uint256): 5000000
Arg [3] : _owner (address): 0x72E28c7F34100AfefC399fcc0AE041B8fe5841AE
Arg [4] : _managers (address[]): 0x6741a38ADBd040e9e1a8A9C78bA52987e56a3e78
Arg [5] : _addOwnerToManagers (bool): True
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000000c90e949f95ffead18e35c1fac84327f2ea9fdb
Arg [1] : 00000000000000000000000056b7b130b2dfca12820184515839bdad5c649fc9
Arg [2] : 00000000000000000000000000000000000000000000000000000000004c4b40
Arg [3] : 00000000000000000000000072e28c7f34100afefc399fcc0ae041b8fe5841ae
Arg [4] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [7] : 0000000000000000000000006741a38adbd040e9e1a8a9c78ba52987e56a3e78
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.