Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- Agent
- Optimization enabled
- true
- Compiler version
- v0.4.24+commit.e67f0147
- Optimization runs
- 200
- EVM Version
- constantinople
- Verified at
- 2025-06-18T14:19:36.237554Z
@aragon/apps-agent/contracts/Agent.sol
/*
* SPDX-License-Identitifer: GPL-3.0-or-later
*/
pragma solidity 0.4.24;
import "./SignatureValidator.sol";
import "./standards/IERC165.sol";
import "./standards/ERC1271.sol";
import "./standards/IERC721Receiver.sol";
import "@aragon/apps-vault/contracts/Vault.sol";
import "@aragon/os/contracts/common/IForwarder.sol";
contract Agent is IERC165, IERC721Receiver, ERC1271Bytes, IForwarder, IsContract, Vault {
/* Hardcoded constants to save gas
bytes32 public constant EXECUTE_ROLE = keccak256("EXECUTE_ROLE");
bytes32 public constant SAFE_EXECUTE_ROLE = keccak256("SAFE_EXECUTE_ROLE");
bytes32 public constant ADD_PROTECTED_TOKEN_ROLE = keccak256("ADD_PROTECTED_TOKEN_ROLE");
bytes32 public constant REMOVE_PROTECTED_TOKEN_ROLE = keccak256("REMOVE_PROTECTED_TOKEN_ROLE");
bytes32 public constant ADD_PRESIGNED_HASH_ROLE = keccak256("ADD_PRESIGNED_HASH_ROLE");
bytes32 public constant DESIGNATE_SIGNER_ROLE = keccak256("DESIGNATE_SIGNER_ROLE");
bytes32 public constant RUN_SCRIPT_ROLE = keccak256("RUN_SCRIPT_ROLE");
*/
bytes32 public constant EXECUTE_ROLE = 0xcebf517aa4440d1d125e0355aae64401211d0848a23c02cc5d29a14822580ba4;
bytes32 public constant SAFE_EXECUTE_ROLE = 0x0a1ad7b87f5846153c6d5a1f761d71c7d0cfd122384f56066cd33239b7933694;
bytes32 public constant ADD_PROTECTED_TOKEN_ROLE = 0x6eb2a499556bfa2872f5aa15812b956cc4a71b4d64eb3553f7073c7e41415aaa;
bytes32 public constant REMOVE_PROTECTED_TOKEN_ROLE = 0x71eee93d500f6f065e38b27d242a756466a00a52a1dbcd6b4260f01a8640402a;
bytes32 public constant ADD_PRESIGNED_HASH_ROLE = 0x0b29780bb523a130b3b01f231ef49ed2fa2781645591a0b0a44ca98f15a5994c;
bytes32 public constant DESIGNATE_SIGNER_ROLE = 0x23ce341656c3f14df6692eebd4757791e33662b7dcf9970c8308303da5472b7c;
bytes32 public constant RUN_SCRIPT_ROLE = 0xb421f7ad7646747f3051c50c0b8e2377839296cd4973e27f63821d73e390338f;
uint256 public constant PROTECTED_TOKENS_CAP = 10;
bytes4 private constant ERC165_INTERFACE_ID = 0x01ffc9a7;
bytes4 private constant ERC721_RECEIVED_INTERFACE_ID = 0x150b7a02; // bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))
string private constant ERROR_TARGET_PROTECTED = "AGENT_TARGET_PROTECTED";
string private constant ERROR_PROTECTED_TOKENS_MODIFIED = "AGENT_PROTECTED_TOKENS_MODIFIED";
string private constant ERROR_PROTECTED_BALANCE_LOWERED = "AGENT_PROTECTED_BALANCE_LOWERED";
string private constant ERROR_TOKENS_CAP_REACHED = "AGENT_TOKENS_CAP_REACHED";
string private constant ERROR_TOKEN_NOT_ERC20 = "AGENT_TOKEN_NOT_ERC20";
string private constant ERROR_TOKEN_ALREADY_PROTECTED = "AGENT_TOKEN_ALREADY_PROTECTED";
string private constant ERROR_TOKEN_NOT_PROTECTED = "AGENT_TOKEN_NOT_PROTECTED";
string private constant ERROR_DESIGNATED_TO_SELF = "AGENT_DESIGNATED_TO_SELF";
string private constant ERROR_CAN_NOT_FORWARD = "AGENT_CAN_NOT_FORWARD";
mapping (bytes32 => bool) public isPresigned;
address public designatedSigner;
address[] public protectedTokens;
event SafeExecute(address indexed sender, address indexed target, bytes data);
event Execute(address indexed sender, address indexed target, uint256 ethValue, bytes data);
event AddProtectedToken(address indexed token);
event RemoveProtectedToken(address indexed token);
event PresignHash(address indexed sender, bytes32 indexed hash);
event SetDesignatedSigner(address indexed sender, address indexed oldSigner, address indexed newSigner);
event ReceiveERC721(address indexed token, address indexed operator, address indexed from, uint256 tokenId, bytes data);
/**
* @notice Execute '`@radspec(_target, _data)`' on `_target``_ethValue == 0 ? '' : ' (Sending ' + @tokenAmount(0x0000000000000000000000000000000000000000, _ethValue) + ')'`
* @param _target Address where the action is being executed
* @param _ethValue Amount of ETH from the contract that is sent with the action
* @param _data Calldata for the action
* @return Exits call frame forwarding the return data of the executed call (either error or success data)
*/
function execute(address _target, uint256 _ethValue, bytes _data)
external // This function MUST always be external as the function performs a low level return, exiting the Agent app execution context
authP(EXECUTE_ROLE, arr(_target, _ethValue, uint256(_getSig(_data)))) // bytes4 casted as uint256 sets the bytes as the LSBs
{
bool result = _target.call.value(_ethValue)(_data);
if (result) {
emit Execute(msg.sender, _target, _ethValue, _data);
}
assembly {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize)
// revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
// if the call returned error data, forward it
switch result case 0 { revert(ptr, returndatasize) }
default { return(ptr, returndatasize) }
}
}
/**
* @notice Execute '`@radspec(_target, _data)`' on `_target`, ensuring that protected tokens can't be spent
* @param _target Address where the action is being executed
* @param _data Calldata for the action
* @return Exits call frame forwarding the return data of the executed call (either error or success data)
*/
function safeExecute(address _target, bytes _data)
external // This function MUST always be external as the function performs a low level return, exiting the Agent app execution context
authP(SAFE_EXECUTE_ROLE, arr(_target, uint256(_getSig(_data)))) // bytes4 casted as uint256 sets the bytes as the LSBs
{
uint256 protectedTokensLength = protectedTokens.length;
address[] memory protectedTokens_ = new address[](protectedTokensLength);
uint256[] memory balances = new uint256[](protectedTokensLength);
for (uint256 i = 0; i < protectedTokensLength; i++) {
address token = protectedTokens[i];
require(_target != token, ERROR_TARGET_PROTECTED);
// we copy the protected tokens array to check whether the storage array has been modified during the underlying call
protectedTokens_[i] = token;
// we copy the balances to check whether they have been modified during the underlying call
balances[i] = balance(token);
}
bool result = _target.call(_data);
bytes32 ptr;
uint256 size;
assembly {
size := returndatasize
ptr := mload(0x40)
mstore(0x40, add(ptr, returndatasize))
returndatacopy(ptr, 0, returndatasize)
}
if (result) {
// if the underlying call has succeeded, we check that the protected tokens
// and their balances have not been modified and return the call's return data
require(protectedTokens.length == protectedTokensLength, ERROR_PROTECTED_TOKENS_MODIFIED);
for (uint256 j = 0; j < protectedTokensLength; j++) {
require(protectedTokens[j] == protectedTokens_[j], ERROR_PROTECTED_TOKENS_MODIFIED);
require(balance(protectedTokens[j]) >= balances[j], ERROR_PROTECTED_BALANCE_LOWERED);
}
emit SafeExecute(msg.sender, _target, _data);
assembly {
return(ptr, size)
}
} else {
// if the underlying call has failed, we revert and forward returned error data
assembly {
revert(ptr, size)
}
}
}
/**
* @notice Add `_token.symbol(): string` to the list of protected tokens
* @param _token Address of the token to be protected
*/
function addProtectedToken(address _token) external authP(ADD_PROTECTED_TOKEN_ROLE, arr(_token)) {
require(protectedTokens.length < PROTECTED_TOKENS_CAP, ERROR_TOKENS_CAP_REACHED);
require(_isERC20(_token), ERROR_TOKEN_NOT_ERC20);
require(!_tokenIsProtected(_token), ERROR_TOKEN_ALREADY_PROTECTED);
_addProtectedToken(_token);
}
/**
* @notice Remove `_token.symbol(): string` from the list of protected tokens
* @param _token Address of the token to be unprotected
*/
function removeProtectedToken(address _token) external authP(REMOVE_PROTECTED_TOKEN_ROLE, arr(_token)) {
require(_tokenIsProtected(_token), ERROR_TOKEN_NOT_PROTECTED);
_removeProtectedToken(_token);
}
/**
* @notice Pre-sign hash `_hash`
* @param _hash Hash that will be considered signed regardless of the signature checked with 'isValidSignature()'
*/
function presignHash(bytes32 _hash)
external
authP(ADD_PRESIGNED_HASH_ROLE, arr(_hash))
{
isPresigned[_hash] = true;
emit PresignHash(msg.sender, _hash);
}
/**
* @notice Set `_designatedSigner` as the designated signer of the app, which will be able to sign messages on behalf of the app
* @param _designatedSigner Address that will be able to sign messages on behalf of the app
*/
function setDesignatedSigner(address _designatedSigner)
external
authP(DESIGNATE_SIGNER_ROLE, arr(_designatedSigner))
{
// Prevent an infinite loop by setting the app itself as its designated signer.
// An undetectable loop can be created by setting a different contract as the
// designated signer which calls back into `isValidSignature`.
// Given that `isValidSignature` is always called with just 50k gas, the max
// damage of the loop is wasting 50k gas.
require(_designatedSigner != address(this), ERROR_DESIGNATED_TO_SELF);
address oldDesignatedSigner = designatedSigner;
designatedSigner = _designatedSigner;
emit SetDesignatedSigner(msg.sender, oldDesignatedSigner, _designatedSigner);
}
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns (bytes4) {
emit ReceiveERC721(msg.sender, _operator, _from, _tokenId, _data);
return ERC721_RECEIVED_INTERFACE_ID;
}
// Forwarding fns
/**
* @notice Tells whether the Agent app is a forwarder or not
* @dev IForwarder interface conformance
* @return Always true
*/
function isForwarder() external pure returns (bool) {
return true;
}
/**
* @notice Tells whether this contract supports a given ERC-165 interface
* @dev Implements conformance to ERC-165
* @param _interfaceId Interface bytes to check
* @return True if this contract supports the interface
*/
function supportsInterface(bytes4 _interfaceId) external pure returns (bool) {
return
_interfaceId == ERC1271_INTERFACE_ID ||
_interfaceId == ERC721_RECEIVED_INTERFACE_ID ||
_interfaceId == ERC165_INTERFACE_ID;
}
/**
* @notice Execute the script as the Agent app
* @dev IForwarder interface conformance. Forwards any token holder action.
* @param _evmScript Script being executed
*/
function forward(bytes _evmScript) public {
require(canForward(msg.sender, _evmScript), ERROR_CAN_NOT_FORWARD);
bytes memory input = ""; // no input
address[] memory blacklist = new address[](0); // no addr blacklist, can interact with anything
runScript(_evmScript, input, blacklist);
// We don't need to emit an event here as EVMScriptRunner will emit ScriptResult if successful
}
/**
* @notice Tells whether `_sender` can forward actions or not
* @dev IForwarder interface conformance
* @param _sender Address of the account intending to forward an action
* @return True if the given address can run scripts, false otherwise
*/
function canForward(address _sender, bytes _evmScript) public view returns (bool) {
// Note that `canPerform()` implicitly does an initialization check itself
return canPerform(_sender, RUN_SCRIPT_ROLE, arr(_getScriptACLParam(_evmScript)));
}
// ERC-1271 conformance
/**
* @notice Tells whether a signature is seen as valid by this contract through ERC-1271
* @param _hash Arbitrary length data signed on the behalf of address (this)
* @param _signature Signature byte array associated with _data
* @return The ERC-1271 magic value if the signature is valid
*/
function isValidSignature(bytes32 _hash, bytes _signature) public view returns (bytes4) {
// Short-circuit in case the hash was presigned. Optimization as performing calls
// and ecrecover is more expensive than an SLOAD.
if (isPresigned[_hash]) {
return returnIsValidSignatureMagicNumber(true);
}
bool isValid;
if (designatedSigner == address(0)) {
isValid = false;
} else {
isValid = SignatureValidator.isValidSignature(_hash, designatedSigner, _signature);
}
return returnIsValidSignatureMagicNumber(isValid);
}
// Getters
function getProtectedTokensLength() public view isInitialized returns (uint256) {
return protectedTokens.length;
}
// Internal fns
function _addProtectedToken(address _token) internal {
protectedTokens.push(_token);
emit AddProtectedToken(_token);
}
function _removeProtectedToken(address _token) internal {
protectedTokens[_protectedTokenIndex(_token)] = protectedTokens[protectedTokens.length - 1];
protectedTokens.length--;
emit RemoveProtectedToken(_token);
}
function _isERC20(address _token) internal view returns (bool) {
if (!isContract(_token)) {
return false;
}
// Throwaway sanity check to make sure the token's `balanceOf()` does not error (for now)
balance(_token);
return true;
}
function _protectedTokenIndex(address _token) internal view returns (uint256) {
for (uint i = 0; i < protectedTokens.length; i++) {
if (protectedTokens[i] == _token) {
return i;
}
}
revert(ERROR_TOKEN_NOT_PROTECTED);
}
function _tokenIsProtected(address _token) internal view returns (bool) {
for (uint256 i = 0; i < protectedTokens.length; i++) {
if (protectedTokens[i] == _token) {
return true;
}
}
return false;
}
function _getScriptACLParam(bytes _evmScript) internal pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(_evmScript)));
}
function _getSig(bytes _data) internal pure returns (bytes4 sig) {
if (_data.length < 4) {
return;
}
assembly { sig := mload(add(_data, 0x20)) }
}
}
@aragon/apps-agent/contracts/SignatureValidator.sol
pragma solidity 0.4.24;
// Inspired by https://github.com/horizon-games/multi-token-standard/blob/319740cf2a78b8816269ae49a09c537b3fd7303b/contracts/utils/SignatureValidator.sol
// This should probably be moved into aOS: https://github.com/aragon/aragonOS/pull/442
import "./standards/ERC1271.sol";
library SignatureValidator {
enum SignatureMode {
Invalid, // 0x00
EIP712, // 0x01
EthSign, // 0x02
ERC1271, // 0x03
NMode // 0x04, to check if mode is specified, leave at the end
}
// bytes4(keccak256("isValidSignature(bytes,bytes)")
bytes4 public constant ERC1271_RETURN_VALID_SIGNATURE = 0x20c13b0b;
uint256 internal constant ERC1271_ISVALIDSIG_MAX_GAS = 250000;
string private constant ERROR_INVALID_LENGTH_POP_BYTE = "SIGVAL_INVALID_LENGTH_POP_BYTE";
/// @dev Validates that a hash was signed by a specified signer.
/// @param hash Hash which was signed.
/// @param signer Address of the signer.
/// @param signature ECDSA signature along with the mode (0 = Invalid, 1 = EIP712, 2 = EthSign, 3 = ERC1271) {mode}{r}{s}{v}.
/// @return Returns whether signature is from a specified user.
function isValidSignature(bytes32 hash, address signer, bytes signature) internal view returns (bool) {
if (signature.length == 0) {
return false;
}
uint8 modeByte = uint8(signature[0]);
if (modeByte >= uint8(SignatureMode.NMode)) {
return false;
}
SignatureMode mode = SignatureMode(modeByte);
if (mode == SignatureMode.EIP712) {
return ecVerify(hash, signer, signature);
} else if (mode == SignatureMode.EthSign) {
return ecVerify(
keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)),
signer,
signature
);
} else if (mode == SignatureMode.ERC1271) {
// Pop the mode byte before sending it down the validation chain
return safeIsValidSignature(signer, hash, popFirstByte(signature));
} else {
return false;
}
}
function ecVerify(bytes32 hash, address signer, bytes memory signature) private pure returns (bool) {
(bool badSig, bytes32 r, bytes32 s, uint8 v) = unpackEcSig(signature);
if (badSig) {
return false;
}
return signer == ecrecover(hash, v, r, s);
}
function unpackEcSig(bytes memory signature) private pure returns (bool badSig, bytes32 r, bytes32 s, uint8 v) {
if (signature.length != 66) {
badSig = true;
return;
}
v = uint8(signature[65]);
assembly {
r := mload(add(signature, 33))
s := mload(add(signature, 65))
}
// Allow signature version to be 0 or 1
if (v < 27) {
v += 27;
}
if (v != 27 && v != 28) {
badSig = true;
}
}
function popFirstByte(bytes memory input) private pure returns (bytes memory output) {
uint256 inputLength = input.length;
require(inputLength > 0, ERROR_INVALID_LENGTH_POP_BYTE);
output = new bytes(inputLength - 1);
if (output.length == 0) {
return output;
}
uint256 inputPointer;
uint256 outputPointer;
assembly {
inputPointer := add(input, 0x21)
outputPointer := add(output, 0x20)
}
memcpy(outputPointer, inputPointer, output.length);
}
function safeIsValidSignature(address validator, bytes32 hash, bytes memory signature) private view returns (bool) {
bytes memory data = abi.encodeWithSelector(ERC1271(validator).isValidSignature.selector, hash, signature);
bytes4 erc1271Return = safeBytes4StaticCall(validator, data, ERC1271_ISVALIDSIG_MAX_GAS);
return erc1271Return == ERC1271_RETURN_VALID_SIGNATURE;
}
function safeBytes4StaticCall(address target, bytes data, uint256 maxGas) private view returns (bytes4 ret) {
uint256 gasLeft = gasleft();
uint256 callGas = gasLeft > maxGas ? maxGas : gasLeft;
bool ok;
assembly {
ok := staticcall(callGas, target, add(data, 0x20), mload(data), 0, 0)
}
if (!ok) {
return;
}
uint256 size;
assembly { size := returndatasize }
if (size != 32) {
return;
}
assembly {
let ptr := mload(0x40) // get next free memory ptr
returndatacopy(ptr, 0, size) // copy return from above `staticcall`
ret := mload(ptr) // read data at ptr and set it to be returned
}
return ret;
}
// From: https://github.com/Arachnid/solidity-stringutils/blob/01e955c1d6/src/strings.sol
function memcpy(uint256 dest, uint256 src, uint256 len) private pure {
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
}
@aragon/apps-agent/contracts/standards/ERC1271.sol
pragma solidity 0.4.24;
// ERC1271 on Feb 12th, 2019: https://github.com/ethereum/EIPs/blob/a97dc434930d0ccc4461c97d8c7a920dc585adf2/EIPS/eip-1271.md
// Using `isValidSignature(bytes32,bytes)` even though the standard still hasn't been modified
// Rationale: https://github.com/ethereum/EIPs/issues/1271#issuecomment-462719728
contract ERC1271 {
bytes4 constant public ERC1271_INTERFACE_ID = 0xfb855dc9; // this.isValidSignature.selector
bytes4 constant public ERC1271_RETURN_VALID_SIGNATURE = 0x20c13b0b; // TODO: Likely needs to be updated
bytes4 constant public ERC1271_RETURN_INVALID_SIGNATURE = 0x00000000;
/**
* @dev Function must be implemented by deriving contract
* @param _hash Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
* @return A bytes4 magic value 0x20c13b0b if the signature check passes, 0x00000000 if not
*
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4);
function returnIsValidSignatureMagicNumber(bool isValid) internal pure returns (bytes4) {
return isValid ? ERC1271_RETURN_VALID_SIGNATURE : ERC1271_RETURN_INVALID_SIGNATURE;
}
}
contract ERC1271Bytes is ERC1271 {
/**
* @dev Default behavior of `isValidSignature(bytes,bytes)`, can be overloaded for custom validation
* @param _data Arbitrary length data signed on the behalf of address(this)
* @param _signature Signature byte array associated with _data
* @return A bytes4 magic value 0x20c13b0b if the signature check passes, 0x00000000 if not
*
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes _data, bytes _signature) public view returns (bytes4) {
return isValidSignature(keccak256(_data), _signature);
}
}
@aragon/apps-agent/contracts/standards/IERC165.sol
pragma solidity 0.4.24;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external pure returns (bool);
}
@aragon/apps-agent/contracts/standards/IERC721Receiver.sol
pragma solidity 0.4.24;
interface IERC721Receiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a {IERC721-safeTransferFrom}. This function MUST return the function selector,
* otherwise the caller will revert the transaction. The selector to be
* returned can be obtained as `this.onERC721Received.selector`. This
* function MAY throw to revert and reject the transfer.
* Note: the ERC721 contract address is always the message sender.
* @param operator The address which called `safeTransferFrom` function
* @param from The address which previously owned the token
* @param tokenId The NFT identifier which is being transferred
* @param data Additional data with no specified format
* @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
*/
function onERC721Received(address operator, address from, uint256 tokenId, bytes data) external returns (bytes4);
}
@aragon/os/contracts/common/DepositableStorage.sol
pragma solidity 0.4.24;
import "./UnstructuredStorage.sol";
contract DepositableStorage {
using UnstructuredStorage for bytes32;
// keccak256("aragonOS.depositableStorage.depositable")
bytes32 internal constant DEPOSITABLE_POSITION = 0x665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea;
function isDepositable() public view returns (bool) {
return DEPOSITABLE_POSITION.getStorageBool();
}
function setDepositable(bool _depositable) internal {
DEPOSITABLE_POSITION.setStorageBool(_depositable);
}
}
@aragon/os/contracts/common/EtherTokenConstant.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
// aragonOS and aragon-apps rely on address(0) to denote native ETH, in
// contracts where both tokens and ETH are accepted
contract EtherTokenConstant {
address internal constant ETH = address(0);
}
@aragon/os/contracts/common/IForwarder.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IForwarder {
function isForwarder() external pure returns (bool);
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function canForward(address sender, bytes evmCallScript) public view returns (bool);
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function forward(bytes evmCallScript) public;
}
@aragon/os/contracts/common/IVaultRecoverable.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IVaultRecoverable {
event RecoverToVault(address indexed vault, address indexed token, uint256 amount);
function transferToVault(address token) external;
function allowRecoverability(address token) external view returns (bool);
function getRecoveryVault() external view returns (address);
}
@aragon/apps-vault/contracts/Vault.sol
pragma solidity 0.4.24;
import "@aragon/os/contracts/apps/AragonApp.sol";
import "@aragon/os/contracts/common/DepositableStorage.sol";
import "@aragon/os/contracts/common/EtherTokenConstant.sol";
import "@aragon/os/contracts/common/SafeERC20.sol";
import "@aragon/os/contracts/lib/token/ERC20.sol";
contract Vault is EtherTokenConstant, AragonApp, DepositableStorage {
using SafeERC20 for ERC20;
bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");
string private constant ERROR_DATA_NON_ZERO = "VAULT_DATA_NON_ZERO";
string private constant ERROR_NOT_DEPOSITABLE = "VAULT_NOT_DEPOSITABLE";
string private constant ERROR_DEPOSIT_VALUE_ZERO = "VAULT_DEPOSIT_VALUE_ZERO";
string private constant ERROR_TRANSFER_VALUE_ZERO = "VAULT_TRANSFER_VALUE_ZERO";
string private constant ERROR_SEND_REVERTED = "VAULT_SEND_REVERTED";
string private constant ERROR_VALUE_MISMATCH = "VAULT_VALUE_MISMATCH";
string private constant ERROR_TOKEN_TRANSFER_FROM_REVERTED = "VAULT_TOKEN_TRANSFER_FROM_REVERT";
string private constant ERROR_TOKEN_TRANSFER_REVERTED = "VAULT_TOKEN_TRANSFER_REVERTED";
event VaultTransfer(address indexed token, address indexed to, uint256 amount);
event VaultDeposit(address indexed token, address indexed sender, uint256 amount);
/**
* @dev On a normal send() or transfer() this fallback is never executed as it will be
* intercepted by the Proxy (see aragonOS#281)
*/
function () external payable isInitialized {
require(msg.data.length == 0, ERROR_DATA_NON_ZERO);
_deposit(ETH, msg.value);
}
/**
* @notice Initialize Vault app
* @dev As an AragonApp it needs to be initialized in order for roles (`auth` and `authP`) to work
*/
function initialize() external onlyInit {
initialized();
setDepositable(true);
}
/**
* @notice Deposit `_value` `_token` to the vault
* @param _token Address of the token being transferred
* @param _value Amount of tokens being transferred
*/
function deposit(address _token, uint256 _value) external payable isInitialized {
_deposit(_token, _value);
}
/**
* @notice Transfer `_value` `_token` from the Vault to `_to`
* @param _token Address of the token being transferred
* @param _to Address of the recipient of tokens
* @param _value Amount of tokens being transferred
*/
/* solium-disable-next-line function-order */
function transfer(address _token, address _to, uint256 _value)
external
authP(TRANSFER_ROLE, arr(_token, _to, _value))
{
require(_value > 0, ERROR_TRANSFER_VALUE_ZERO);
if (_token == ETH) {
require(_to.send(_value), ERROR_SEND_REVERTED);
} else {
require(ERC20(_token).safeTransfer(_to, _value), ERROR_TOKEN_TRANSFER_REVERTED);
}
emit VaultTransfer(_token, _to, _value);
}
function balance(address _token) public view returns (uint256) {
if (_token == ETH) {
return address(this).balance;
} else {
return ERC20(_token).staticBalanceOf(address(this));
}
}
/**
* @dev Disable recovery escape hatch, as it could be used
* maliciously to transfer funds away from the vault
*/
function allowRecoverability(address) public view returns (bool) {
return false;
}
function _deposit(address _token, uint256 _value) internal {
require(isDepositable(), ERROR_NOT_DEPOSITABLE);
require(_value > 0, ERROR_DEPOSIT_VALUE_ZERO);
if (_token == ETH) {
// Deposit is implicit in this case
require(msg.value == _value, ERROR_VALUE_MISMATCH);
} else {
require(
ERC20(_token).safeTransferFrom(msg.sender, address(this), _value),
ERROR_TOKEN_TRANSFER_FROM_REVERTED
);
}
emit VaultDeposit(_token, msg.sender, _value);
}
}
@aragon/os/contracts/acl/ACLSyntaxSugar.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract ACLSyntaxSugar {
function arr() internal pure returns (uint256[]) {
return new uint256[](0);
}
function arr(bytes32 _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(bytes32 _a, bytes32 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a) internal pure returns (uint256[] r) {
return arr(uint256(_a));
}
function arr(address _a, address _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c);
}
function arr(address _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
return arr(uint256(_a), _b, _c, _d);
}
function arr(address _a, uint256 _b) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b));
}
function arr(address _a, address _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), _c, _d, _e);
}
function arr(address _a, address _b, address _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(address _a, address _b, uint256 _c) internal pure returns (uint256[] r) {
return arr(uint256(_a), uint256(_b), uint256(_c));
}
function arr(uint256 _a) internal pure returns (uint256[] r) {
r = new uint256[](1);
r[0] = _a;
}
function arr(uint256 _a, uint256 _b) internal pure returns (uint256[] r) {
r = new uint256[](2);
r[0] = _a;
r[1] = _b;
}
function arr(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256[] r) {
r = new uint256[](3);
r[0] = _a;
r[1] = _b;
r[2] = _c;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256[] r) {
r = new uint256[](4);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
}
function arr(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256[] r) {
r = new uint256[](5);
r[0] = _a;
r[1] = _b;
r[2] = _c;
r[3] = _d;
r[4] = _e;
}
}
contract ACLHelpers {
function decodeParamOp(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 30));
}
function decodeParamId(uint256 _x) internal pure returns (uint8 b) {
return uint8(_x >> (8 * 31));
}
function decodeParamsList(uint256 _x) internal pure returns (uint32 a, uint32 b, uint32 c) {
a = uint32(_x);
b = uint32(_x >> (8 * 4));
c = uint32(_x >> (8 * 8));
}
}
@aragon/os/contracts/acl/IACL.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IACL {
function initialize(address permissionsCreator) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
}
@aragon/os/contracts/apps/AppStorage.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
import "../kernel/IKernel.sol";
contract AppStorage {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_POSITION = keccak256("aragonOS.appStorage.kernel");
bytes32 internal constant APP_ID_POSITION = keccak256("aragonOS.appStorage.appId");
*/
bytes32 internal constant KERNEL_POSITION = 0x4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b;
bytes32 internal constant APP_ID_POSITION = 0xd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b;
function kernel() public view returns (IKernel) {
return IKernel(KERNEL_POSITION.getStorageAddress());
}
function appId() public view returns (bytes32) {
return APP_ID_POSITION.getStorageBytes32();
}
function setKernel(IKernel _kernel) internal {
KERNEL_POSITION.setStorageAddress(address(_kernel));
}
function setAppId(bytes32 _appId) internal {
APP_ID_POSITION.setStorageBytes32(_appId);
}
}
@aragon/os/contracts/apps/AragonApp.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./AppStorage.sol";
import "../acl/ACLSyntaxSugar.sol";
import "../common/Autopetrified.sol";
import "../common/ConversionHelpers.sol";
import "../common/ReentrancyGuard.sol";
import "../common/VaultRecoverable.sol";
import "../evmscript/EVMScriptRunner.sol";
// Contracts inheriting from AragonApp are, by default, immediately petrified upon deployment so
// that they can never be initialized.
// Unless overriden, this behaviour enforces those contracts to be usable only behind an AppProxy.
// ReentrancyGuard, EVMScriptRunner, and ACLSyntaxSugar are not directly used by this contract, but
// are included so that they are automatically usable by subclassing contracts
contract AragonApp is AppStorage, Autopetrified, VaultRecoverable, ReentrancyGuard, EVMScriptRunner, ACLSyntaxSugar {
string private constant ERROR_AUTH_FAILED = "APP_AUTH_FAILED";
modifier auth(bytes32 _role) {
require(canPerform(msg.sender, _role, new uint256[](0)), ERROR_AUTH_FAILED);
_;
}
modifier authP(bytes32 _role, uint256[] _params) {
require(canPerform(msg.sender, _role, _params), ERROR_AUTH_FAILED);
_;
}
/**
* @dev Check whether an action can be performed by a sender for a particular role on this app
* @param _sender Sender of the call
* @param _role Role on this app
* @param _params Permission params for the role
* @return Boolean indicating whether the sender has the permissions to perform the action.
* Always returns false if the app hasn't been initialized yet.
*/
function canPerform(address _sender, bytes32 _role, uint256[] _params) public view returns (bool) {
if (!hasInitialized()) {
return false;
}
IKernel linkedKernel = kernel();
if (address(linkedKernel) == address(0)) {
return false;
}
return linkedKernel.hasPermission(
_sender,
address(this),
_role,
ConversionHelpers.dangerouslyCastUintArrayToBytes(_params)
);
}
/**
* @dev Get the recovery vault for the app
* @return Recovery vault address for the app
*/
function getRecoveryVault() public view returns (address) {
// Funds recovery via a vault is only available when used with a kernel
return kernel().getRecoveryVault(); // if kernel is not set, it will revert
}
}
@aragon/os/contracts/common/Autopetrified.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Petrifiable.sol";
contract Autopetrified is Petrifiable {
constructor() public {
// Immediately petrify base (non-proxy) instances of inherited contracts on deploy.
// This renders them uninitializable (and unusable without a proxy).
petrify();
}
}
@aragon/os/contracts/common/ConversionHelpers.sol
pragma solidity ^0.4.24;
library ConversionHelpers {
string private constant ERROR_IMPROPER_LENGTH = "CONVERSION_IMPROPER_LENGTH";
function dangerouslyCastUintArrayToBytes(uint256[] memory _input) internal pure returns (bytes memory output) {
// Force cast the uint256[] into a bytes array, by overwriting its length
// Note that the bytes array doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 byteLength = _input.length * 32;
assembly {
output := _input
mstore(output, byteLength)
}
}
function dangerouslyCastBytesToUintArray(bytes memory _input) internal pure returns (uint256[] memory output) {
// Force cast the bytes array into a uint256[], by overwriting its length
// Note that the uint256[] doesn't need to be initialized as we immediately overwrite it
// with the input and a new length. The input becomes invalid from this point forward.
uint256 intsLength = _input.length / 32;
require(_input.length == intsLength * 32, ERROR_IMPROPER_LENGTH);
assembly {
output := _input
mstore(output, intsLength)
}
}
}
@aragon/os/contracts/common/Initializable.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./TimeHelpers.sol";
import "./UnstructuredStorage.sol";
contract Initializable is TimeHelpers {
using UnstructuredStorage for bytes32;
// keccak256("aragonOS.initializable.initializationBlock")
bytes32 internal constant INITIALIZATION_BLOCK_POSITION = 0xebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e;
string private constant ERROR_ALREADY_INITIALIZED = "INIT_ALREADY_INITIALIZED";
string private constant ERROR_NOT_INITIALIZED = "INIT_NOT_INITIALIZED";
modifier onlyInit {
require(getInitializationBlock() == 0, ERROR_ALREADY_INITIALIZED);
_;
}
modifier isInitialized {
require(hasInitialized(), ERROR_NOT_INITIALIZED);
_;
}
/**
* @return Block number in which the contract was initialized
*/
function getInitializationBlock() public view returns (uint256) {
return INITIALIZATION_BLOCK_POSITION.getStorageUint256();
}
/**
* @return Whether the contract has been initialized by the time of the current block
*/
function hasInitialized() public view returns (bool) {
uint256 initializationBlock = getInitializationBlock();
return initializationBlock != 0 && getBlockNumber() >= initializationBlock;
}
/**
* @dev Function to be called by top level contract after initialization has finished.
*/
function initialized() internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(getBlockNumber());
}
/**
* @dev Function to be called by top level contract after initialization to enable the contract
* at a future block number rather than immediately.
*/
function initializedAt(uint256 _blockNumber) internal onlyInit {
INITIALIZATION_BLOCK_POSITION.setStorageUint256(_blockNumber);
}
}
@aragon/os/contracts/common/IsContract.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract IsContract {
/*
* NOTE: this should NEVER be used for authentication
* (see pitfalls: https://github.com/fergarrui/ethereum-security/tree/master/contracts/extcodesize).
*
* This is only intended to be used as a sanity check that an address is actually a contract,
* RATHER THAN an address not being a contract.
*/
function isContract(address _target) internal view returns (bool) {
if (_target == address(0)) {
return false;
}
uint256 size;
assembly { size := extcodesize(_target) }
return size > 0;
}
}
@aragon/os/contracts/common/Petrifiable.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Initializable.sol";
contract Petrifiable is Initializable {
// Use block UINT256_MAX (which should be never) as the initializable date
uint256 internal constant PETRIFIED_BLOCK = uint256(-1);
function isPetrified() public view returns (bool) {
return getInitializationBlock() == PETRIFIED_BLOCK;
}
/**
* @dev Function to be called by top level contract to prevent being initialized.
* Useful for freezing base contracts when they're used behind proxies.
*/
function petrify() internal onlyInit {
initializedAt(PETRIFIED_BLOCK);
}
}
@aragon/os/contracts/common/ReentrancyGuard.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../common/UnstructuredStorage.sol";
contract ReentrancyGuard {
using UnstructuredStorage for bytes32;
/* Hardcoded constants to save gas
bytes32 internal constant REENTRANCY_MUTEX_POSITION = keccak256("aragonOS.reentrancyGuard.mutex");
*/
bytes32 private constant REENTRANCY_MUTEX_POSITION = 0xe855346402235fdd185c890e68d2c4ecad599b88587635ee285bce2fda58dacb;
string private constant ERROR_REENTRANT = "REENTRANCY_REENTRANT_CALL";
modifier nonReentrant() {
// Ensure mutex is unlocked
require(!REENTRANCY_MUTEX_POSITION.getStorageBool(), ERROR_REENTRANT);
// Lock mutex before function call
REENTRANCY_MUTEX_POSITION.setStorageBool(true);
// Perform function call
_;
// Unlock mutex after function call
REENTRANCY_MUTEX_POSITION.setStorageBool(false);
}
}
@aragon/os/contracts/common/SafeERC20.sol
// Inspired by AdEx (https://github.com/AdExNetwork/adex-protocol-eth/blob/b9df617829661a7518ee10f4cb6c4108659dd6d5/contracts/libs/SafeERC20.sol)
// and 0x (https://github.com/0xProject/0x-monorepo/blob/737d1dc54d72872e24abce5a1dbe1b66d35fa21a/contracts/protocol/contracts/protocol/AssetProxy/ERC20Proxy.sol#L143)
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
library SafeERC20 {
// Before 0.5, solidity has a mismatch between `address.transfer()` and `token.transfer()`:
// https://github.com/ethereum/solidity/issues/3544
bytes4 private constant TRANSFER_SELECTOR = 0xa9059cbb;
string private constant ERROR_TOKEN_BALANCE_REVERTED = "SAFE_ERC_20_BALANCE_REVERTED";
string private constant ERROR_TOKEN_ALLOWANCE_REVERTED = "SAFE_ERC_20_ALLOWANCE_REVERTED";
function invokeAndCheckSuccess(address _addr, bytes memory _calldata)
private
returns (bool)
{
bool ret;
assembly {
let ptr := mload(0x40) // free memory pointer
let success := call(
gas, // forward all gas
_addr, // address
0, // no value
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
// Check number of bytes returned from last function call
switch returndatasize
// No bytes returned: assume success
case 0 {
ret := 1
}
// 32 bytes returned: check if non-zero
case 0x20 {
// Only return success if returned data was true
// Already have output in ptr
ret := eq(mload(ptr), 1)
}
// Not sure what was returned: don't mark as success
default { }
}
}
return ret;
}
function staticInvoke(address _addr, bytes memory _calldata)
private
view
returns (bool, uint256)
{
bool success;
uint256 ret;
assembly {
let ptr := mload(0x40) // free memory pointer
success := staticcall(
gas, // forward all gas
_addr, // address
add(_calldata, 0x20), // calldata start
mload(_calldata), // calldata length
ptr, // write output over free memory
0x20 // uint256 return
)
if gt(success, 0) {
ret := mload(ptr)
}
}
return (success, ret);
}
/**
* @dev Same as a standards-compliant ERC20.transfer() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransfer(ERC20 _token, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferCallData = abi.encodeWithSelector(
TRANSFER_SELECTOR,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferCallData);
}
/**
* @dev Same as a standards-compliant ERC20.transferFrom() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeTransferFrom(ERC20 _token, address _from, address _to, uint256 _amount) internal returns (bool) {
bytes memory transferFromCallData = abi.encodeWithSelector(
_token.transferFrom.selector,
_from,
_to,
_amount
);
return invokeAndCheckSuccess(_token, transferFromCallData);
}
/**
* @dev Same as a standards-compliant ERC20.approve() that never reverts (returns false).
* Note that this makes an external call to the token.
*/
function safeApprove(ERC20 _token, address _spender, uint256 _amount) internal returns (bool) {
bytes memory approveCallData = abi.encodeWithSelector(
_token.approve.selector,
_spender,
_amount
);
return invokeAndCheckSuccess(_token, approveCallData);
}
/**
* @dev Static call into ERC20.balanceOf().
* Reverts if the call fails for some reason (should never fail).
*/
function staticBalanceOf(ERC20 _token, address _owner) internal view returns (uint256) {
bytes memory balanceOfCallData = abi.encodeWithSelector(
_token.balanceOf.selector,
_owner
);
(bool success, uint256 tokenBalance) = staticInvoke(_token, balanceOfCallData);
require(success, ERROR_TOKEN_BALANCE_REVERTED);
return tokenBalance;
}
/**
* @dev Static call into ERC20.allowance().
* Reverts if the call fails for some reason (should never fail).
*/
function staticAllowance(ERC20 _token, address _owner, address _spender) internal view returns (uint256) {
bytes memory allowanceCallData = abi.encodeWithSelector(
_token.allowance.selector,
_owner,
_spender
);
(bool success, uint256 allowance) = staticInvoke(_token, allowanceCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return allowance;
}
/**
* @dev Static call into ERC20.totalSupply().
* Reverts if the call fails for some reason (should never fail).
*/
function staticTotalSupply(ERC20 _token) internal view returns (uint256) {
bytes memory totalSupplyCallData = abi.encodeWithSelector(_token.totalSupply.selector);
(bool success, uint256 totalSupply) = staticInvoke(_token, totalSupplyCallData);
require(success, ERROR_TOKEN_ALLOWANCE_REVERTED);
return totalSupply;
}
}
@aragon/os/contracts/common/TimeHelpers.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./Uint256Helpers.sol";
contract TimeHelpers {
using Uint256Helpers for uint256;
/**
* @dev Returns the current block number.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber() internal view returns (uint256) {
return block.number;
}
/**
* @dev Returns the current block number, converted to uint64.
* Using a function rather than `block.number` allows us to easily mock the block number in
* tests.
*/
function getBlockNumber64() internal view returns (uint64) {
return getBlockNumber().toUint64();
}
/**
* @dev Returns the current timestamp.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp() internal view returns (uint256) {
return block.timestamp; // solium-disable-line security/no-block-members
}
/**
* @dev Returns the current timestamp, converted to uint64.
* Using a function rather than `block.timestamp` allows us to easily mock it in
* tests.
*/
function getTimestamp64() internal view returns (uint64) {
return getTimestamp().toUint64();
}
}
@aragon/os/contracts/common/Uint256Helpers.sol
pragma solidity ^0.4.24;
library Uint256Helpers {
uint256 private constant MAX_UINT64 = uint64(-1);
string private constant ERROR_NUMBER_TOO_BIG = "UINT64_NUMBER_TOO_BIG";
function toUint64(uint256 a) internal pure returns (uint64) {
require(a <= MAX_UINT64, ERROR_NUMBER_TOO_BIG);
return uint64(a);
}
}
@aragon/os/contracts/common/UnstructuredStorage.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
library UnstructuredStorage {
function getStorageBool(bytes32 position) internal view returns (bool data) {
assembly { data := sload(position) }
}
function getStorageAddress(bytes32 position) internal view returns (address data) {
assembly { data := sload(position) }
}
function getStorageBytes32(bytes32 position) internal view returns (bytes32 data) {
assembly { data := sload(position) }
}
function getStorageUint256(bytes32 position) internal view returns (uint256 data) {
assembly { data := sload(position) }
}
function setStorageBool(bytes32 position, bool data) internal {
assembly { sstore(position, data) }
}
function setStorageAddress(bytes32 position, address data) internal {
assembly { sstore(position, data) }
}
function setStorageBytes32(bytes32 position, bytes32 data) internal {
assembly { sstore(position, data) }
}
function setStorageUint256(bytes32 position, uint256 data) internal {
assembly { sstore(position, data) }
}
}
@aragon/os/contracts/common/VaultRecoverable.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../lib/token/ERC20.sol";
import "./EtherTokenConstant.sol";
import "./IsContract.sol";
import "./IVaultRecoverable.sol";
import "./SafeERC20.sol";
contract VaultRecoverable is IVaultRecoverable, EtherTokenConstant, IsContract {
using SafeERC20 for ERC20;
string private constant ERROR_DISALLOWED = "RECOVER_DISALLOWED";
string private constant ERROR_VAULT_NOT_CONTRACT = "RECOVER_VAULT_NOT_CONTRACT";
string private constant ERROR_TOKEN_TRANSFER_FAILED = "RECOVER_TOKEN_TRANSFER_FAILED";
/**
* @notice Send funds to recovery Vault. This contract should never receive funds,
* but in case it does, this function allows one to recover them.
* @param _token Token balance to be sent to recovery vault.
*/
function transferToVault(address _token) external {
require(allowRecoverability(_token), ERROR_DISALLOWED);
address vault = getRecoveryVault();
require(isContract(vault), ERROR_VAULT_NOT_CONTRACT);
uint256 balance;
if (_token == ETH) {
balance = address(this).balance;
vault.transfer(balance);
} else {
ERC20 token = ERC20(_token);
balance = token.staticBalanceOf(this);
require(token.safeTransfer(vault, balance), ERROR_TOKEN_TRANSFER_FAILED);
}
emit RecoverToVault(vault, _token, balance);
}
/**
* @dev By default deriving from AragonApp makes it recoverable
* @param token Token address that would be recovered
* @return bool whether the app allows the recovery
*/
function allowRecoverability(address token) public view returns (bool) {
return true;
}
// Cast non-implemented interface to be public so we can use it internally
function getRecoveryVault() public view returns (address);
}
@aragon/os/contracts/evmscript/EVMScriptRunner.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
import "./IEVMScriptRegistry.sol";
import "../apps/AppStorage.sol";
import "../kernel/KernelConstants.sol";
import "../common/Initializable.sol";
contract EVMScriptRunner is AppStorage, Initializable, EVMScriptRegistryConstants, KernelNamespaceConstants {
string private constant ERROR_EXECUTOR_UNAVAILABLE = "EVMRUN_EXECUTOR_UNAVAILABLE";
string private constant ERROR_PROTECTED_STATE_MODIFIED = "EVMRUN_PROTECTED_STATE_MODIFIED";
/* This is manually crafted in assembly
string private constant ERROR_EXECUTOR_INVALID_RETURN = "EVMRUN_EXECUTOR_INVALID_RETURN";
*/
event ScriptResult(address indexed executor, bytes script, bytes input, bytes returnData);
function getEVMScriptExecutor(bytes _script) public view returns (IEVMScriptExecutor) {
return IEVMScriptExecutor(getEVMScriptRegistry().getScriptExecutor(_script));
}
function getEVMScriptRegistry() public view returns (IEVMScriptRegistry) {
address registryAddr = kernel().getApp(KERNEL_APP_ADDR_NAMESPACE, EVMSCRIPT_REGISTRY_APP_ID);
return IEVMScriptRegistry(registryAddr);
}
function runScript(bytes _script, bytes _input, address[] _blacklist)
internal
isInitialized
protectState
returns (bytes)
{
IEVMScriptExecutor executor = getEVMScriptExecutor(_script);
require(address(executor) != address(0), ERROR_EXECUTOR_UNAVAILABLE);
bytes4 sig = executor.execScript.selector;
bytes memory data = abi.encodeWithSelector(sig, _script, _input, _blacklist);
bytes memory output;
assembly {
let success := delegatecall(
gas, // forward all gas
executor, // address
add(data, 0x20), // calldata start
mload(data), // calldata length
0, // don't write output (we'll handle this ourselves)
0 // don't write output
)
output := mload(0x40) // free mem ptr get
switch success
case 0 {
// If the call errored, forward its full error data
returndatacopy(output, 0, returndatasize)
revert(output, returndatasize)
}
default {
switch gt(returndatasize, 0x3f)
case 0 {
// Need at least 0x40 bytes returned for properly ABI-encoded bytes values,
// revert with "EVMRUN_EXECUTOR_INVALID_RETURN"
// See remix: doing a `revert("EVMRUN_EXECUTOR_INVALID_RETURN")` always results in
// this memory layout
mstore(output, 0x08c379a000000000000000000000000000000000000000000000000000000000) // error identifier
mstore(add(output, 0x04), 0x0000000000000000000000000000000000000000000000000000000000000020) // starting offset
mstore(add(output, 0x24), 0x000000000000000000000000000000000000000000000000000000000000001e) // reason length
mstore(add(output, 0x44), 0x45564d52554e5f4558454355544f525f494e56414c49445f52455455524e0000) // reason
revert(output, 100) // 100 = 4 + 3 * 32 (error identifier + 3 words for the ABI encoded error)
}
default {
// Copy result
//
// Needs to perform an ABI decode for the expected `bytes` return type of
// `executor.execScript()` as solidity will automatically ABI encode the returned bytes as:
// [ position of the first dynamic length return value = 0x20 (32 bytes) ]
// [ output length (32 bytes) ]
// [ output content (N bytes) ]
//
// Perform the ABI decode by ignoring the first 32 bytes of the return data
let copysize := sub(returndatasize, 0x20)
returndatacopy(output, 0x20, copysize)
mstore(0x40, add(output, copysize)) // free mem ptr set
}
}
}
emit ScriptResult(address(executor), _script, _input, output);
return output;
}
modifier protectState {
address preKernel = address(kernel());
bytes32 preAppId = appId();
_; // exec
require(address(kernel()) == preKernel, ERROR_PROTECTED_STATE_MODIFIED);
require(appId() == preAppId, ERROR_PROTECTED_STATE_MODIFIED);
}
}
@aragon/os/contracts/evmscript/IEVMScriptExecutor.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
interface IEVMScriptExecutor {
function execScript(bytes script, bytes input, address[] blacklist) external returns (bytes);
function executorType() external pure returns (bytes32);
}
@aragon/os/contracts/evmscript/IEVMScriptRegistry.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "./IEVMScriptExecutor.sol";
contract EVMScriptRegistryConstants {
/* Hardcoded constants to save gas
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = apmNamehash("evmreg");
*/
bytes32 internal constant EVMSCRIPT_REGISTRY_APP_ID = 0xddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd61;
}
interface IEVMScriptRegistry {
function addScriptExecutor(IEVMScriptExecutor executor) external returns (uint id);
function disableScriptExecutor(uint256 executorId) external;
// TODO: this should be external
// See https://github.com/ethereum/solidity/issues/4832
function getScriptExecutor(bytes script) public view returns (IEVMScriptExecutor);
}
@aragon/os/contracts/kernel/IKernel.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
import "../acl/IACL.sol";
import "../common/IVaultRecoverable.sol";
interface IKernelEvents {
event SetApp(bytes32 indexed namespace, bytes32 indexed appId, address app);
}
// This should be an interface, but interfaces can't inherit yet :(
contract IKernel is IKernelEvents, IVaultRecoverable {
function acl() public view returns (IACL);
function hasPermission(address who, address where, bytes32 what, bytes how) public view returns (bool);
function setApp(bytes32 namespace, bytes32 appId, address app) public;
function getApp(bytes32 namespace, bytes32 appId) public view returns (address);
}
@aragon/os/contracts/kernel/KernelConstants.sol
/*
* SPDX-License-Identifier: MIT
*/
pragma solidity ^0.4.24;
contract KernelAppIds {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_APP_ID = apmNamehash("kernel");
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = apmNamehash("acl");
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = apmNamehash("vault");
*/
bytes32 internal constant KERNEL_CORE_APP_ID = 0x3b4bf6bf3ad5000ecf0f989d5befde585c6860fea3e574a4fab4c49d1c177d9c;
bytes32 internal constant KERNEL_DEFAULT_ACL_APP_ID = 0xe3262375f45a6e2026b7e7b18c2b807434f2508fe1a2a3dfb493c7df8f4aad6a;
bytes32 internal constant KERNEL_DEFAULT_VAULT_APP_ID = 0x7e852e0fcfce6551c13800f1e7476f982525c2b5277ba14b24339c68416336d1;
}
contract KernelNamespaceConstants {
/* Hardcoded constants to save gas
bytes32 internal constant KERNEL_CORE_NAMESPACE = keccak256("core");
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = keccak256("base");
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = keccak256("app");
*/
bytes32 internal constant KERNEL_CORE_NAMESPACE = 0xc681a85306374a5ab27f0bbc385296a54bcd314a1948b6cf61c4ea1bc44bb9f8;
bytes32 internal constant KERNEL_APP_BASES_NAMESPACE = 0xf1f3eb40f5bc1ad1344716ced8b8a0431d840b5783aea1fd01786bc26f35ac0f;
bytes32 internal constant KERNEL_APP_ADDR_NAMESPACE = 0xd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb;
}
@aragon/os/contracts/lib/token/ERC20.sol
// See https://github.com/OpenZeppelin/openzeppelin-solidity/blob/a9f910d34f0ab33a1ae5e714f69f9596a02b4d91/contracts/token/ERC20/ERC20.sol
pragma solidity ^0.4.24;
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
function totalSupply() public view returns (uint256);
function balanceOf(address _who) public view returns (uint256);
function allowance(address _owner, address _spender)
public view returns (uint256);
function transfer(address _to, uint256 _value) public returns (bool);
function approve(address _spender, uint256 _value)
public returns (bool);
function transferFrom(address _from, address _to, uint256 _value)
public returns (bool);
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"constantinople"}
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"ADD_PROTECTED_TOKEN_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"_interfaceId"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"hasInitialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"ERC1271_INTERFACE_ID","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"onERC721Received","inputs":[{"type":"address","name":"_operator"},{"type":"address","name":"_from"},{"type":"uint256","name":"_tokenId"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"isValidSignature","inputs":[{"type":"bytes32","name":"_hash"},{"type":"bytes","name":"_signature"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"ERC1271_RETURN_INVALID_SIGNATURE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"TRANSFER_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"isValidSignature","inputs":[{"type":"bytes","name":"_data"},{"type":"bytes","name":"_signature"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getProtectedTokensLength","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getEVMScriptExecutor","inputs":[{"type":"bytes","name":"_script"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getRecoveryVault","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"RUN_SCRIPT_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"SAFE_EXECUTE_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"REMOVE_PROTECTED_TOKEN_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"deposit","inputs":[{"type":"address","name":"_token"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isDepositable","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"presignHash","inputs":[{"type":"bytes32","name":"_hash"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"DESIGNATE_SIGNER_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeProtectedToken","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"EXECUTE_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addProtectedToken","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"allowRecoverability","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"appId","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"protectedTokens","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getInitializationBlock","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes4","name":""}],"name":"ERC1271_RETURN_VALID_SIGNATURE","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferToVault","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canPerform","inputs":[{"type":"address","name":"_sender"},{"type":"bytes32","name":"_role"},{"type":"uint256[]","name":"_params"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getEVMScriptRegistry","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setDesignatedSigner","inputs":[{"type":"address","name":"_designatedSigner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"designatedSigner","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"safeExecute","inputs":[{"type":"address","name":"_target"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"PROTECTED_TOKENS_CAP","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":""}],"name":"ADD_PRESIGNED_HASH_ROLE","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isPresigned","inputs":[{"type":"bytes32","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"execute","inputs":[{"type":"address","name":"_target"},{"type":"uint256","name":"_ethValue"},{"type":"bytes","name":"_data"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transfer","inputs":[{"type":"address","name":"_token"},{"type":"address","name":"_to"},{"type":"uint256","name":"_value"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"canForward","inputs":[{"type":"address","name":"_sender"},{"type":"bytes","name":"_evmScript"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"kernel","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"forward","inputs":[{"type":"bytes","name":"_evmScript"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isPetrified","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"balance","inputs":[{"type":"address","name":"_token"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isForwarder","inputs":[],"constant":true},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"event","name":"SafeExecute","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"target","indexed":true},{"type":"bytes","name":"data","indexed":false}],"anonymous":false},{"type":"event","name":"Execute","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"target","indexed":true},{"type":"uint256","name":"ethValue","indexed":false},{"type":"bytes","name":"data","indexed":false}],"anonymous":false},{"type":"event","name":"AddProtectedToken","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"RemoveProtectedToken","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"PresignHash","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"bytes32","name":"hash","indexed":true}],"anonymous":false},{"type":"event","name":"SetDesignatedSigner","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"oldSigner","indexed":true},{"type":"address","name":"newSigner","indexed":true}],"anonymous":false},{"type":"event","name":"ReceiveERC721","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"operator","indexed":true},{"type":"address","name":"from","indexed":true},{"type":"uint256","name":"tokenId","indexed":false},{"type":"bytes","name":"data","indexed":false}],"anonymous":false},{"type":"event","name":"VaultTransfer","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"to","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"VaultDeposit","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"sender","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"ScriptResult","inputs":[{"type":"address","name":"executor","indexed":true},{"type":"bytes","name":"script","indexed":false},{"type":"bytes","name":"input","indexed":false},{"type":"bytes","name":"returnData","indexed":false}],"anonymous":false},{"type":"event","name":"RecoverToVault","inputs":[{"type":"address","name":"vault","indexed":true},{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false}]
Contract Creation Code
0x6080604052620000146200001a60201b60201c565b62000231565b6200002a6200011c60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a454400000000000000006020820152901562000106576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620000ca578181015183820152602001620000b0565b50505050905090810190601f168015620000f85780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506200011a6000196200014f60201b60201c565b565b60006200014a600080516020620041db83398151915260001b600019166200022960201b62002cee1760201c565b905090565b6200015f6200011c60201b60201c565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015620001fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252838181518152602001915080519060200190808383600083811015620000ca578181015183820152602001620000b0565b5062000226600080516020620041db833981519152826200022d602090811b62003ccd17901c565b50565b5490565b9055565b613f9a80620002416000396000f3006080604052600436106102075760003560e01c63ffffffff1680627bb0031461035357806301ffc9a71461037a5780630803fac0146103b057806311a5e409146103c5578063150b7a02146103f75780631626ba7e146104305780631ce301811461048e578063206b60f9146104a357806320c13b0b146104b857806326f06d241461054f5780632914b9bd1461056457806332f0a3b5146105d9578063368c3c34146105ee5780633e4eb7561461060357806342b2d0661461061857806347e7ef241461062d57806348a0c8dd146106445780634c7ec0b01461065957806354842f1414610671578063578eb50b146106865780635fa5e4e6146106a75780636298e902146106bc5780637e7db6e1146106dd57806380afdea8146106fe5780638129fc1c14610713578063851a3790146107285780638b3dd749146107405780639890cdca146107555780639d4941d81461076a578063a1658fad1461078b578063a479e508146107f2578063a83e52b414610807578063aae2505114610828578063ab23c3451461083d578063b03bdb041461086a578063b06c42441461087f578063b4fa653c14610894578063b61d27f6146108ac578063beabacc8146108dd578063c0774df314610907578063d4aae0c41461096e578063d948d46814610983578063de4796ed146109dc578063e3d670d7146109f1578063fd64eccb14610a12575b61020f610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156102bf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561028457818101518382015260200161026c565b50505050905090810190601f1680156102b15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060408051808201909152601381527f5641554c545f444154415f4e4f4e5f5a45524f00000000000000000000000000602082015236156103455760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50610351600034610a51565b005b34801561035f57600080fd5b50610368610ced565b60408051918252519081900360200190f35b34801561038657600080fd5b5061039c600160e060020a031960043516610d11565b604080519115158252519081900360200190f35b3480156103bc57600080fd5b5061039c610a27565b3480156103d157600080fd5b506103da610db0565b60408051600160e060020a03199092168252519081900360200190f35b34801561040357600080fd5b506103da600160a060020a0360048035821691602480359091169160443591606435908101910135610dd4565b34801561043c57600080fd5b5060408051602060046024803582810135601f81018590048502860185019096528585526103da958335953695604494919390910191908190840183828082843750949750610e779650505050505050565b34801561049a57600080fd5b506103da610ee9565b3480156104af57600080fd5b50610368610eee565b3480156104c457600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103da94369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a999881019791965091820194509250829150840183828082843750949750610f239650505050505050565b34801561055b57600080fd5b50610368610f92565b34801561057057600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105bd9436949293602493928401919081908401838280828437509497506110199650505050505050565b60408051600160a060020a039092168252519081900360200190f35b3480156105e557600080fd5b506105bd6110fc565b3480156105fa57600080fd5b50610368611171565b34801561060f57600080fd5b50610368611195565b34801561062457600080fd5b506103686111b9565b610351600160a060020a03600435166024356111dd565b34801561065057600080fd5b5061039c611268565b34801561066557600080fd5b50610351600435611298565b34801561067d57600080fd5b5061036861138a565b34801561069257600080fd5b50610351600160a060020a03600435166113ae565b3480156106b357600080fd5b506103686114f6565b3480156106c857600080fd5b50610351600160a060020a036004351661151a565b3480156106e957600080fd5b5061039c600160a060020a0360043516611777565b34801561070a57600080fd5b5061036861177d565b34801561071f57600080fd5b506103516117a8565b34801561073457600080fd5b506105bd60043561184a565b34801561074c57600080fd5b50610368611872565b34801561076157600080fd5b506103da61189d565b34801561077657600080fd5b50610351600160a060020a03600435166118c1565b34801561079757600080fd5b50604080516020600460443581810135838102808601850190965280855261039c958335600160a060020a0316956024803596369695606495939492019291829185019084908082843750949750611b509650505050505050565b3480156107fe57600080fd5b506105bd611c9d565b34801561081357600080fd5b50610351600160a060020a0360043516611d52565b34801561083457600080fd5b506105bd611ef2565b34801561084957600080fd5b5061035160048035600160a060020a03169060248035908101910135611f01565b34801561087657600080fd5b5061036861245e565b34801561088b57600080fd5b50610368612463565b3480156108a057600080fd5b5061039c600435612487565b3480156108b857600080fd5b5061035160048035600160a060020a031690602480359160443591820191013561249c565b3480156108e957600080fd5b50610351600160a060020a0360043581169060243516604435612645565b34801561091357600080fd5b5060408051602060046024803582810135601f810185900485028601850190965285855261039c958335600160a060020a03169536956044949193909101919081908401838280828437509497506129419650505050505050565b34801561097a57600080fd5b506105bd61297e565b34801561098f57600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103519436949293602493928401919081908401838280828437509497506129a99650505050505050565b3480156109e857600080fd5b5061039c612a6c565b3480156109fd57600080fd5b50610368600160a060020a0360043516612a7f565b348015610a1e57600080fd5b5061039c612ab9565b600080610a32611872565b90508015801590610a4a575080610a47612abe565b10155b91505b5090565b610a59611268565b60408051808201909152601581527f5641554c545f4e4f545f4445504f53495441424c4500000000000000000000006020820152901515610adf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601881527f5641554c545f4445504f5349545f56414c55455f5a45524f0000000000000000602082015260008211610b675760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a0382161515610c045760408051808201909152601481527f5641554c545f56414c55455f4d49534d415443480000000000000000000000006020820152348214610bfe5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50610ca9565b610c1f600160a060020a03831633308463ffffffff612ac216565b6040805190810160405280602081526020017f5641554c545f544f4b454e5f5452414e534645525f46524f4d5f524556455254815250901515610ca75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b6040805182815290513391600160a060020a038516917f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e9181900360200190a35050565b7f6eb2a499556bfa2872f5aa15812b956cc4a71b4d64eb3553f7073c7e41415aaa81565b6000600160e060020a031982167ffb855dc9000000000000000000000000000000000000000000000000000000001480610d745750600160e060020a031982167f150b7a0200000000000000000000000000000000000000000000000000000000145b80610da85750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b90505b919050565b7ffb855dc90000000000000000000000000000000000000000000000000000000081565b600084600160a060020a031686600160a060020a031633600160a060020a03167fe0d2ab3bf6896c073bb33b920a9b60f3c8207b3cc3b7561c3101cb081a8f0883878787604051808481526020018060200182810382528484828181526020019250808284376040519201829003965090945050505050a4507f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b600082815260208190526040812054819060ff1615610ea157610e9a6001612b41565b9150610ee2565b600154600160a060020a03161515610ebb57506000610ed6565b600154610ed3908590600160a060020a031685612b76565b90505b610edf81612b41565b91505b5092915050565b600081565b604080517f5452414e534645525f524f4c45000000000000000000000000000000000000008152905190819003600d01902081565b6000610f8b836040518082805190602001908083835b60208310610f585780518252601f199092019160209182019101610f39565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902083610e77565b9392505050565b6000610f9c610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156110105760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50506002545b90565b6000611023611c9d565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561107e578181015183820152602001611066565b50505050905090810190601f1680156110ab5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b1580156110ca57600080fd5b505af11580156110de573d6000803e3d6000fd5b505050506040513d60208110156110f457600080fd5b505192915050565b600061110661297e565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561114057600080fd5b505af1158015611154573d6000803e3d6000fd5b505050506040513d602081101561116a57600080fd5b5051905090565b7fb421f7ad7646747f3051c50c0b8e2377839296cd4973e27f63821d73e390338f81565b7f0a1ad7b87f5846153c6d5a1f761d71c7d0cfd122384f56066cd33239b793369481565b7f71eee93d500f6f065e38b27d242a756466a00a52a1dbcd6b4260f01a8640402a81565b6111e5610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156112595760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506112648282610a51565b5050565b60006112937f665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea612cee565b905090565b7f0b29780bb523a130b3b01f231ef49ed2fa2781645591a0b0a44ca98f15a5994c6112c282612cf2565b6112cd338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156113415760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600083815260208190526040808220805460ff1916600117905551849133917fb150212e573caa2a0216cf8f273ef996af143fd7b2d35abd92c8105536cac1609190a3505050565b7f23ce341656c3f14df6692eebd4757791e33662b7dcf9970c8308303da5472b7c81565b7f71eee93d500f6f065e38b27d242a756466a00a52a1dbcd6b4260f01a8640402a6113d882612d00565b6113e3338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156114575760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061146183612d14565b60408051808201909152601981527f4147454e545f544f4b454e5f4e4f545f50524f5445435445440000000000000060208201529015156114e75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506114f183612d72565b505050565b7fcebf517aa4440d1d125e0355aae64401211d0848a23c02cc5d29a14822580ba481565b7f6eb2a499556bfa2872f5aa15812b956cc4a71b4d64eb3553f7073c7e41415aaa61154482612d00565b61154f338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156115c35760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060025460408051808201909152601881527f4147454e545f544f4b454e535f4341505f524541434845440000000000000000602082015290600a1161164e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061165883612e2f565b60408051808201909152601581527f4147454e545f544f4b454e5f4e4f545f4552433230000000000000000000000060208201529015156116de5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506116e883612d14565b60408051808201909152601d81527f4147454e545f544f4b454e5f414c52454144595f50524f5445435445440000006020820152901561176d5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506114f183612e5a565b50600090565b60006112937fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b612cee565b6117b0611872565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156118355760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061183e612edf565b6118486001612fa5565b565b600280548290811061185857fe5b600091825260209091200154600160a060020a0316905081565b60006112937febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e612cee565b7f20c13b0b0000000000000000000000000000000000000000000000000000000081565b60008060006118cf84611777565b60408051808201909152601281527f5245434f5645525f444953414c4c4f574544000000000000000000000000000060208201529015156119555760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061195e6110fc565b925061196983612fdc565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156119ef5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a0384161515611a405760405130319250600160a060020a0384169083156108fc029084906000818181858888f19350505050158015611a3a573d6000803e3d6000fd5b50611aff565b5082611a5b600160a060020a0382163063ffffffff61300216565b9150611a77600160a060020a038216848463ffffffff61310216565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c45440000006020820152901515611afd5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080611b5b610a27565b1515611b6a5760009150611c95565b611b7261297e565b9050600160a060020a0381161515611b8d5760009150611c95565b80600160a060020a031663fdef9106863087611ba888613178565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015611c17578181015183820152602001611bff565b50505050905090810190601f168015611c445780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015611c6657600080fd5b505af1158015611c7a573d6000803e3d6000fd5b505050506040513d6020811015611c9057600080fd5b505191505b509392505050565b600080611ca861297e565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b1580156110ca57600080fd5b60007f23ce341656c3f14df6692eebd4757791e33662b7dcf9970c8308303da5472b7c611d7e83612d00565b611d89338383611b50565b60408051808201909152600f8152600080516020613f2f8339815191526020820152901515611dfd5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601881527f4147454e545f44455349474e415445445f544f5f53454c4600000000000000006020820152600160a060020a038516301415611e8e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060018054600160a060020a0386811673ffffffffffffffffffffffffffffffffffffffff198316811790935560405191169450849033907f3ecf54ed9acd859c5ee7f080794267b8f08b65d2446d816cef1efccd6d00d73590600090a450505050565b600154600160a060020a031681565b60006060806000806000806000807f0a1ad7b87f5846153c6d5a1f761d71c7d0cfd122384f56066cd33239b793369460001b611f788d611f708e8e8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613182945050505050565b60e01c61319b565b611f83338383611b50565b60408051808201909152600f8152600080516020613f2f8339815191526020820152901515611ff75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600254604080518281526020808402820101909152909b508b8015612027578160200160208202803883390190505b5099508a604051908082528060200260200182016040528015612054578160200160208202803883390190505b509850600097505b8a88101561216957600280548990811061207257fe5b6000918252602091829020015460408051808201909152601681527f4147454e545f5441524745545f50524f5445435445440000000000000000000092810192909252600160a060020a0390811698508f168814156121165760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50868a8981518110151561212657fe5b600160a060020a0390921660209283029091019091015261214687612a7f565b898981518110151561215457fe5b6020908102909101015260019097019661205c565b8d600160a060020a03168d8d604051808383808284378201915050925050506000604051808303816000865af191505095503d935060405194503d85016040523d6000863e851561245a5760025460408051808201909152601f81527f4147454e545f50524f5445435445445f544f4b454e535f4d4f444946494544006020820152908c1461223d5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600092505b8a8310156123f257898381518110151561225957fe5b90602001906020020151600160a060020a031660028481548110151561227b57fe5b6000918252602091829020015460408051808201909152601f81527f4147454e545f50524f5445435445445f544f4b454e535f4d4f44494649454400928101929092529091600160a060020a039091161461231b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50888381518110151561232a57fe5b9060200190602002015161236060028581548110151561234657fe5b600091825260209091200154600160a060020a0316612a7f565b60408051808201909152601f81527f4147454e545f50524f5445435445445f42414c414e43455f4c4f57455245440060208201529111156123e65760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600190920191612243565b8d600160a060020a031633600160a060020a03167f47f4287d5285559a03d8affeadc53ef3fca238a63c256c08a22bfd30fd5d33ce8f8f6040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a38385f35b8385fd5b600a81565b7f0b29780bb523a130b3b01f231ef49ed2fa2781645591a0b0a44ca98f15a5994c81565b60006020819052908152604090205460ff1681565b60007fcebf517aa4440d1d125e0355aae64401211d0848a23c02cc5d29a14822580ba460001b612508868661250087878080601f01602080910402602001604051908101604052809392919081815260200183838082843750613182945050505050565b60e01c6131b0565b612513338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156125875760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5086600160a060020a03168686866040518083838082843782019150509250505060006040518083038185875af1925050509250821561262e5786600160a060020a031633600160a060020a03167fc25cfed0b22da6a56f0e5ff784979a0b8623eddf2aee4acd33c2adefb09cbab6888888604051808481526020018060200182810382528484828181526020019250808284376040519201829003965090945050505050a35b6040513d6000823e838015612641573d82f35b3d82fd5b604080517f5452414e534645525f524f4c45000000000000000000000000000000000000008152905190819003600d0190206126828484846131ce565b61268d338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156127015760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601981527f5641554c545f5452414e534645525f56414c55455f5a45524f000000000000006020820152600084116127895760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a038516151561284d57604051600160a060020a0385169084156108fc029085906000818181858888f193505050506040805190810160405280601381526020017f5641554c545f53454e445f5245564552544544000000000000000000000000008152509015156128475760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506128ef565b612867600160a060020a038616858563ffffffff61310216565b60408051808201909152601d81527f5641554c545f544f4b454e5f5452414e534645525f524556455254454400000060208201529015156128ed5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b83600160a060020a031685600160a060020a03167f239e7f6cdac8fb35a788a46b431b54da87de90b82448a2c294be5e92a6e579af856040518082815260200191505060405180910390a35050505050565b6000610f8b837fb421f7ad7646747f3051c50c0b8e2377839296cd4973e27f63821d73e390338f612979612974866131ed565b6132ba565b611b50565b60006112937f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b612cee565b6060806129b63384612941565b60408051808201909152601581527f4147454e545f43414e5f4e4f545f464f525741524400000000000000000000006020820152901515612a3c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50506040805160208082018352600080835283519081529081019092529150612a668383836132fb565b50505050565b6000600019612a79611872565b14905090565b6000600160a060020a0382161515612a9957503031610dab565b612ab2600160a060020a0383163063ffffffff61300216565b9050610dab565b600190565b4390565b60408051600160a060020a038581166024830152841660448201526064808201849052825180830390910181526084909101909152602081018051600160e060020a03167f23b872dd00000000000000000000000000000000000000000000000000000000179052600090612b3786826138ee565b9695505050505050565b600081612b4f576000610da8565b507f20c13b0b00000000000000000000000000000000000000000000000000000000919050565b6000806000835160001415612b8e5760009250612ce5565b836000815181101515612b9d57fe5b016020015160f890811c811b901c9150600460ff831610612bc15760009250612ce5565b8160ff166004811115612bd057fe5b90506001816004811115612be057fe5b1415612bf857612bf186868661393c565b9250612ce5565b6002816004811115612c0657fe5b1415612cb957604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083018a905283518084039091018152605c909201928390528151612bf193918291908401908083835b60208310612c855780518252601f199092019160209182019101612c66565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020868661393c565b6003816004811115612cc757fe5b1415612ce057612bf18587612cdb876139ea565b613adf565b600092505b50509392505050565b5490565b6060610da88260001c6132ba565b6060610da882600160a060020a03166132ba565b6000805b600254811015612d675782600160a060020a0316600282815481101515612d3b57fe5b600091825260209091200154600160a060020a03161415612d5f5760019150612d6c565b600101612d18565b600091505b50919050565b600280546000198101908110612d8457fe5b600091825260209091200154600160a060020a03166002612da483613bfe565b81548110612dae57fe5b6000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790556002805490612df7906000198301613ef5565b50604051600160a060020a038216907f3da25279c93c5b22b359bebff8b5ddbfd9b0506be8344b93c9a7dc999459fe0490600090a250565b6000612e3a82612fdc565b1515612e4857506000610dab565b612e5182612a7f565b50600192915050565b6002805460018101825560009182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03841690811790915560405190917ff70a5123a7f334e5dac1d9aa3a6aafbc316712bf2519ffe0d3aa4f7cba52767e91a250565b612ee7611872565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015612f6c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50611848612f78612abe565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff613ccd16565b612fd57f665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea8263ffffffff613ccd16565b50565b5490565b600080600160a060020a0383161515612ff85760009150612d6c565b50506000903b1190565b60408051600160a060020a038316602480830191909152825180830390910181526044909101909152602081018051600160e060020a03167f70a0823100000000000000000000000000000000000000000000000000000000179052600090818061306d8684613cd1565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156130f85760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5095945050505050565b60408051600160a060020a03841660248201526044808201849052825180830390910181526064909101909152602081018051600160e060020a03167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061316f85826138ee565b95945050505050565b8051602002815290565b600060048251101561319357610dab565b506020015190565b6060610f8b83600160a060020a031683613d02565b60606131c684600160a060020a03168484613d5d565b949350505050565b60606131c684600160a060020a031684600160a060020a031684613d5d565b6000816040516020018082805190602001908083835b602083106132225780518252601f199092019160209182019101613203565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106132855780518252601f199092019160209182019101613266565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c95945050505050565b60408051600180825281830190925260609160208083019080388339019050509050818160008151811015156132ec57fe5b60209081029091010152919050565b606060008060608061330b610a27565b6040805180820190915260148152600080516020613f4f833981519152602082015290151561337f5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060008061338b61297e565b915061339561177d565b90506133a08a611019565b60408051808201909152601b81527f45564d52554e5f4558454355544f525f554e415641494c41424c4500000000006020820152909650600160a060020a03871615156134325760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506040516060602482019081528b5160848301528b517f279cea3500000000000000000000000000000000000000000000000000000000975087928d928d928d9282916044820191606481019160a490910190602089019080838360005b838110156134a8578181015183820152602001613490565b50505050905090810190601f1680156134d55780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b838110156135085781810151838201526020016134f0565b50505050905090810190601f1680156135355780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b8381101561356a578181015183820152602001613552565b50505050905001965050505050505060405160208183030381529060405290600160e060020a031916602082018051600160e060020a0383818316178352505050509350600080855160208701895af4604051935080801561362e57603f3d1180156135e35760203d03806020883e8601604052613628565b60e560020a62461bcd02865260206004870152601e60248701527f45564d52554e5f4558454355544f525f494e56414c49445f52455455524e00006044870152606486fd5b50613637565b3d6000863e3d85fd5b505085600160a060020a03167f5229a5dba83a54ae8cb5b51bdd6de9474cacbe9dd332f5185f3a4f4f2e3f4ad98b8b8660405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b838110156136ac578181015183820152602001613694565b50505050905090810190601f1680156136d95780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b8381101561370c5781810151838201526020016136f4565b50505050905090810190601f1680156137395780820380516001836020036101000a031916815260200191505b50848103825285518152855160209182019187019080838360005b8381101561376c578181015183820152602001613754565b50505050905090810190601f1680156137995780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a282965081600160a060020a03166137bf61297e565b600160a060020a0316146040805190810160405280601f81526020017f45564d52554e5f50524f5445435445445f53544154455f4d4f444946494544008152509015156138515760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b508061385b61177d565b60408051808201909152601f81527f45564d52554e5f50524f5445435445445f53544154455f4d4f44494649454400602082015291146138e05760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505050505050509392505050565b6000806040516020818551602087016000895af16000811115613932573d801561391f576020811461392857613930565b60019350613930565b600183511493505b505b5090949350505050565b600080600080600061394d86613dd6565b9350935093509350831561396457600094506139df565b60408051600080825260208083018085528c905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af11580156139be573d6000803e3d6000fd5b50505060206040510351600160a060020a031687600160a060020a03161494505b505050509392505050565b805160408051808201909152601e81527f53494756414c5f494e56414c49445f4c454e4754485f504f505f4259544500006020820152606091906000908190818411613a7b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600183036040519080825280601f01601f191660200182016040528015613aad578160200160208202803883390190505b509350835160001415613abf57613ad7565b602185019150602084019050613ad781838651613e57565b505050919050565b60408051602481018481526044820192835283516064830152835160009360609385937f1626ba7e000000000000000000000000000000000000000000000000000000009389938993909160849091019060208501908083838b5b83811015613b52578181015183820152602001613b3a565b50505050905090810190601f168015613b7f5780820380516001836020036101000a031916815260200191505b50935050505060405160208183030381529060405290600160e060020a031916602082018051600160e060020a0383818316178352505050509150613bc886836203d090613e9b565b600160e060020a0319167f20c13b0b00000000000000000000000000000000000000000000000000000000149695505050505050565b6000805b600254811015613c505782600160a060020a0316600282815481101515613c2557fe5b600091825260209091200154600160a060020a03161415613c4857809150612d6c565b600101613c02565b604080518082018252601981527f4147454e545f544f4b454e5f4e4f545f50524f544543544544000000000000006020808301918252925160e560020a62461bcd0281526004810193845282516024820152825192939283926044909201919080838360008381101561028457818101518382015260200161026c565b9055565b6000806000806040516020818751602089018a5afa92506000831115613cf657805191505b50909590945092505050565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515613d3257fe5b602090810290910101528051829082906001908110613d4d57fe5b6020908102909101015292915050565b6040805160038082526080820190925260609160208201838038833901905050905083816000815181101515613d8f57fe5b602090810290910101528051839082906001908110613daa57fe5b602090810290910101528051829082906002908110613dc557fe5b602090810290910101529392505050565b60008060008084516042141515613df05760019350613e50565b846041815181101515613dff57fe5b90602001015160f81c60f81b60f81c90506021850151925060418501519150601b8160ff161015613e2e57601b015b8060ff16601b14158015613e4657508060ff16601c14155b15613e5057600193505b9193509193565b60005b60208210613e7c578251845260209384019390920191601f1990910190613e5a565b50905182516020929092036101000a6000190180199091169116179052565b60008060008060005a9350858411613eb35783613eb5565b855b9250600080885160208a018b87fa9150811515613ed1576139df565b503d60208114613ee0576139df565b604051816000823e5198975050505050505050565b8154818355818111156114f1576000838152602090206114f191810190830161101691905b80821115610a4d5760008155600101613f1a56004150505f415554485f4641494c45440000000000000000000000000000000000494e49545f4e4f545f494e495449414c495a4544000000000000000000000000a165627a7a72305820874a11eb1b5a6c34530bdb9ad5c9bd0d4ff8e59d5cafd7ff03eae869d79ee7670029ebb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e
Deployed ByteCode
0x6080604052600436106102075760003560e01c63ffffffff1680627bb0031461035357806301ffc9a71461037a5780630803fac0146103b057806311a5e409146103c5578063150b7a02146103f75780631626ba7e146104305780631ce301811461048e578063206b60f9146104a357806320c13b0b146104b857806326f06d241461054f5780632914b9bd1461056457806332f0a3b5146105d9578063368c3c34146105ee5780633e4eb7561461060357806342b2d0661461061857806347e7ef241461062d57806348a0c8dd146106445780634c7ec0b01461065957806354842f1414610671578063578eb50b146106865780635fa5e4e6146106a75780636298e902146106bc5780637e7db6e1146106dd57806380afdea8146106fe5780638129fc1c14610713578063851a3790146107285780638b3dd749146107405780639890cdca146107555780639d4941d81461076a578063a1658fad1461078b578063a479e508146107f2578063a83e52b414610807578063aae2505114610828578063ab23c3451461083d578063b03bdb041461086a578063b06c42441461087f578063b4fa653c14610894578063b61d27f6146108ac578063beabacc8146108dd578063c0774df314610907578063d4aae0c41461096e578063d948d46814610983578063de4796ed146109dc578063e3d670d7146109f1578063fd64eccb14610a12575b61020f610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156102bf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561028457818101518382015260200161026c565b50505050905090810190601f1680156102b15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060408051808201909152601381527f5641554c545f444154415f4e4f4e5f5a45524f00000000000000000000000000602082015236156103455760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50610351600034610a51565b005b34801561035f57600080fd5b50610368610ced565b60408051918252519081900360200190f35b34801561038657600080fd5b5061039c600160e060020a031960043516610d11565b604080519115158252519081900360200190f35b3480156103bc57600080fd5b5061039c610a27565b3480156103d157600080fd5b506103da610db0565b60408051600160e060020a03199092168252519081900360200190f35b34801561040357600080fd5b506103da600160a060020a0360048035821691602480359091169160443591606435908101910135610dd4565b34801561043c57600080fd5b5060408051602060046024803582810135601f81018590048502860185019096528585526103da958335953695604494919390910191908190840183828082843750949750610e779650505050505050565b34801561049a57600080fd5b506103da610ee9565b3480156104af57600080fd5b50610368610eee565b3480156104c457600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103da94369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a999881019791965091820194509250829150840183828082843750949750610f239650505050505050565b34801561055b57600080fd5b50610368610f92565b34801561057057600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526105bd9436949293602493928401919081908401838280828437509497506110199650505050505050565b60408051600160a060020a039092168252519081900360200190f35b3480156105e557600080fd5b506105bd6110fc565b3480156105fa57600080fd5b50610368611171565b34801561060f57600080fd5b50610368611195565b34801561062457600080fd5b506103686111b9565b610351600160a060020a03600435166024356111dd565b34801561065057600080fd5b5061039c611268565b34801561066557600080fd5b50610351600435611298565b34801561067d57600080fd5b5061036861138a565b34801561069257600080fd5b50610351600160a060020a03600435166113ae565b3480156106b357600080fd5b506103686114f6565b3480156106c857600080fd5b50610351600160a060020a036004351661151a565b3480156106e957600080fd5b5061039c600160a060020a0360043516611777565b34801561070a57600080fd5b5061036861177d565b34801561071f57600080fd5b506103516117a8565b34801561073457600080fd5b506105bd60043561184a565b34801561074c57600080fd5b50610368611872565b34801561076157600080fd5b506103da61189d565b34801561077657600080fd5b50610351600160a060020a03600435166118c1565b34801561079757600080fd5b50604080516020600460443581810135838102808601850190965280855261039c958335600160a060020a0316956024803596369695606495939492019291829185019084908082843750949750611b509650505050505050565b3480156107fe57600080fd5b506105bd611c9d565b34801561081357600080fd5b50610351600160a060020a0360043516611d52565b34801561083457600080fd5b506105bd611ef2565b34801561084957600080fd5b5061035160048035600160a060020a03169060248035908101910135611f01565b34801561087657600080fd5b5061036861245e565b34801561088b57600080fd5b50610368612463565b3480156108a057600080fd5b5061039c600435612487565b3480156108b857600080fd5b5061035160048035600160a060020a031690602480359160443591820191013561249c565b3480156108e957600080fd5b50610351600160a060020a0360043581169060243516604435612645565b34801561091357600080fd5b5060408051602060046024803582810135601f810185900485028601850190965285855261039c958335600160a060020a03169536956044949193909101919081908401838280828437509497506129419650505050505050565b34801561097a57600080fd5b506105bd61297e565b34801561098f57600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526103519436949293602493928401919081908401838280828437509497506129a99650505050505050565b3480156109e857600080fd5b5061039c612a6c565b3480156109fd57600080fd5b50610368600160a060020a0360043516612a7f565b348015610a1e57600080fd5b5061039c612ab9565b600080610a32611872565b90508015801590610a4a575080610a47612abe565b10155b91505b5090565b610a59611268565b60408051808201909152601581527f5641554c545f4e4f545f4445504f53495441424c4500000000000000000000006020820152901515610adf5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601881527f5641554c545f4445504f5349545f56414c55455f5a45524f0000000000000000602082015260008211610b675760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a0382161515610c045760408051808201909152601481527f5641554c545f56414c55455f4d49534d415443480000000000000000000000006020820152348214610bfe5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50610ca9565b610c1f600160a060020a03831633308463ffffffff612ac216565b6040805190810160405280602081526020017f5641554c545f544f4b454e5f5452414e534645525f46524f4d5f524556455254815250901515610ca75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b6040805182815290513391600160a060020a038516917f2790b90165fd3973ad7edde4eca71b4f8808dd4857a2a3a3e8ae5642a5cb196e9181900360200190a35050565b7f6eb2a499556bfa2872f5aa15812b956cc4a71b4d64eb3553f7073c7e41415aaa81565b6000600160e060020a031982167ffb855dc9000000000000000000000000000000000000000000000000000000001480610d745750600160e060020a031982167f150b7a0200000000000000000000000000000000000000000000000000000000145b80610da85750600160e060020a031982167f01ffc9a700000000000000000000000000000000000000000000000000000000145b90505b919050565b7ffb855dc90000000000000000000000000000000000000000000000000000000081565b600084600160a060020a031686600160a060020a031633600160a060020a03167fe0d2ab3bf6896c073bb33b920a9b60f3c8207b3cc3b7561c3101cb081a8f0883878787604051808481526020018060200182810382528484828181526020019250808284376040519201829003965090945050505050a4507f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b600082815260208190526040812054819060ff1615610ea157610e9a6001612b41565b9150610ee2565b600154600160a060020a03161515610ebb57506000610ed6565b600154610ed3908590600160a060020a031685612b76565b90505b610edf81612b41565b91505b5092915050565b600081565b604080517f5452414e534645525f524f4c45000000000000000000000000000000000000008152905190819003600d01902081565b6000610f8b836040518082805190602001908083835b60208310610f585780518252601f199092019160209182019101610f39565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902083610e77565b9392505050565b6000610f9c610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156110105760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50506002545b90565b6000611023611c9d565b600160a060020a03166304bf2a7f836040518263ffffffff1660e01b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561107e578181015183820152602001611066565b50505050905090810190601f1680156110ab5780820380516001836020036101000a031916815260200191505b5092505050602060405180830381600087803b1580156110ca57600080fd5b505af11580156110de573d6000803e3d6000fd5b505050506040513d60208110156110f457600080fd5b505192915050565b600061110661297e565b600160a060020a03166332f0a3b56040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561114057600080fd5b505af1158015611154573d6000803e3d6000fd5b505050506040513d602081101561116a57600080fd5b5051905090565b7fb421f7ad7646747f3051c50c0b8e2377839296cd4973e27f63821d73e390338f81565b7f0a1ad7b87f5846153c6d5a1f761d71c7d0cfd122384f56066cd33239b793369481565b7f71eee93d500f6f065e38b27d242a756466a00a52a1dbcd6b4260f01a8640402a81565b6111e5610a27565b6040805180820190915260148152600080516020613f4f83398151915260208201529015156112595760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506112648282610a51565b5050565b60006112937f665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea612cee565b905090565b7f0b29780bb523a130b3b01f231ef49ed2fa2781645591a0b0a44ca98f15a5994c6112c282612cf2565b6112cd338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156113415760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600083815260208190526040808220805460ff1916600117905551849133917fb150212e573caa2a0216cf8f273ef996af143fd7b2d35abd92c8105536cac1609190a3505050565b7f23ce341656c3f14df6692eebd4757791e33662b7dcf9970c8308303da5472b7c81565b7f71eee93d500f6f065e38b27d242a756466a00a52a1dbcd6b4260f01a8640402a6113d882612d00565b6113e3338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156114575760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061146183612d14565b60408051808201909152601981527f4147454e545f544f4b454e5f4e4f545f50524f5445435445440000000000000060208201529015156114e75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506114f183612d72565b505050565b7fcebf517aa4440d1d125e0355aae64401211d0848a23c02cc5d29a14822580ba481565b7f6eb2a499556bfa2872f5aa15812b956cc4a71b4d64eb3553f7073c7e41415aaa61154482612d00565b61154f338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156115c35760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060025460408051808201909152601881527f4147454e545f544f4b454e535f4341505f524541434845440000000000000000602082015290600a1161164e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061165883612e2f565b60408051808201909152601581527f4147454e545f544f4b454e5f4e4f545f4552433230000000000000000000000060208201529015156116de5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506116e883612d14565b60408051808201909152601d81527f4147454e545f544f4b454e5f414c52454144595f50524f5445435445440000006020820152901561176d5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506114f183612e5a565b50600090565b60006112937fd625496217aa6a3453eecb9c3489dc5a53e6c67b444329ea2b2cbc9ff547639b612cee565b6117b0611872565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a45440000000000000000602082015290156118355760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061183e612edf565b6118486001612fa5565b565b600280548290811061185857fe5b600091825260209091200154600160a060020a0316905081565b60006112937febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e612cee565b7f20c13b0b0000000000000000000000000000000000000000000000000000000081565b60008060006118cf84611777565b60408051808201909152601281527f5245434f5645525f444953414c4c4f574544000000000000000000000000000060208201529015156119555760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5061195e6110fc565b925061196983612fdc565b60408051808201909152601a81527f5245434f5645525f5641554c545f4e4f545f434f4e545241435400000000000060208201529015156119ef5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a0384161515611a405760405130319250600160a060020a0384169083156108fc029084906000818181858888f19350505050158015611a3a573d6000803e3d6000fd5b50611aff565b5082611a5b600160a060020a0382163063ffffffff61300216565b9150611a77600160a060020a038216848463ffffffff61310216565b60408051808201909152601d81527f5245434f5645525f544f4b454e5f5452414e534645525f4641494c45440000006020820152901515611afd5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b83600160a060020a031683600160a060020a03167f596caf56044b55fb8c4ca640089bbc2b63cae3e978b851f5745cbb7c5b288e02846040518082815260200191505060405180910390a350505050565b600080611b5b610a27565b1515611b6a5760009150611c95565b611b7261297e565b9050600160a060020a0381161515611b8d5760009150611c95565b80600160a060020a031663fdef9106863087611ba888613178565b60405163ffffffff861660e01b8152600160a060020a03808616600483019081529085166024830152604482018490526080606483019081528351608484015283519192909160a490910190602085019080838360005b83811015611c17578181015183820152602001611bff565b50505050905090810190601f168015611c445780820380516001836020036101000a031916815260200191505b5095505050505050602060405180830381600087803b158015611c6657600080fd5b505af1158015611c7a573d6000803e3d6000fd5b505050506040513d6020811015611c9057600080fd5b505191505b509392505050565b600080611ca861297e565b604080517fbe00bbd80000000000000000000000000000000000000000000000000000000081527fd6f028ca0e8edb4a8c9757ca4fdccab25fa1e0317da1188108f7d2dee14902fb60048201527fddbcfd564f642ab5627cf68b9b7d374fb4f8a36e941a75d89c87998cef03bd6160248201529051600160a060020a03929092169163be00bbd8916044808201926020929091908290030181600087803b1580156110ca57600080fd5b60007f23ce341656c3f14df6692eebd4757791e33662b7dcf9970c8308303da5472b7c611d7e83612d00565b611d89338383611b50565b60408051808201909152600f8152600080516020613f2f8339815191526020820152901515611dfd5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601881527f4147454e545f44455349474e415445445f544f5f53454c4600000000000000006020820152600160a060020a038516301415611e8e5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060018054600160a060020a0386811673ffffffffffffffffffffffffffffffffffffffff198316811790935560405191169450849033907f3ecf54ed9acd859c5ee7f080794267b8f08b65d2446d816cef1efccd6d00d73590600090a450505050565b600154600160a060020a031681565b60006060806000806000806000807f0a1ad7b87f5846153c6d5a1f761d71c7d0cfd122384f56066cd33239b793369460001b611f788d611f708e8e8080601f01602080910402602001604051908101604052809392919081815260200183838082843750613182945050505050565b60e01c61319b565b611f83338383611b50565b60408051808201909152600f8152600080516020613f2f8339815191526020820152901515611ff75760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600254604080518281526020808402820101909152909b508b8015612027578160200160208202803883390190505b5099508a604051908082528060200260200182016040528015612054578160200160208202803883390190505b509850600097505b8a88101561216957600280548990811061207257fe5b6000918252602091829020015460408051808201909152601681527f4147454e545f5441524745545f50524f5445435445440000000000000000000092810192909252600160a060020a0390811698508f168814156121165760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50868a8981518110151561212657fe5b600160a060020a0390921660209283029091019091015261214687612a7f565b898981518110151561215457fe5b6020908102909101015260019097019661205c565b8d600160a060020a03168d8d604051808383808284378201915050925050506000604051808303816000865af191505095503d935060405194503d85016040523d6000863e851561245a5760025460408051808201909152601f81527f4147454e545f50524f5445435445445f544f4b454e535f4d4f444946494544006020820152908c1461223d5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600092505b8a8310156123f257898381518110151561225957fe5b90602001906020020151600160a060020a031660028481548110151561227b57fe5b6000918252602091829020015460408051808201909152601f81527f4147454e545f50524f5445435445445f544f4b454e535f4d4f44494649454400928101929092529091600160a060020a039091161461231b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50888381518110151561232a57fe5b9060200190602002015161236060028581548110151561234657fe5b600091825260209091200154600160a060020a0316612a7f565b60408051808201909152601f81527f4147454e545f50524f5445435445445f42414c414e43455f4c4f57455245440060208201529111156123e65760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600190920191612243565b8d600160a060020a031633600160a060020a03167f47f4287d5285559a03d8affeadc53ef3fca238a63c256c08a22bfd30fd5d33ce8f8f6040518080602001828103825284848281815260200192508082843760405192018290039550909350505050a38385f35b8385fd5b600a81565b7f0b29780bb523a130b3b01f231ef49ed2fa2781645591a0b0a44ca98f15a5994c81565b60006020819052908152604090205460ff1681565b60007fcebf517aa4440d1d125e0355aae64401211d0848a23c02cc5d29a14822580ba460001b612508868661250087878080601f01602080910402602001604051908101604052809392919081815260200183838082843750613182945050505050565b60e01c6131b0565b612513338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156125875760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5086600160a060020a03168686866040518083838082843782019150509250505060006040518083038185875af1925050509250821561262e5786600160a060020a031633600160a060020a03167fc25cfed0b22da6a56f0e5ff784979a0b8623eddf2aee4acd33c2adefb09cbab6888888604051808481526020018060200182810382528484828181526020019250808284376040519201829003965090945050505050a35b6040513d6000823e838015612641573d82f35b3d82fd5b604080517f5452414e534645525f524f4c45000000000000000000000000000000000000008152905190819003600d0190206126828484846131ce565b61268d338383611b50565b60408051808201909152600f8152600080516020613f2f83398151915260208201529015156127015760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060408051808201909152601981527f5641554c545f5452414e534645525f56414c55455f5a45524f000000000000006020820152600084116127895760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600160a060020a038516151561284d57604051600160a060020a0385169084156108fc029085906000818181858888f193505050506040805190810160405280601381526020017f5641554c545f53454e445f5245564552544544000000000000000000000000008152509015156128475760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506128ef565b612867600160a060020a038616858563ffffffff61310216565b60408051808201909152601d81527f5641554c545f544f4b454e5f5452414e534645525f524556455254454400000060208201529015156128ed5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505b83600160a060020a031685600160a060020a03167f239e7f6cdac8fb35a788a46b431b54da87de90b82448a2c294be5e92a6e579af856040518082815260200191505060405180910390a35050505050565b6000610f8b837fb421f7ad7646747f3051c50c0b8e2377839296cd4973e27f63821d73e390338f612979612974866131ed565b6132ba565b611b50565b60006112937f4172f0f7d2289153072b0a6ca36959e0cbe2efc3afe50fc81636caa96338137b612cee565b6060806129b63384612941565b60408051808201909152601581527f4147454e545f43414e5f4e4f545f464f525741524400000000000000000000006020820152901515612a3c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50506040805160208082018352600080835283519081529081019092529150612a668383836132fb565b50505050565b6000600019612a79611872565b14905090565b6000600160a060020a0382161515612a9957503031610dab565b612ab2600160a060020a0383163063ffffffff61300216565b9050610dab565b600190565b4390565b60408051600160a060020a038581166024830152841660448201526064808201849052825180830390910181526084909101909152602081018051600160e060020a03167f23b872dd00000000000000000000000000000000000000000000000000000000179052600090612b3786826138ee565b9695505050505050565b600081612b4f576000610da8565b507f20c13b0b00000000000000000000000000000000000000000000000000000000919050565b6000806000835160001415612b8e5760009250612ce5565b836000815181101515612b9d57fe5b016020015160f890811c811b901c9150600460ff831610612bc15760009250612ce5565b8160ff166004811115612bd057fe5b90506001816004811115612be057fe5b1415612bf857612bf186868661393c565b9250612ce5565b6002816004811115612c0657fe5b1415612cb957604080517f19457468657265756d205369676e6564204d6573736167653a0a333200000000602080830191909152603c8083018a905283518084039091018152605c909201928390528151612bf193918291908401908083835b60208310612c855780518252601f199092019160209182019101612c66565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020868661393c565b6003816004811115612cc757fe5b1415612ce057612bf18587612cdb876139ea565b613adf565b600092505b50509392505050565b5490565b6060610da88260001c6132ba565b6060610da882600160a060020a03166132ba565b6000805b600254811015612d675782600160a060020a0316600282815481101515612d3b57fe5b600091825260209091200154600160a060020a03161415612d5f5760019150612d6c565b600101612d18565b600091505b50919050565b600280546000198101908110612d8457fe5b600091825260209091200154600160a060020a03166002612da483613bfe565b81548110612dae57fe5b6000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03929092169190911790556002805490612df7906000198301613ef5565b50604051600160a060020a038216907f3da25279c93c5b22b359bebff8b5ddbfd9b0506be8344b93c9a7dc999459fe0490600090a250565b6000612e3a82612fdc565b1515612e4857506000610dab565b612e5182612a7f565b50600192915050565b6002805460018101825560009182527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace01805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03841690811790915560405190917ff70a5123a7f334e5dac1d9aa3a6aafbc316712bf2519ffe0d3aa4f7cba52767e91a250565b612ee7611872565b60408051808201909152601881527f494e49545f414c52454144595f494e495449414c495a4544000000000000000060208201529015612f6c5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50611848612f78612abe565b7febb05b386a8d34882b8711d156f463690983dc47815980fb82aeeff1aa43579e9063ffffffff613ccd16565b612fd57f665fd576fbbe6f247aff98f5c94a561e3f71ec2d3c988d56f12d342396c50cea8263ffffffff613ccd16565b50565b5490565b600080600160a060020a0383161515612ff85760009150612d6c565b50506000903b1190565b60408051600160a060020a038316602480830191909152825180830390910181526044909101909152602081018051600160e060020a03167f70a0823100000000000000000000000000000000000000000000000000000000179052600090818061306d8684613cd1565b60408051808201909152601c81527f534146455f4552435f32305f42414c414e43455f524556455254454400000000602082015291935091508215156130f85760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5095945050505050565b60408051600160a060020a03841660248201526044808201849052825180830390910181526064909101909152602081018051600160e060020a03167fa9059cbb0000000000000000000000000000000000000000000000000000000017905260009061316f85826138ee565b95945050505050565b8051602002815290565b600060048251101561319357610dab565b506020015190565b6060610f8b83600160a060020a031683613d02565b60606131c684600160a060020a03168484613d5d565b949350505050565b60606131c684600160a060020a031684600160a060020a031684613d5d565b6000816040516020018082805190602001908083835b602083106132225780518252601f199092019160209182019101613203565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040516020818303038152906040526040518082805190602001908083835b602083106132855780518252601f199092019160209182019101613266565b5181516020939093036101000a6000190180199091169216919091179052604051920182900390912060001c95945050505050565b60408051600180825281830190925260609160208083019080388339019050509050818160008151811015156132ec57fe5b60209081029091010152919050565b606060008060608061330b610a27565b6040805180820190915260148152600080516020613f4f833981519152602082015290151561337f5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b5060008061338b61297e565b915061339561177d565b90506133a08a611019565b60408051808201909152601b81527f45564d52554e5f4558454355544f525f554e415641494c41424c4500000000006020820152909650600160a060020a03871615156134325760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b506040516060602482019081528b5160848301528b517f279cea3500000000000000000000000000000000000000000000000000000000975087928d928d928d9282916044820191606481019160a490910190602089019080838360005b838110156134a8578181015183820152602001613490565b50505050905090810190601f1680156134d55780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b838110156135085781810151838201526020016134f0565b50505050905090810190601f1680156135355780820380516001836020036101000a031916815260200191505b508481038252855181528551602091820191808801910280838360005b8381101561356a578181015183820152602001613552565b50505050905001965050505050505060405160208183030381529060405290600160e060020a031916602082018051600160e060020a0383818316178352505050509350600080855160208701895af4604051935080801561362e57603f3d1180156135e35760203d03806020883e8601604052613628565b60e560020a62461bcd02865260206004870152601e60248701527f45564d52554e5f4558454355544f525f494e56414c49445f52455455524e00006044870152606486fd5b50613637565b3d6000863e3d85fd5b505085600160a060020a03167f5229a5dba83a54ae8cb5b51bdd6de9474cacbe9dd332f5185f3a4f4f2e3f4ad98b8b8660405180806020018060200180602001848103845287818151815260200191508051906020019080838360005b838110156136ac578181015183820152602001613694565b50505050905090810190601f1680156136d95780820380516001836020036101000a031916815260200191505b50848103835286518152865160209182019188019080838360005b8381101561370c5781810151838201526020016136f4565b50505050905090810190601f1680156137395780820380516001836020036101000a031916815260200191505b50848103825285518152855160209182019187019080838360005b8381101561376c578181015183820152602001613754565b50505050905090810190601f1680156137995780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a282965081600160a060020a03166137bf61297e565b600160a060020a0316146040805190810160405280601f81526020017f45564d52554e5f50524f5445435445445f53544154455f4d4f444946494544008152509015156138515760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b508061385b61177d565b60408051808201909152601f81527f45564d52554e5f50524f5445435445445f53544154455f4d4f44494649454400602082015291146138e05760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b505050505050509392505050565b6000806040516020818551602087016000895af16000811115613932573d801561391f576020811461392857613930565b60019350613930565b600183511493505b505b5090949350505050565b600080600080600061394d86613dd6565b9350935093509350831561396457600094506139df565b60408051600080825260208083018085528c905260ff8516838501526060830187905260808301869052925160019360a0808501949193601f19840193928390039091019190865af11580156139be573d6000803e3d6000fd5b50505060206040510351600160a060020a031687600160a060020a03161494505b505050509392505050565b805160408051808201909152601e81527f53494756414c5f494e56414c49445f4c454e4754485f504f505f4259544500006020820152606091906000908190818411613a7b5760405160e560020a62461bcd0281526004018080602001828103825283818151815260200191508051906020019080838360008381101561028457818101518382015260200161026c565b50600183036040519080825280601f01601f191660200182016040528015613aad578160200160208202803883390190505b509350835160001415613abf57613ad7565b602185019150602084019050613ad781838651613e57565b505050919050565b60408051602481018481526044820192835283516064830152835160009360609385937f1626ba7e000000000000000000000000000000000000000000000000000000009389938993909160849091019060208501908083838b5b83811015613b52578181015183820152602001613b3a565b50505050905090810190601f168015613b7f5780820380516001836020036101000a031916815260200191505b50935050505060405160208183030381529060405290600160e060020a031916602082018051600160e060020a0383818316178352505050509150613bc886836203d090613e9b565b600160e060020a0319167f20c13b0b00000000000000000000000000000000000000000000000000000000149695505050505050565b6000805b600254811015613c505782600160a060020a0316600282815481101515613c2557fe5b600091825260209091200154600160a060020a03161415613c4857809150612d6c565b600101613c02565b604080518082018252601981527f4147454e545f544f4b454e5f4e4f545f50524f544543544544000000000000006020808301918252925160e560020a62461bcd0281526004810193845282516024820152825192939283926044909201919080838360008381101561028457818101518382015260200161026c565b9055565b6000806000806040516020818751602089018a5afa92506000831115613cf657805191505b50909590945092505050565b604080516002808252606080830184529260208301908038833901905050905082816000815181101515613d3257fe5b602090810290910101528051829082906001908110613d4d57fe5b6020908102909101015292915050565b6040805160038082526080820190925260609160208201838038833901905050905083816000815181101515613d8f57fe5b602090810290910101528051839082906001908110613daa57fe5b602090810290910101528051829082906002908110613dc557fe5b602090810290910101529392505050565b60008060008084516042141515613df05760019350613e50565b846041815181101515613dff57fe5b90602001015160f81c60f81b60f81c90506021850151925060418501519150601b8160ff161015613e2e57601b015b8060ff16601b14158015613e4657508060ff16601c14155b15613e5057600193505b9193509193565b60005b60208210613e7c578251845260209384019390920191601f1990910190613e5a565b50905182516020929092036101000a6000190180199091169116179052565b60008060008060005a9350858411613eb35783613eb5565b855b9250600080885160208a018b87fa9150811515613ed1576139df565b503d60208114613ee0576139df565b604051816000823e5198975050505050505050565b8154818355818111156114f1576000838152602090206114f191810190830161101691905b80821115610a4d5760008155600101613f1a56004150505f415554485f4641494c45440000000000000000000000000000000000494e49545f4e4f545f494e495449414c495a4544000000000000000000000000a165627a7a72305820874a11eb1b5a6c34530bdb9ad5c9bd0d4ff8e59d5cafd7ff03eae869d79ee7670029