Address Details
contract
0x926E88a280902Bfff5047693B9CeAfdb9F4d5095
- Contract Name
- FederatedAttestations
- Creator
- 0x456f41–3584da at 0x19a887–69ba54
- Balance
- 0 CELO ( )
- Locked CELO Balance
- 0.00 CELO
- Voting CELO Balance
- 0.00 CELO
- Pending Unlocked Gold
- 0.00 CELO
- Tokens
-
Fetching tokens...
- Transactions
- 0 Transactions
- Transfers
- 0 Transfers
- Gas Used
- Fetching gas used...
- Last Balance Update
- 18135438
This contract has been partially verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- FederatedAttestations
- Optimization enabled
- false
- Compiler version
- v0.5.13+commit.5b0b510c
- EVM Version
- istanbul
- Verified at
- 2023-01-23T13:08:28.111030Z
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/identity/FederatedAttestations.sol
pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/math/SafeMath.sol"; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "openzeppelin-solidity/contracts/utils/SafeCast.sol"; import "./interfaces/IFederatedAttestations.sol"; import "../common/interfaces/IAccounts.sol"; import "../common/interfaces/ICeloVersionedContract.sol"; import "../common/Initializable.sol"; import "../common/UsingRegistryV2.sol"; import "../common/Signatures.sol"; /** * @title Contract mapping identifiers to accounts */ contract FederatedAttestations is IFederatedAttestations, ICeloVersionedContract, Ownable, Initializable, UsingRegistryV2 { using SafeMath for uint256; using SafeCast for uint256; struct OwnershipAttestation { address account; address signer; uint64 issuedOn; uint64 publishedOn; // using uint64 to allow for extra space to add parameters } // Mappings from identifier <-> attestation are separated by issuer, // *requiring* users to specify issuers when retrieving attestations. // Maintaining bidirectional mappings (vs. in Attestations.sol) makes it possible // to perform lookups by identifier or account without indexing event data. // identifier -> issuer -> attestations mapping(bytes32 => mapping(address => OwnershipAttestation[])) public identifierToAttestations; // account -> issuer -> identifiers mapping(address => mapping(address => bytes32[])) public addressToIdentifiers; // unique attestation hash -> isRevoked mapping(bytes32 => bool) public revokedAttestations; bytes32 public eip712DomainSeparator; bytes32 public constant EIP712_OWNERSHIP_ATTESTATION_TYPEHASH = keccak256( abi.encodePacked( "OwnershipAttestation(bytes32 identifier,address issuer,", "address account,address signer,uint64 issuedOn)" ) ); // Changing any of these constraints will require re-benchmarking // and checking assumptions for batch revocation. // These can only be modified by releasing a new version of this contract. uint256 public constant MAX_ATTESTATIONS_PER_IDENTIFIER = 20; uint256 public constant MAX_IDENTIFIERS_PER_ADDRESS = 20; event EIP712DomainSeparatorSet(bytes32 eip712DomainSeparator); event AttestationRegistered( bytes32 indexed identifier, address indexed issuer, address indexed account, address signer, uint64 issuedOn, uint64 publishedOn ); event AttestationRevoked( bytes32 indexed identifier, address indexed issuer, address indexed account, address signer, uint64 issuedOn, uint64 publishedOn ); /** * @notice Sets initialized == true on implementation contracts * @param test Set to true to skip implementation initialization */ constructor(bool test) public Initializable(test) {} /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return The storage, major, minor, and patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) { return (1, 1, 0, 0); } /** * @notice Used in place of the constructor to allow the contract to be upgradable via proxy. */ function initialize() external initializer { _transferOwnership(msg.sender); setEip712DomainSeparator(); } /** * @notice Registers an attestation directly from the issuer * @param identifier Hash of the identifier to be attested * @param account Address of the account being mapped to the identifier * @param issuedOn Time at which the issuer issued the attestation in Unix time * @dev Attestation signer and issuer in storage is set to msg.sender * @dev Throws if an attestation with the same (identifier, issuer, account) already exists */ function registerAttestationAsIssuer(bytes32 identifier, address account, uint64 issuedOn) external { _registerAttestation(identifier, msg.sender, account, msg.sender, issuedOn); } /** * @notice Registers an attestation with a valid signature * @param identifier Hash of the identifier to be attested * @param issuer Address of the attestation issuer * @param account Address of the account being mapped to the identifier * @param issuedOn Time at which the issuer issued the attestation in Unix time * @param signer Address of the signer of the attestation * @param v The recovery id of the incoming ECDSA signature * @param r Output value r of the ECDSA signature * @param s Output value s of the ECDSA signature * @dev Throws if an attestation with the same (identifier, issuer, account) already exists */ function registerAttestation( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn, uint8 v, bytes32 r, bytes32 s ) external { validateAttestationSig(identifier, issuer, account, signer, issuedOn, v, r, s); _registerAttestation(identifier, issuer, account, signer, issuedOn); } /** * @notice Revokes an attestation * @param identifier Hash of the identifier to be revoked * @param issuer Address of the attestation issuer * @param account Address of the account mapped to the identifier * @dev Throws if sender is not the issuer, signer, or account */ function revokeAttestation(bytes32 identifier, address issuer, address account) external { require( account == msg.sender || // Minor gas optimization to prevent storage lookup in Accounts.sol if issuer == msg.sender issuer == msg.sender || getAccounts().attestationSignerToAccount(msg.sender) == issuer, "Sender does not have permission to revoke this attestation" ); _revokeAttestation(identifier, issuer, account); } /** * @notice Revokes attestations [identifiers <-> accounts] from issuer * @param issuer Address of the issuer of all attestations to be revoked * @param identifiers Hash of the identifiers * @param accounts Addresses of the accounts mapped to the identifiers * at the same indices * @dev Throws if the number of identifiers and accounts is not the same * @dev Throws if sender is not the issuer or currently registered signer of issuer * @dev Throws if an attestation is not found for identifiers[i] <-> accounts[i] */ function batchRevokeAttestations( address issuer, bytes32[] calldata identifiers, address[] calldata accounts ) external { require(identifiers.length == accounts.length, "Unequal number of identifiers and accounts"); require( issuer == msg.sender || getAccounts().attestationSignerToAccount(msg.sender) == issuer, "Sender does not have permission to revoke attestations from this issuer" ); for (uint256 i = 0; i < identifiers.length; i = i.add(1)) { _revokeAttestation(identifiers[i], issuer, accounts[i]); } } /** * @notice Returns info about attestations for `identifier` produced by * signers of `trustedIssuers` * @param identifier Hash of the identifier * @param trustedIssuers Array of n issuers whose attestations will be included * @return countsPerIssuer Array of number of attestations returned per issuer * For m (== sum([0])) found attestations: * @return accounts Array of m accounts * @return signers Array of m signers * @return issuedOns Array of m issuedOns * @return publishedOns Array of m publishedOns * @dev Adds attestation info to the arrays in order of provided trustedIssuers * @dev Expectation that only one attestation exists per (identifier, issuer, account) */ function lookupAttestations(bytes32 identifier, address[] calldata trustedIssuers) external view returns ( uint256[] memory countsPerIssuer, address[] memory accounts, address[] memory signers, uint64[] memory issuedOns, uint64[] memory publishedOns ) { uint256 totalAttestations; (totalAttestations, countsPerIssuer) = getNumAttestations(identifier, trustedIssuers); accounts = new address[](totalAttestations); signers = new address[](totalAttestations); issuedOns = new uint64[](totalAttestations); publishedOns = new uint64[](totalAttestations); totalAttestations = 0; OwnershipAttestation[] memory attestationsPerIssuer; for (uint256 i = 0; i < trustedIssuers.length; i = i.add(1)) { attestationsPerIssuer = identifierToAttestations[identifier][trustedIssuers[i]]; for (uint256 j = 0; j < attestationsPerIssuer.length; j = j.add(1)) { accounts[totalAttestations] = attestationsPerIssuer[j].account; signers[totalAttestations] = attestationsPerIssuer[j].signer; issuedOns[totalAttestations] = attestationsPerIssuer[j].issuedOn; publishedOns[totalAttestations] = attestationsPerIssuer[j].publishedOn; totalAttestations = totalAttestations.add(1); } } return (countsPerIssuer, accounts, signers, issuedOns, publishedOns); } /** * @notice Returns identifiers mapped to `account` by signers of `trustedIssuers` * @param account Address of the account * @param trustedIssuers Array of n issuers whose identifier mappings will be used * @return countsPerIssuer Array of number of identifiers returned per issuer * @return identifiers Array (length == sum([0])) of identifiers * @dev Adds identifier info to the arrays in order of provided trustedIssuers * @dev Expectation that only one attestation exists per (identifier, issuer, account) */ function lookupIdentifiers(address account, address[] calldata trustedIssuers) external view returns (uint256[] memory countsPerIssuer, bytes32[] memory identifiers) { uint256 totalIdentifiers; (totalIdentifiers, countsPerIssuer) = getNumIdentifiers(account, trustedIssuers); identifiers = new bytes32[](totalIdentifiers); bytes32[] memory identifiersPerIssuer; uint256 currIndex = 0; for (uint256 i = 0; i < trustedIssuers.length; i = i.add(1)) { identifiersPerIssuer = addressToIdentifiers[account][trustedIssuers[i]]; for (uint256 j = 0; j < identifiersPerIssuer.length; j = j.add(1)) { identifiers[currIndex] = identifiersPerIssuer[j]; currIndex = currIndex.add(1); } } return (countsPerIssuer, identifiers); } /** * @notice Validates the given attestation and signature * @param identifier Hash of the identifier to be attested * @param issuer Address of the attestation issuer * @param account Address of the account being mapped to the identifier * @param issuedOn Time at which the issuer issued the attestation in Unix time * @param signer Address of the signer of the attestation * @param v The recovery id of the incoming ECDSA signature * @param r Output value r of the ECDSA signature * @param s Output value s of the ECDSA signature * @dev Throws if attestation has been revoked * @dev Throws if signer is not an authorized AttestationSigner of the issuer */ function validateAttestationSig( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn, uint8 v, bytes32 r, bytes32 s ) public view { // attestationSignerToAccount instead of isSigner allows the issuer to act as its own signer require( getAccounts().attestationSignerToAccount(signer) == issuer, "Signer is not a currently authorized AttestationSigner for the issuer" ); bytes32 structHash = getUniqueAttestationHash(identifier, issuer, account, signer, issuedOn); address guessedSigner = Signatures.getSignerOfTypedDataHash( eip712DomainSeparator, structHash, v, r, s ); require(guessedSigner == signer, "Signature is invalid"); } function getUniqueAttestationHash( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn ) public pure returns (bytes32) { return keccak256( abi.encode( EIP712_OWNERSHIP_ATTESTATION_TYPEHASH, identifier, issuer, account, signer, issuedOn ) ); } /** * @notice Sets the EIP712 domain separator for the Celo FederatedAttestations abstraction. */ function setEip712DomainSeparator() internal { uint256 chainId; assembly { chainId := chainid } eip712DomainSeparator = keccak256( abi.encode( keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ), keccak256(bytes("FederatedAttestations")), keccak256("1.0"), chainId, address(this) ) ); emit EIP712DomainSeparatorSet(eip712DomainSeparator); } /** * @notice Helper function for lookupAttestations to calculate the total number of attestations completed for an identifier by each trusted issuer * @param identifier Hash of the identifier * @param trustedIssuers Array of n issuers whose attestations will be included * @return totalAttestations Sum total of attestations found * @return countsPerIssuer Array of number of attestations found per issuer */ function getNumAttestations(bytes32 identifier, address[] memory trustedIssuers) internal view returns (uint256 totalAttestations, uint256[] memory countsPerIssuer) { totalAttestations = 0; uint256 numAttestationsForIssuer; countsPerIssuer = new uint256[](trustedIssuers.length); for (uint256 i = 0; i < trustedIssuers.length; i = i.add(1)) { numAttestationsForIssuer = identifierToAttestations[identifier][trustedIssuers[i]].length; totalAttestations = totalAttestations.add(numAttestationsForIssuer); countsPerIssuer[i] = numAttestationsForIssuer; } return (totalAttestations, countsPerIssuer); } /** * @notice Helper function for lookupIdentifiers to calculate the total number of identifiers completed for an identifier by each trusted issuer * @param account Address of the account * @param trustedIssuers Array of n issuers whose identifiers will be included * @return totalIdentifiers Sum total of identifiers found * @return countsPerIssuer Array of number of identifiers found per issuer */ function getNumIdentifiers(address account, address[] memory trustedIssuers) internal view returns (uint256 totalIdentifiers, uint256[] memory countsPerIssuer) { totalIdentifiers = 0; uint256 numIdentifiersForIssuer; countsPerIssuer = new uint256[](trustedIssuers.length); for (uint256 i = 0; i < trustedIssuers.length; i = i.add(1)) { numIdentifiersForIssuer = addressToIdentifiers[account][trustedIssuers[i]].length; totalIdentifiers = totalIdentifiers.add(numIdentifiersForIssuer); countsPerIssuer[i] = numIdentifiersForIssuer; } return (totalIdentifiers, countsPerIssuer); } /** * @notice Registers an attestation * @param identifier Hash of the identifier to be attested * @param issuer Address of the attestation issuer * @param account Address of the account being mapped to the identifier * @param issuedOn Time at which the issuer issued the attestation in Unix time * @param signer Address of the signer of the attestation */ function _registerAttestation( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn ) private { require( !revokedAttestations[getUniqueAttestationHash(identifier, issuer, account, signer, issuedOn)], "Attestation has been revoked" ); uint256 numExistingAttestations = identifierToAttestations[identifier][issuer].length; require( numExistingAttestations.add(1) <= MAX_ATTESTATIONS_PER_IDENTIFIER, "Max attestations already registered for identifier" ); require( addressToIdentifiers[account][issuer].length.add(1) <= MAX_IDENTIFIERS_PER_ADDRESS, "Max identifiers already registered for account" ); for (uint256 i = 0; i < numExistingAttestations; i = i.add(1)) { // This enforces only one attestation to be uploaded // for a given set of (identifier, issuer, account) // Editing/upgrading an attestation requires that it be revoked before a new one is registered require( identifierToAttestations[identifier][issuer][i].account != account, "Attestation for this account already exists" ); } uint64 publishedOn = uint64(block.timestamp); OwnershipAttestation memory attestation = OwnershipAttestation( account, signer, issuedOn, publishedOn ); identifierToAttestations[identifier][issuer].push(attestation); addressToIdentifiers[account][issuer].push(identifier); emit AttestationRegistered(identifier, issuer, account, signer, issuedOn, publishedOn); } /** * @notice Revokes an attestation: * helper function for revokeAttestation and batchRevokeAttestations * @param identifier Hash of the identifier to be revoked * @param issuer Address of the attestation issuer * @param account Address of the account mapped to the identifier * @dev Reverts if attestation is not found mapping identifier <-> account */ function _revokeAttestation(bytes32 identifier, address issuer, address account) private { OwnershipAttestation[] storage attestations = identifierToAttestations[identifier][issuer]; uint256 lenAttestations = attestations.length; for (uint256 i = 0; i < lenAttestations; i = i.add(1)) { if (attestations[i].account != account) { continue; } OwnershipAttestation memory attestation = attestations[i]; // This is meant to delete the attestations in the array // and then move the last element in the array to that empty spot, // to avoid having empty elements in the array if (i != lenAttestations - 1) { attestations[i] = attestations[lenAttestations - 1]; } attestations.pop(); bool deletedIdentifier = false; bytes32[] storage identifiers = addressToIdentifiers[account][issuer]; uint256 lenIdentifiers = identifiers.length; for (uint256 j = 0; j < lenIdentifiers; j = j.add(1)) { if (identifiers[j] != identifier) { continue; } if (j != lenIdentifiers - 1) { identifiers[j] = identifiers[lenIdentifiers - 1]; } identifiers.pop(); deletedIdentifier = true; break; } // Should never be false - both mappings should always be updated in unison assert(deletedIdentifier); bytes32 attestationHash = getUniqueAttestationHash( identifier, issuer, account, attestation.signer, attestation.issuedOn ); revokedAttestations[attestationHash] = true; emit AttestationRevoked( identifier, issuer, account, attestation.signer, attestation.issuedOn, attestation.publishedOn ); return; } revert("Attestation to be revoked does not exist"); } }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/Initializable.sol
pragma solidity ^0.5.13; contract Initializable { bool public initialized; constructor(bool testingDeployment) public { if (!testingDeployment) { initialized = true; } } modifier initializer() { require(!initialized, "contract already initialized"); initialized = true; _; } }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/Signatures.sol
pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol"; library Signatures { /** * @notice Given a signed address, returns the signer of the address. * @param message The address that was signed. * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfAddress(address message, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { bytes32 hash = keccak256(abi.encodePacked(message)); return getSignerOfMessageHash(hash, v, r, s); } /** * @notice Given a message hash, returns the signer of the address. * @param messageHash The hash of a message. * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfMessageHash(bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (address) { bytes memory signature = new bytes(65); // Concatenate (r, s, v) into signature. assembly { mstore(add(signature, 32), r) mstore(add(signature, 64), s) mstore8(add(signature, 96), v) } bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(messageHash); return ECDSA.recover(prefixedHash, signature); } /** * @notice Given a domain separator and a structHash, construct the typed data hash * @param eip712DomainSeparator Context specific domain separator * @param structHash hash of the typed data struct * @return The EIP712 typed data hash */ function toEthSignedTypedDataHash(bytes32 eip712DomainSeparator, bytes32 structHash) public pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", eip712DomainSeparator, structHash)); } /** * @notice Given a domain separator and a structHash and a signature return the signer * @param eip712DomainSeparator Context specific domain separator * @param structHash hash of the typed data struct * @param v The recovery id of the incoming ECDSA signature. * @param r Output value r of the ECDSA signature. * @param s Output value s of the ECDSA signature. */ function getSignerOfTypedDataHash( bytes32 eip712DomainSeparator, bytes32 structHash, uint8 v, bytes32 r, bytes32 s ) public pure returns (address) { bytes memory signature = new bytes(65); // Concatenate (r, s, v) into signature. assembly { mstore(add(signature, 32), r) mstore(add(signature, 64), s) mstore8(add(signature, 96), v) } bytes32 prefixedHash = toEthSignedTypedDataHash(eip712DomainSeparator, structHash); return ECDSA.recover(prefixedHash, signature); } }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/UsingRegistryV2.sol
pragma solidity ^0.5.13; import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; import "./interfaces/IAccounts.sol"; import "./interfaces/IFeeCurrencyWhitelist.sol"; import "./interfaces/IFreezer.sol"; import "./interfaces/IRegistry.sol"; import "../governance/interfaces/IElection.sol"; import "../governance/interfaces/IGovernance.sol"; import "../governance/interfaces/ILockedGold.sol"; import "../governance/interfaces/IValidators.sol"; import "../identity/interfaces/IRandom.sol"; import "../identity/interfaces/IAttestations.sol"; import "../identity/interfaces/IFederatedAttestations.sol"; import "../stability/interfaces/IExchange.sol"; import "../stability/interfaces/IReserve.sol"; import "../stability/interfaces/ISortedOracles.sol"; import "../stability/interfaces/IStableToken.sol"; contract UsingRegistryV2 { address internal constant registryAddress = 0x000000000000000000000000000000000000ce10; IRegistry public constant registryContract = IRegistry(registryAddress); bytes32 internal constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts")); bytes32 internal constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations")); bytes32 internal constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256( abi.encodePacked("DowntimeSlasher") ); bytes32 internal constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256( abi.encodePacked("DoubleSigningSlasher") ); bytes32 internal constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election")); bytes32 internal constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange")); bytes32 internal constant EXCHANGE_EURO_REGISTRY_ID = keccak256(abi.encodePacked("ExchangeEUR")); bytes32 internal constant EXCHANGE_REAL_REGISTRY_ID = keccak256(abi.encodePacked("ExchangeBRL")); bytes32 internal constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256( abi.encodePacked("FeeCurrencyWhitelist") ); bytes32 internal constant FEDERATED_ATTESTATIONS_REGISTRY_ID = keccak256( abi.encodePacked("FederatedAttestations") ); bytes32 internal constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer")); bytes32 internal constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken")); bytes32 internal constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance")); bytes32 internal constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256( abi.encodePacked("GovernanceSlasher") ); bytes32 internal constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold")); bytes32 internal constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve")); bytes32 internal constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random")); bytes32 internal constant SORTED_ORACLES_REGISTRY_ID = keccak256( abi.encodePacked("SortedOracles") ); bytes32 internal constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken")); bytes32 internal constant STABLE_EURO_TOKEN_REGISTRY_ID = keccak256( abi.encodePacked("StableTokenEUR") ); bytes32 internal constant STABLE_REAL_TOKEN_REGISTRY_ID = keccak256( abi.encodePacked("StableTokenBRL") ); bytes32 internal constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators")); modifier onlyRegisteredContract(bytes32 identifierHash) { require( registryContract.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract" ); _; } modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) { require(registryContract.isOneOf(identifierHashes, msg.sender), "only registered contracts"); _; } function getAccounts() internal view returns (IAccounts) { return IAccounts(registryContract.getAddressForOrDie(ACCOUNTS_REGISTRY_ID)); } function getAttestations() internal view returns (IAttestations) { return IAttestations(registryContract.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID)); } function getElection() internal view returns (IElection) { return IElection(registryContract.getAddressForOrDie(ELECTION_REGISTRY_ID)); } function getExchange() internal view returns (IExchange) { return IExchange(registryContract.getAddressForOrDie(EXCHANGE_REGISTRY_ID)); } function getExchangeDollar() internal view returns (IExchange) { return getExchange(); } function getExchangeEuro() internal view returns (IExchange) { return IExchange(registryContract.getAddressForOrDie(EXCHANGE_EURO_REGISTRY_ID)); } function getExchangeREAL() internal view returns (IExchange) { return IExchange(registryContract.getAddressForOrDie(EXCHANGE_REAL_REGISTRY_ID)); } function getFeeCurrencyWhitelistRegistry() internal view returns (IFeeCurrencyWhitelist) { return IFeeCurrencyWhitelist( registryContract.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID) ); } function getFederatedAttestations() internal view returns (IFederatedAttestations) { return IFederatedAttestations( registryContract.getAddressForOrDie(FEDERATED_ATTESTATIONS_REGISTRY_ID) ); } function getFreezer() internal view returns (IFreezer) { return IFreezer(registryContract.getAddressForOrDie(FREEZER_REGISTRY_ID)); } function getGoldToken() internal view returns (IERC20) { return IERC20(registryContract.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)); } function getGovernance() internal view returns (IGovernance) { return IGovernance(registryContract.getAddressForOrDie(GOVERNANCE_REGISTRY_ID)); } function getLockedGold() internal view returns (ILockedGold) { return ILockedGold(registryContract.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID)); } function getRandom() internal view returns (IRandom) { return IRandom(registryContract.getAddressForOrDie(RANDOM_REGISTRY_ID)); } function getReserve() internal view returns (IReserve) { return IReserve(registryContract.getAddressForOrDie(RESERVE_REGISTRY_ID)); } function getSortedOracles() internal view returns (ISortedOracles) { return ISortedOracles(registryContract.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID)); } function getStableToken() internal view returns (IStableToken) { return IStableToken(registryContract.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID)); } function getStableDollarToken() internal view returns (IStableToken) { return getStableToken(); } function getStableEuroToken() internal view returns (IStableToken) { return IStableToken(registryContract.getAddressForOrDie(STABLE_EURO_TOKEN_REGISTRY_ID)); } function getStableRealToken() internal view returns (IStableToken) { return IStableToken(registryContract.getAddressForOrDie(STABLE_REAL_TOKEN_REGISTRY_ID)); } function getValidators() internal view returns (IValidators) { return IValidators(registryContract.getAddressForOrDie(VALIDATORS_REGISTRY_ID)); } }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/interfaces/IAccounts.sol
pragma solidity ^0.5.13; interface IAccounts { function isAccount(address) external view returns (bool); function voteSignerToAccount(address) external view returns (address); function validatorSignerToAccount(address) external view returns (address); function attestationSignerToAccount(address) external view returns (address); function signerToAccount(address) external view returns (address); function getAttestationSigner(address) external view returns (address); function getValidatorSigner(address) external view returns (address); function getVoteSigner(address) external view returns (address); function hasAuthorizedVoteSigner(address) external view returns (bool); function hasAuthorizedValidatorSigner(address) external view returns (bool); function hasAuthorizedAttestationSigner(address) external view returns (bool); function setAccountDataEncryptionKey(bytes calldata) external; function setMetadataURL(string calldata) external; function setName(string calldata) external; function setWalletAddress(address, uint8, bytes32, bytes32) external; function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external; function getDataEncryptionKey(address) external view returns (bytes memory); function getWalletAddress(address) external view returns (address); function getMetadataURL(address) external view returns (string memory); function batchGetMetadataURL(address[] calldata) external view returns (uint256[] memory, bytes memory); function getName(address) external view returns (string memory); function authorizeVoteSigner(address, uint8, bytes32, bytes32) external; function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external; function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata) external; function authorizeValidatorSignerWithKeys( address, uint8, bytes32, bytes32, bytes calldata, bytes calldata, bytes calldata ) external; function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external; function createAccount() external returns (bool); function setPaymentDelegation(address, uint256) external; function getPaymentDelegation(address) external view returns (address, uint256); function isSigner(address, address, bytes32) external view returns (bool); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/interfaces/ICeloVersionedContract.sol
pragma solidity ^0.5.13; interface ICeloVersionedContract { /** * @notice Returns the storage, major, minor, and patch version of the contract. * @return Storage version of the contract. * @return Major version of the contract. * @return Minor version of the contract. * @return Patch version of the contract. */ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/interfaces/IFeeCurrencyWhitelist.sol
pragma solidity ^0.5.13; interface IFeeCurrencyWhitelist { function addToken(address) external; function getWhitelist() external view returns (address[] memory); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/interfaces/IFreezer.sol
pragma solidity ^0.5.13; interface IFreezer { function isFrozen(address) external view returns (bool); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/common/interfaces/IRegistry.sol
pragma solidity ^0.5.13; interface IRegistry { function setAddressFor(string calldata, address) external; function getAddressForOrDie(bytes32) external view returns (address); function getAddressFor(bytes32) external view returns (address); function getAddressForStringOrDie(string calldata identifier) external view returns (address); function getAddressForString(string calldata identifier) external view returns (address); function isOneOf(bytes32[] calldata, address) external view returns (bool); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/governance/interfaces/IElection.sol
pragma solidity ^0.5.13; interface IElection { function electValidatorSigners() external view returns (address[] memory); function electNValidatorSigners(uint256, uint256) external view returns (address[] memory); function vote(address, uint256, address, address) external returns (bool); function activate(address) external returns (bool); function revokeActive(address, uint256, address, address, uint256) external returns (bool); function revokeAllActive(address, address, address, uint256) external returns (bool); function revokePending(address, uint256, address, address, uint256) external returns (bool); function markGroupIneligible(address) external; function markGroupEligible(address, address, address) external; function forceDecrementVotes( address, uint256, address[] calldata, address[] calldata, uint256[] calldata ) external returns (uint256); // view functions function getElectableValidators() external view returns (uint256, uint256); function getElectabilityThreshold() external view returns (uint256); function getNumVotesReceivable(address) external view returns (uint256); function getTotalVotes() external view returns (uint256); function getActiveVotes() external view returns (uint256); function getTotalVotesByAccount(address) external view returns (uint256); function getPendingVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVotesForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroupByAccount(address, address) external view returns (uint256); function getActiveVoteUnitsForGroupByAccount(address, address) external view returns (uint256); function getTotalVotesForGroup(address) external view returns (uint256); function getActiveVotesForGroup(address) external view returns (uint256); function getPendingVotesForGroup(address) external view returns (uint256); function getGroupEligibility(address) external view returns (bool); function getGroupEpochRewards(address, uint256, uint256[] calldata) external view returns (uint256); function getGroupsVotedForByAccount(address) external view returns (address[] memory); function getEligibleValidatorGroups() external view returns (address[] memory); function getTotalVotesForEligibleValidatorGroups() external view returns (address[] memory, uint256[] memory); function getCurrentValidatorSigners() external view returns (address[] memory); function canReceiveVotes(address, uint256) external view returns (bool); function hasActivatablePendingVotes(address, address) external view returns (bool); // only owner function setElectableValidators(uint256, uint256) external returns (bool); function setMaxNumGroupsVotedFor(uint256) external returns (bool); function setElectabilityThreshold(uint256) external returns (bool); // only VM function distributeEpochRewards(address, uint256, address, address) external; }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/governance/interfaces/IGovernance.sol
pragma solidity ^0.5.13; interface IGovernance { function isVoting(address) external view returns (bool); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/governance/interfaces/ILockedGold.sol
pragma solidity ^0.5.13; interface ILockedGold { function incrementNonvotingAccountBalance(address, uint256) external; function decrementNonvotingAccountBalance(address, uint256) external; function getAccountTotalLockedGold(address) external view returns (uint256); function getTotalLockedGold() external view returns (uint256); function getPendingWithdrawals(address) external view returns (uint256[] memory, uint256[] memory); function getTotalPendingWithdrawals(address) external view returns (uint256); function lock() external payable; function unlock(uint256) external; function relock(uint256, uint256) external; function withdraw(uint256) external; function slash( address account, uint256 penalty, address reporter, uint256 reward, address[] calldata lessers, address[] calldata greaters, uint256[] calldata indices ) external; function isSlasher(address) external view returns (bool); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/governance/interfaces/IValidators.sol
pragma solidity ^0.5.13; interface IValidators { function registerValidator(bytes calldata, bytes calldata, bytes calldata) external returns (bool); function deregisterValidator(uint256) external returns (bool); function affiliate(address) external returns (bool); function deaffiliate() external returns (bool); function updateBlsPublicKey(bytes calldata, bytes calldata) external returns (bool); function registerValidatorGroup(uint256) external returns (bool); function deregisterValidatorGroup(uint256) external returns (bool); function addMember(address) external returns (bool); function addFirstMember(address, address, address) external returns (bool); function removeMember(address) external returns (bool); function reorderMember(address, address, address) external returns (bool); function updateCommission() external; function setNextCommissionUpdate(uint256) external; function resetSlashingMultiplier() external; // only owner function setCommissionUpdateDelay(uint256) external; function setMaxGroupSize(uint256) external returns (bool); function setMembershipHistoryLength(uint256) external returns (bool); function setValidatorScoreParameters(uint256, uint256) external returns (bool); function setGroupLockedGoldRequirements(uint256, uint256) external returns (bool); function setValidatorLockedGoldRequirements(uint256, uint256) external returns (bool); function setSlashingMultiplierResetPeriod(uint256) external; // view functions function getMaxGroupSize() external view returns (uint256); function getCommissionUpdateDelay() external view returns (uint256); function getValidatorScoreParameters() external view returns (uint256, uint256); function getMembershipHistory(address) external view returns (uint256[] memory, address[] memory, uint256, uint256); function calculateEpochScore(uint256) external view returns (uint256); function calculateGroupEpochScore(uint256[] calldata) external view returns (uint256); function getAccountLockedGoldRequirement(address) external view returns (uint256); function meetsAccountLockedGoldRequirements(address) external view returns (bool); function getValidatorBlsPublicKeyFromSigner(address) external view returns (bytes memory); function getValidator(address account) external view returns (bytes memory, bytes memory, address, uint256, address); function getValidatorGroup(address) external view returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256); function getGroupNumMembers(address) external view returns (uint256); function getTopGroupValidators(address, uint256) external view returns (address[] memory); function getGroupsNumMembers(address[] calldata accounts) external view returns (uint256[] memory); function getNumRegisteredValidators() external view returns (uint256); function groupMembershipInEpoch(address, uint256, uint256) external view returns (address); // only registered contract function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool); function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata) external returns (bool); function getValidatorLockedGoldRequirements() external view returns (uint256, uint256); function getGroupLockedGoldRequirements() external view returns (uint256, uint256); function getRegisteredValidators() external view returns (address[] memory); function getRegisteredValidatorSigners() external view returns (address[] memory); function getRegisteredValidatorGroups() external view returns (address[] memory); function isValidatorGroup(address) external view returns (bool); function isValidator(address) external view returns (bool); function getValidatorGroupSlashingMultiplier(address) external view returns (uint256); function getMembershipInLastEpoch(address) external view returns (address); function getMembershipInLastEpochFromSigner(address) external view returns (address); // only VM function updateValidatorScoreFromSigner(address, uint256) external; function distributeEpochPaymentsFromSigner(address, uint256) external returns (uint256); // only slasher function forceDeaffiliateIfValidator(address) external; function halveSlashingMultiplier(address) external; }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/identity/interfaces/IAttestations.sol
pragma solidity ^0.5.13; interface IAttestations { function request(bytes32, uint256, address) external; function selectIssuers(bytes32) external; function complete(bytes32, uint8, bytes32, bytes32) external; function revoke(bytes32, uint256) external; function withdraw(address) external; function approveTransfer(bytes32, uint256, address, address, bool) external; // view functions function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address); function getAttestationIssuers(bytes32, address) external view returns (address[] memory); function getAttestationStats(bytes32, address) external view returns (uint32, uint32); function batchGetAttestationStats(bytes32[] calldata) external view returns (uint256[] memory, address[] memory, uint64[] memory, uint64[] memory); function getAttestationState(bytes32, address, address) external view returns (uint8, uint32, address); function getCompletableAttestations(bytes32, address) external view returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory); function getAttestationRequestFee(address) external view returns (uint256); function getMaxAttestations() external view returns (uint256); function validateAttestationCode(bytes32, address, uint8, bytes32, bytes32) external view returns (address); function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory); function requireNAttestationsRequested(bytes32, address, uint32) external view; // only owner function setAttestationRequestFee(address, uint256) external; function setAttestationExpiryBlocks(uint256) external; function setSelectIssuersWaitBlocks(uint256) external; function setMaxAttestations(uint256) external; }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/identity/interfaces/IFederatedAttestations.sol
pragma solidity ^0.5.13; interface IFederatedAttestations { function registerAttestationAsIssuer(bytes32 identifier, address account, uint64 issuedOn) external; function registerAttestation( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn, uint8 v, bytes32 r, bytes32 s ) external; function revokeAttestation(bytes32 identifier, address issuer, address account) external; function batchRevokeAttestations( address issuer, bytes32[] calldata identifiers, address[] calldata accounts ) external; // view functions function lookupAttestations(bytes32 identifier, address[] calldata trustedIssuers) external view returns ( uint256[] memory, address[] memory, address[] memory, uint64[] memory, uint64[] memory ); function lookupIdentifiers(address account, address[] calldata trustedIssuers) external view returns (uint256[] memory, bytes32[] memory); function validateAttestationSig( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn, uint8 v, bytes32 r, bytes32 s ) external view; function getUniqueAttestationHash( bytes32 identifier, address issuer, address account, address signer, uint64 issuedOn ) external pure returns (bytes32); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/identity/interfaces/IRandom.sol
pragma solidity ^0.5.13; interface IRandom { function revealAndCommit(bytes32, bytes32, address) external; function randomnessBlockRetentionWindow() external view returns (uint256); function random() external view returns (bytes32); function getBlockRandomness(uint256) external view returns (bytes32); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/stability/interfaces/IExchange.sol
pragma solidity ^0.5.13; interface IExchange { function buy(uint256, uint256, bool) external returns (uint256); function sell(uint256, uint256, bool) external returns (uint256); function exchange(uint256, uint256, bool) external returns (uint256); function setUpdateFrequency(uint256) external; function getBuyTokenAmount(uint256, bool) external view returns (uint256); function getSellTokenAmount(uint256, bool) external view returns (uint256); function getBuyAndSellBuckets(bool) external view returns (uint256, uint256); function getStableBucketCap() external view returns (uint256); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/stability/interfaces/IReserve.sol
pragma solidity ^0.5.13; interface IReserve { function setTobinTaxStalenessThreshold(uint256) external; function addToken(address) external returns (bool); function removeToken(address, uint256) external returns (bool); function transferGold(address payable, uint256) external returns (bool); function transferExchangeGold(address payable, uint256) external returns (bool); function getReserveGoldBalance() external view returns (uint256); function getUnfrozenReserveGoldBalance() external view returns (uint256); function getOrComputeTobinTax() external returns (uint256, uint256); function getTokens() external view returns (address[] memory); function getReserveRatio() external view returns (uint256); function addExchangeSpender(address) external; function removeExchangeSpender(address, uint256) external; function addSpender(address) external; function removeSpender(address) external; }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/stability/interfaces/ISortedOracles.sol
pragma solidity ^0.5.13; interface ISortedOracles { function addOracle(address, address) external; function removeOracle(address, address, uint256) external; function report(address, uint256, address, address) external; function removeExpiredReports(address, uint256) external; function isOldestReportExpired(address token) external view returns (bool, address); function numRates(address) external view returns (uint256); function medianRate(address) external view returns (uint256, uint256); function numTimestamps(address) external view returns (uint256); function medianTimestamp(address) external view returns (uint256); }
/Users/carter/git/clabs/celo-monorepo/packages/protocol/contracts/stability/interfaces/IStableToken.sol
pragma solidity ^0.5.13; /** * @title This interface describes the functions specific to Celo Stable Tokens, and in the * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol. */ interface IStableToken { function mint(address, uint256) external returns (bool); function burn(uint256) external returns (bool); function setInflationParameters(uint256, uint256) external; function valueToUnits(uint256) external view returns (uint256); function unitsToValue(uint256) external view returns (uint256); function getInflationParameters() external view returns (uint256, uint256, uint256, uint256); // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported. function balanceOf(address) external view returns (uint256); }
/openzeppelin-solidity/contracts/GSN/Context.sol
pragma solidity ^0.5.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ contract Context { // Empty internal constructor, to prevent people from mistakenly deploying // an instance of this contract, which should be used via inheritance. constructor () internal { } // solhint-disable-previous-line no-empty-blocks function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
/openzeppelin-solidity/contracts/cryptography/ECDSA.sol
pragma solidity ^0.5.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * NOTE: This call _does not revert_ if the signature is invalid, or * if the signer is otherwise unable to be retrieved. In those scenarios, * the zero address is returned. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { return (address(0)); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return address(0); } if (v != 27 && v != 28) { return address(0); } // If the signature is valid (and not malleable), return the signer address return ecrecover(hash, v, r, s); } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
/openzeppelin-solidity/contracts/math/SafeMath.sol
pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. * * _Available since v2.4.0._ */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. * * _Available since v2.4.0._ */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
/openzeppelin-solidity/contracts/ownership/Ownable.sol
pragma solidity ^0.5.0; import "../GSN/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } /** * @dev Returns true if the caller is the current owner. */ function isOwner() public view returns (bool) { return _msgSender() == _owner; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). */ function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
/openzeppelin-solidity/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.5.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. Does not include * the optional functions; to access them see {ERC20Detailed}. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
/openzeppelin-solidity/contracts/utils/SafeCast.sol
pragma solidity ^0.5.0; /** * @dev Wrappers over Solidity's uintXX casting operators with added overflow * checks. * * Downcasting from uint256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} to extend it to smaller types, by performing * all math on `uint256` and then downcasting. * * _Available since v2.5.0._ */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); return uint8(value); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"bool","name":"test","internalType":"bool"}]},{"type":"event","name":"AttestationRegistered","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32","indexed":true},{"type":"address","name":"issuer","internalType":"address","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"signer","internalType":"address","indexed":false},{"type":"uint64","name":"issuedOn","internalType":"uint64","indexed":false},{"type":"uint64","name":"publishedOn","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"AttestationRevoked","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32","indexed":true},{"type":"address","name":"issuer","internalType":"address","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"signer","internalType":"address","indexed":false},{"type":"uint64","name":"issuedOn","internalType":"uint64","indexed":false},{"type":"uint64","name":"publishedOn","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"EIP712DomainSeparatorSet","inputs":[{"type":"bytes32","name":"eip712DomainSeparator","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"EIP712_OWNERSHIP_ATTESTATION_TYPEHASH","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_ATTESTATIONS_PER_IDENTIFIER","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_IDENTIFIERS_PER_ADDRESS","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"addressToIdentifiers","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"batchRevokeAttestations","inputs":[{"type":"address","name":"issuer","internalType":"address"},{"type":"bytes32[]","name":"identifiers","internalType":"bytes32[]"},{"type":"address[]","name":"accounts","internalType":"address[]"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"eip712DomainSeparator","inputs":[],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getUniqueAttestationHash","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address","name":"issuer","internalType":"address"},{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"signer","internalType":"address"},{"type":"uint64","name":"issuedOn","internalType":"uint64"}],"constant":true},{"type":"function","stateMutability":"pure","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getVersionNumber","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"signer","internalType":"address"},{"type":"uint64","name":"issuedOn","internalType":"uint64"},{"type":"uint64","name":"publishedOn","internalType":"uint64"}],"name":"identifierToAttestations","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"countsPerIssuer","internalType":"uint256[]"},{"type":"address[]","name":"accounts","internalType":"address[]"},{"type":"address[]","name":"signers","internalType":"address[]"},{"type":"uint64[]","name":"issuedOns","internalType":"uint64[]"},{"type":"uint64[]","name":"publishedOns","internalType":"uint64[]"}],"name":"lookupAttestations","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address[]","name":"trustedIssuers","internalType":"address[]"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"countsPerIssuer","internalType":"uint256[]"},{"type":"bytes32[]","name":"identifiers","internalType":"bytes32[]"}],"name":"lookupIdentifiers","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"address[]","name":"trustedIssuers","internalType":"address[]"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"registerAttestation","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address","name":"issuer","internalType":"address"},{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"signer","internalType":"address"},{"type":"uint64","name":"issuedOn","internalType":"uint64"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"registerAttestationAsIssuer","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"},{"type":"uint64","name":"issuedOn","internalType":"uint64"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract IRegistry"}],"name":"registryContract","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"revokeAttestation","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address","name":"issuer","internalType":"address"},{"type":"address","name":"account","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"revokedAttestations","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[],"name":"validateAttestationSig","inputs":[{"type":"bytes32","name":"identifier","internalType":"bytes32"},{"type":"address","name":"issuer","internalType":"address"},{"type":"address","name":"account","internalType":"address"},{"type":"address","name":"signer","internalType":"address"},{"type":"uint64","name":"issuedOn","internalType":"uint64"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}],"constant":true}]
Contract Creation Code
0x60806040523480156200001157600080fd5b506040516200389e3803806200389e833981810160405260208110156200003757600080fd5b81019080805190602001909291905050508060006200005b6200012360201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a350806200011b576001600060146101000a81548160ff0219169083151502179055505b50506200012b565b600033905090565b613763806200013b6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80638129fc1c116100c3578063b4b773421161007c578063b4b7734214610889578063b71aae46146108a7578063cba33ce01461096b578063e27ff311146109ed578063e3a1b7c614610adb578063f2fde38b14610bdc5761014d565b80638129fc1c146105395780638da5cb5b146105435780638f32d59b1461058d57806394b09057146105af5780639b43e48014610673578063a862e12e146106915761014d565b80635b07fdd8116101155780635b07fdd8146103155780635fa2fc30146103335780636125a6c214610379578063715018a6146104af57806373dfde98146104b95780637e68298d1461051b5761014d565b80630ab3ddc6146101525780631100b32414610208578063158ef93e1461027657806328c1f99b1461029857806354255be0146102e2575b600080fd5b6101f2600480360360a081101561016857600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190505050610c20565b6040518082815260200191505060405180910390f35b6102746004803603606081101561021e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d48565b005b61027e610f06565b604051808215151515815260200191505060405180910390f35b6102a0610f19565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102ea610f1f565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b61031d610f45565b6040518082815260200191505060405180910390f35b61035f6004803603602081101561034957600080fd5b8101908080359060200190929190505050610f4b565b604051808215151515815260200191505060405180910390f35b6104106004803603604081101561038f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156103cc57600080fd5b8201836020820111156103de57600080fd5b8035906020019184602083028401116401000000008311171561040057600080fd5b9091929391929390505050610f6b565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561045757808201518184015260208101905061043c565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561049957808201518184015260208101905061047e565b5050505090500194505050505060405180910390f35b6104b761119c565b005b610519600480360360608110156104cf57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff1690602001909291905050506112d5565b005b6105236112e7565b6040518082815260200191505060405180910390f35b61054161131f565b005b61054b6113d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105956113f9565b604051808215151515815260200191505060405180910390f35b61067160048036036101008110156105c657600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050611457565b005b61067b61170d565b6040518082815260200191505060405180910390f35b610712600480360360408110156106a757600080fd5b8101908080359060200190929190803590602001906401000000008111156106ce57600080fd5b8201836020820111156106e057600080fd5b8035906020019184602083028401116401000000008311171561070257600080fd5b9091929391929390505050611712565b60405180806020018060200180602001806020018060200186810386528b818151815260200191508051906020019060200280838360005b8381101561076557808201518184015260208101905061074a565b5050505090500186810385528a818151815260200191508051906020019060200280838360005b838110156107a757808201518184015260208101905061078c565b50505050905001868103845289818151815260200191508051906020019060200280838360005b838110156107e95780820151818401526020810190506107ce565b50505050905001868103835288818151815260200191508051906020019060200280838360005b8381101561082b578082015181840152602081019050610810565b50505050905001868103825287818151815260200191508051906020019060200280838360005b8381101561086d578082015181840152602081019050610852565b505050509050019a505050505050505050505060405180910390f35b610891611bef565b6040518082815260200191505060405180910390f35b61096960048036036101008110156108be57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050611bf4565b005b6109d76004803603606081101561098157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611c1b565b6040518082815260200191505060405180910390f35b610ad960048036036060811015610a0357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610a4057600080fd5b820183602082011115610a5257600080fd5b80359060200191846020830284011164010000000083111715610a7457600080fd5b909192939192939080359060200190640100000000811115610a9557600080fd5b820183602082011115610aa757600080fd5b80359060200191846020830284011164010000000083111715610ac957600080fd5b9091929391929390505050611c56565b005b610b3160048036036060811015610af157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611ea5565b604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff16815260200194505050505060405180910390f35b610c1e60048036036020811015610bf257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611f64565b005b600060405160200180806136be6037913960370180613572602f9139602f019050604051602081830303815290604052805190602001208686868686604051602001808781526020018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001965050505050505060405160208183030381529060405280519060200120905095945050505050565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610dad57503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b80610ea157508173ffffffffffffffffffffffffffffffffffffffff16610dd2611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610e4e57600080fd5b505afa158015610e62573d6000803e3d6000fd5b505050506040513d6020811015610e7857600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b610ef6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001806136f5603a913960400191505060405180910390fd5b610f018383836120c5565b505050565b600060149054906101000a900460ff1681565b61ce1081565b600080600080600180600080839350829250819150809050935093509350935090919293565b60045481565b60036020528060005260406000206000915054906101000a900460ff1681565b6060806000610fbb86868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050612807565b809450819250505080604051908082528060200260200182016040528015610ff25781602001602082028038833980820191505090505b5091506060600080905060008090505b8787905081101561118a57600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600089898481811061105a57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156110fb57602002820191906000526020600020905b8154815260200190600101908083116110e7575b5050505050925060008090505b835181101561116e5783818151811061111d57fe5b602002602001015186848151811061113157fe5b60200260200101818152505061115160018461294090919063ffffffff16565b925061116760018261294090919063ffffffff16565b9050611108565b5061118360018261294090919063ffffffff16565b9050611002565b50848494509450505050935093915050565b6111a46113f9565b611216576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6112e283338433856129c8565b505050565b60405160200180806136be6037913960370180613572602f9139602f0190506040516020818303038152906040528051906020012081565b600060149054906101000a900460ff16156113a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff0219169083151502179055506113c6336130a9565b6113ce6131ed565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661143b613330565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b8673ffffffffffffffffffffffffffffffffffffffff16611476611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156114f257600080fd5b505afa158015611506573d6000803e3d6000fd5b505050506040513d602081101561151c57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611599576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260458152602001806134ae6045913960600191505060405180910390fd5b60006115a88989898989610c20565b90506000731578b071de10e587f49db5934a24ca830fddde196334d1a233600454848888886040518663ffffffff1660e01b8152600401808681526020018581526020018460ff1660ff1681526020018381526020018281526020019550505050505060206040518083038186803b15801561162357600080fd5b505af4158015611637573d6000803e3d6000fd5b505050506040513d602081101561164d57600080fd5b810190808051906020019092919050505090508673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611701576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e617475726520697320696e76616c696400000000000000000000000081525060200191505060405180910390fd5b50505050505050505050565b601481565b6060806060806060600061176789898980806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050613338565b80975081925050508060405190808252806020026020018201604052801561179e5781602001602082028038833980820191505090505b509450806040519080825280602002602001820160405280156117d05781602001602082028038833980820191505090505b509350806040519080825280602002602001820160405280156118025781602001602082028038833980820191505090505b509250806040519080825280602002602001820160405280156118345781602001602082028038833980820191505090505b50915060009050606060008090505b89899050811015611bd257600160008c815260200190815260200160002060008b8b8481811061186f57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611a2857838290600052602060002090600302016040518060800160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016002820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681525050815260200190600101906118e6565b50505050915060008090505b8251811015611bb657828181518110611a4957fe5b602002602001015160000151888581518110611a6157fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110611aa757fe5b602002602001015160200151878581518110611abf57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110611b0557fe5b602002602001015160400151868581518110611b1d57fe5b602002602001019067ffffffffffffffff16908167ffffffffffffffff1681525050828181518110611b4b57fe5b602002602001015160600151858581518110611b6357fe5b602002602001019067ffffffffffffffff16908167ffffffffffffffff1681525050611b9960018561294090919063ffffffff16565b9350611baf60018261294090919063ffffffff16565b9050611a34565b50611bcb60018261294090919063ffffffff16565b9050611843565b508686868686965096509650965096505050939792965093509350565b601481565b611c048888888888888888611457565b611c1188888888886129c8565b5050505050505050565b60026020528260005260406000206020528160005260406000208181548110611c4057fe5b9060005260206000200160009250925050505481565b818190508484905014611cb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180613625602a913960400191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611dd757508473ffffffffffffffffffffffffffffffffffffffff16611d08611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611d8457600080fd5b505afa158015611d98573d6000803e3d6000fd5b505050506040513d6020811015611dae57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b611e2c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260478152602001806136776047913960600191505060405180910390fd5b60008090505b84849050811015611e9d57611e82858583818110611e4c57fe5b9050602002013587858585818110611e6057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166120c5565b611e9660018261294090919063ffffffff16565b9050611e32565b505050505050565b60016020528260005260406000206020528160005260406000208181548110611eca57fe5b906000526020600020906003020160009250925050508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160149054906101000a900467ffffffffffffffff16908060020160009054906101000a900467ffffffffffffffff16905084565b611f6c6113f9565b611fde576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b611fe7816130a9565b50565b600061ce1073ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561208557600080fd5b505afa158015612099573d6000803e3d6000fd5b505050506040513d60208110156120af57600080fd5b8101908080519060200190929190505050905090565b60006001600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008180549050905060008090505b818110156127b0578373ffffffffffffffffffffffffffffffffffffffff1683828154811061215357fe5b906000526020600020906003020160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146121a557612795565b6121ad613445565b8382815481106121b957fe5b90600052602060002090600302016040518060800160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016002820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681525050905060018303821461247d578360018403815481106122fd57fe5b906000526020600020906003020184838154811061231757fe5b90600052602060002090600302016000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001820160149054906101000a900467ffffffffffffffff168160010160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506002820160009054906101000a900467ffffffffffffffff168160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050505b8380548061248757fe5b6001900381819060005260206000209060030201600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160146101000a81549067ffffffffffffffff02191690556002820160006101000a81549067ffffffffffffffff02191690555050905560008090506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008180549050905060008090505b81811015612665578a8382815481106125cd57fe5b9060005260206000200154146125e25761264a565b600182038114612621578260018303815481106125fb57fe5b906000526020600020015483828154811061261257fe5b90600052602060002001819055505b8280548061262b57fe5b6001900381819060005260206000200160009055905560019350612665565b61265e60018261294090919063ffffffff16565b90506125b8565b508261266d57fe5b60006126848b8b8b88602001518960400151610c20565b905060016003600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff168c7f0e809784d3b3d167f6c74498bc305f88df3512e888b4f0b7fa5f6d06c10a962e886020015189604001518a60600151604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001935050505060405180910390a45050505050505050612802565b6127a960018261294090919063ffffffff16565b9050612128565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061364f6028913960400191505060405180910390fd5b505050565b6000606060009150600083516040519080825280602002602001820160405280156128415781602001602082028038833980820191505090505b50915060008090505b845181101561293157600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008683815181106128a057fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905091506128fb828561294090919063ffffffff16565b93508183828151811061290a57fe5b60200260200101818152505061292a60018261294090919063ffffffff16565b905061284a565b50828292509250509250929050565b6000808284019050838110156129be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600360006129d98787878787610c20565b815260200190815260200160002060009054906101000a900460ff1615612a68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4174746573746174696f6e20686173206265656e207265766f6b65640000000081525060200191505060405180910390fd5b60006001600087815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905090506014612ad660018361294090919063ffffffff16565b1115612b2d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806135a16032913960400191505060405180910390fd5b6014612bc26001600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905061294090919063ffffffff16565b1115612c19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613544602e913960400191505060405180910390fd5b60008090505b81811015612d53578473ffffffffffffffffffffffffffffffffffffffff166001600089815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612c9957fe5b906000526020600020906003020160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415612d38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180613519602b913960400191505060405180910390fd5b612d4c60018261294090919063ffffffff16565b9050612c1f565b506000429050612d61613445565b60405180608001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018567ffffffffffffffff1681526020018367ffffffffffffffff1681525090506001600089815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060608201518160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208890806001815401808255809150509060018203906000526020600020016000909192909190915055508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16897f3ed7f328925f9f666cc51d584ea4f0260f040f224d26993c6f89a6eb9845ed6f888887604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001935050505060405180910390a45050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561312f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806134f36026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600046905060405180806135d360529139605201905060405180910390206040518060400160405280601581526020017f4665646572617465644174746573746174696f6e7300000000000000000000008152508051906020012060405180807f312e300000000000000000000000000000000000000000000000000000000000815250600301905060405180910390208330604051602001808681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200195505050505050604051602081830303815290604052805190602001206004819055507ffc0bad7bd2704c62e2e5e69325dc36cb761ace9063381f1bf0152485a052526e6004546040518082815260200191505060405180910390a150565b600033905090565b6000606060009150600083516040519080825280602002602001820160405280156133725781602001602082028038833980820191505090505b50915060008090505b8451811015613436576001600087815260200190815260200160002060008683815181106133a557fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509150613400828561294090919063ffffffff16565b93508183828151811061340f57fe5b60200260200101818152505061342f60018261294090919063ffffffff16565b905061337b565b50828292509250509250929050565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152509056fe5369676e6572206973206e6f7420612063757272656e746c7920617574686f72697a6564204174746573746174696f6e5369676e657220666f7220746865206973737565724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734174746573746174696f6e20666f722074686973206163636f756e7420616c7265616479206578697374734d6178206964656e7469666965727320616c7265616479207265676973746572656420666f72206163636f756e7461646472657373206163636f756e742c61646472657373207369676e65722c75696e743634206973737565644f6e294d6178206174746573746174696f6e7320616c7265616479207265676973746572656420666f72206964656e746966696572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429556e657175616c206e756d626572206f66206964656e7469666965727320616e64206163636f756e74734174746573746174696f6e20746f206265207265766f6b656420646f6573206e6f7420657869737453656e64657220646f6573206e6f742068617665207065726d697373696f6e20746f207265766f6b65206174746573746174696f6e732066726f6d2074686973206973737565724f776e6572736869704174746573746174696f6e2862797465733332206964656e7469666965722c61646472657373206973737565722c53656e64657220646f6573206e6f742068617665207065726d697373696f6e20746f207265766f6b652074686973206174746573746174696f6ea265627a7a723158208fe7cc7fcc0e3c7393958ca715425f1f1852054571ceb1b99e778c1302f593d064736f6c634300050d00320000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80638129fc1c116100c3578063b4b773421161007c578063b4b7734214610889578063b71aae46146108a7578063cba33ce01461096b578063e27ff311146109ed578063e3a1b7c614610adb578063f2fde38b14610bdc5761014d565b80638129fc1c146105395780638da5cb5b146105435780638f32d59b1461058d57806394b09057146105af5780639b43e48014610673578063a862e12e146106915761014d565b80635b07fdd8116101155780635b07fdd8146103155780635fa2fc30146103335780636125a6c214610379578063715018a6146104af57806373dfde98146104b95780637e68298d1461051b5761014d565b80630ab3ddc6146101525780631100b32414610208578063158ef93e1461027657806328c1f99b1461029857806354255be0146102e2575b600080fd5b6101f2600480360360a081101561016857600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190505050610c20565b6040518082815260200191505060405180910390f35b6102746004803603606081101561021e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d48565b005b61027e610f06565b604051808215151515815260200191505060405180910390f35b6102a0610f19565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6102ea610f1f565b6040518085815260200184815260200183815260200182815260200194505050505060405180910390f35b61031d610f45565b6040518082815260200191505060405180910390f35b61035f6004803603602081101561034957600080fd5b8101908080359060200190929190505050610f4b565b604051808215151515815260200191505060405180910390f35b6104106004803603604081101561038f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001906401000000008111156103cc57600080fd5b8201836020820111156103de57600080fd5b8035906020019184602083028401116401000000008311171561040057600080fd5b9091929391929390505050610f6b565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b8381101561045757808201518184015260208101905061043c565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561049957808201518184015260208101905061047e565b5050505090500194505050505060405180910390f35b6104b761119c565b005b610519600480360360608110156104cf57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff1690602001909291905050506112d5565b005b6105236112e7565b6040518082815260200191505060405180910390f35b61054161131f565b005b61054b6113d0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105956113f9565b604051808215151515815260200191505060405180910390f35b61067160048036036101008110156105c657600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050611457565b005b61067b61170d565b6040518082815260200191505060405180910390f35b610712600480360360408110156106a757600080fd5b8101908080359060200190929190803590602001906401000000008111156106ce57600080fd5b8201836020820111156106e057600080fd5b8035906020019184602083028401116401000000008311171561070257600080fd5b9091929391929390505050611712565b60405180806020018060200180602001806020018060200186810386528b818151815260200191508051906020019060200280838360005b8381101561076557808201518184015260208101905061074a565b5050505090500186810385528a818151815260200191508051906020019060200280838360005b838110156107a757808201518184015260208101905061078c565b50505050905001868103845289818151815260200191508051906020019060200280838360005b838110156107e95780820151818401526020810190506107ce565b50505050905001868103835288818151815260200191508051906020019060200280838360005b8381101561082b578082015181840152602081019050610810565b50505050905001868103825287818151815260200191508051906020019060200280838360005b8381101561086d578082015181840152602081019050610852565b505050509050019a505050505050505050505060405180910390f35b610891611bef565b6040518082815260200191505060405180910390f35b61096960048036036101008110156108be57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803567ffffffffffffffff169060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050611bf4565b005b6109d76004803603606081101561098157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611c1b565b6040518082815260200191505060405180910390f35b610ad960048036036060811015610a0357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190640100000000811115610a4057600080fd5b820183602082011115610a5257600080fd5b80359060200191846020830284011164010000000083111715610a7457600080fd5b909192939192939080359060200190640100000000811115610a9557600080fd5b820183602082011115610aa757600080fd5b80359060200191846020830284011164010000000083111715610ac957600080fd5b9091929391929390505050611c56565b005b610b3160048036036060811015610af157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611ea5565b604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff16815260200194505050505060405180910390f35b610c1e60048036036020811015610bf257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611f64565b005b600060405160200180806136be6037913960370180613572602f9139602f019050604051602081830303815290604052805190602001208686868686604051602001808781526020018681526020018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001965050505050505060405160208183030381529060405280519060200120905095945050505050565b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610dad57503373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b80610ea157508173ffffffffffffffffffffffffffffffffffffffff16610dd2611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610e4e57600080fd5b505afa158015610e62573d6000803e3d6000fd5b505050506040513d6020811015610e7857600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b610ef6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603a8152602001806136f5603a913960400191505060405180910390fd5b610f018383836120c5565b505050565b600060149054906101000a900460ff1681565b61ce1081565b600080600080600180600080839350829250819150809050935093509350935090919293565b60045481565b60036020528060005260406000206000915054906101000a900460ff1681565b6060806000610fbb86868680806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050612807565b809450819250505080604051908082528060200260200182016040528015610ff25781602001602082028038833980820191505090505b5091506060600080905060008090505b8787905081101561118a57600260008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600089898481811061105a57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054806020026020016040519081016040528092919081815260200182805480156110fb57602002820191906000526020600020905b8154815260200190600101908083116110e7575b5050505050925060008090505b835181101561116e5783818151811061111d57fe5b602002602001015186848151811061113157fe5b60200260200101818152505061115160018461294090919063ffffffff16565b925061116760018261294090919063ffffffff16565b9050611108565b5061118360018261294090919063ffffffff16565b9050611002565b50848494509450505050935093915050565b6111a46113f9565b611216576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b6112e283338433856129c8565b505050565b60405160200180806136be6037913960370180613572602f9139602f0190506040516020818303038152906040528051906020012081565b600060149054906101000a900460ff16156113a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f636f6e747261637420616c726561647920696e697469616c697a65640000000081525060200191505060405180910390fd5b6001600060146101000a81548160ff0219169083151502179055506113c6336130a9565b6113ce6131ed565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1661143b613330565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b8673ffffffffffffffffffffffffffffffffffffffff16611476611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb876040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156114f257600080fd5b505afa158015611506573d6000803e3d6000fd5b505050506040513d602081101561151c57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614611599576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260458152602001806134ae6045913960600191505060405180910390fd5b60006115a88989898989610c20565b90506000731578b071de10e587f49db5934a24ca830fddde196334d1a233600454848888886040518663ffffffff1660e01b8152600401808681526020018581526020018460ff1660ff1681526020018381526020018281526020019550505050505060206040518083038186803b15801561162357600080fd5b505af4158015611637573d6000803e3d6000fd5b505050506040513d602081101561164d57600080fd5b810190808051906020019092919050505090508673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611701576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f5369676e617475726520697320696e76616c696400000000000000000000000081525060200191505060405180910390fd5b50505050505050505050565b601481565b6060806060806060600061176789898980806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f82011690508083019250505050505050613338565b80975081925050508060405190808252806020026020018201604052801561179e5781602001602082028038833980820191505090505b509450806040519080825280602002602001820160405280156117d05781602001602082028038833980820191505090505b509350806040519080825280602002602001820160405280156118025781602001602082028038833980820191505090505b509250806040519080825280602002602001820160405280156118345781602001602082028038833980820191505090505b50915060009050606060008090505b89899050811015611bd257600160008c815260200190815260200160002060008b8b8481811061186f57fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015611a2857838290600052602060002090600302016040518060800160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016002820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681525050815260200190600101906118e6565b50505050915060008090505b8251811015611bb657828181518110611a4957fe5b602002602001015160000151888581518110611a6157fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110611aa757fe5b602002602001015160200151878581518110611abf57fe5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050828181518110611b0557fe5b602002602001015160400151868581518110611b1d57fe5b602002602001019067ffffffffffffffff16908167ffffffffffffffff1681525050828181518110611b4b57fe5b602002602001015160600151858581518110611b6357fe5b602002602001019067ffffffffffffffff16908167ffffffffffffffff1681525050611b9960018561294090919063ffffffff16565b9350611baf60018261294090919063ffffffff16565b9050611a34565b50611bcb60018261294090919063ffffffff16565b9050611843565b508686868686965096509650965096505050939792965093509350565b601481565b611c048888888888888888611457565b611c1188888888886129c8565b5050505050505050565b60026020528260005260406000206020528160005260406000208181548110611c4057fe5b9060005260206000200160009250925050505481565b818190508484905014611cb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180613625602a913960400191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480611dd757508473ffffffffffffffffffffffffffffffffffffffff16611d08611fea565b73ffffffffffffffffffffffffffffffffffffffff16637b2434cb336040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015611d8457600080fd5b505afa158015611d98573d6000803e3d6000fd5b505050506040513d6020811015611dae57600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff16145b611e2c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260478152602001806136776047913960600191505060405180910390fd5b60008090505b84849050811015611e9d57611e82858583818110611e4c57fe5b9050602002013587858585818110611e6057fe5b9050602002013573ffffffffffffffffffffffffffffffffffffffff166120c5565b611e9660018261294090919063ffffffff16565b9050611e32565b505050505050565b60016020528260005260406000206020528160005260406000208181548110611eca57fe5b906000526020600020906003020160009250925050508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010160149054906101000a900467ffffffffffffffff16908060020160009054906101000a900467ffffffffffffffff16905084565b611f6c6113f9565b611fde576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b611fe7816130a9565b50565b600061ce1073ffffffffffffffffffffffffffffffffffffffff1663dcf0aaed60405160200180807f4163636f756e74730000000000000000000000000000000000000000000000008152506008019050604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561208557600080fd5b505afa158015612099573d6000803e3d6000fd5b505050506040513d60208110156120af57600080fd5b8101908080519060200190929190505050905090565b60006001600085815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008180549050905060008090505b818110156127b0578373ffffffffffffffffffffffffffffffffffffffff1683828154811061215357fe5b906000526020600020906003020160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146121a557612795565b6121ad613445565b8382815481106121b957fe5b90600052602060002090600302016040518060800160405290816000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160149054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020016002820160009054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681525050905060018303821461247d578360018403815481106122fd57fe5b906000526020600020906003020184838154811061231757fe5b90600052602060002090600302016000820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001820160149054906101000a900467ffffffffffffffff168160010160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506002820160009054906101000a900467ffffffffffffffff168160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055509050505b8380548061248757fe5b6001900381819060005260206000209060030201600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556001820160146101000a81549067ffffffffffffffff02191690556002820160006101000a81549067ffffffffffffffff02191690555050905560008090506000600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008180549050905060008090505b81811015612665578a8382815481106125cd57fe5b9060005260206000200154146125e25761264a565b600182038114612621578260018303815481106125fb57fe5b906000526020600020015483828154811061261257fe5b90600052602060002001819055505b8280548061262b57fe5b6001900381819060005260206000200160009055905560019350612665565b61265e60018261294090919063ffffffff16565b90506125b8565b508261266d57fe5b60006126848b8b8b88602001518960400151610c20565b905060016003600083815260200190815260200160002060006101000a81548160ff0219169083151502179055508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff168c7f0e809784d3b3d167f6c74498bc305f88df3512e888b4f0b7fa5f6d06c10a962e886020015189604001518a60600151604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001935050505060405180910390a45050505050505050612802565b6127a960018261294090919063ffffffff16565b9050612128565b506040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602881526020018061364f6028913960400191505060405180910390fd5b505050565b6000606060009150600083516040519080825280602002602001820160405280156128415781602001602082028038833980820191505090505b50915060008090505b845181101561293157600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008683815181106128a057fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905091506128fb828561294090919063ffffffff16565b93508183828151811061290a57fe5b60200260200101818152505061292a60018261294090919063ffffffff16565b905061284a565b50828292509250509250929050565b6000808284019050838110156129be576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600360006129d98787878787610c20565b815260200190815260200160002060009054906101000a900460ff1615612a68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601c8152602001807f4174746573746174696f6e20686173206265656e207265766f6b65640000000081525060200191505060405180910390fd5b60006001600087815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905090506014612ad660018361294090919063ffffffff16565b1115612b2d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001806135a16032913960400191505060405180910390fd5b6014612bc26001600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905061294090919063ffffffff16565b1115612c19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e815260200180613544602e913960400191505060405180910390fd5b60008090505b81811015612d53578473ffffffffffffffffffffffffffffffffffffffff166001600089815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110612c9957fe5b906000526020600020906003020160000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415612d38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602b815260200180613519602b913960400191505060405180910390fd5b612d4c60018261294090919063ffffffff16565b9050612c1f565b506000429050612d61613445565b60405180608001604052808773ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018567ffffffffffffffff1681526020018367ffffffffffffffff1681525090506001600089815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819080600181540180825580915050906001820390600052602060002090600302016000909192909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060608201518160020160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208890806001815401808255809150509060018203906000526020600020016000909192909190915055508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff16897f3ed7f328925f9f666cc51d584ea4f0260f040f224d26993c6f89a6eb9845ed6f888887604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018367ffffffffffffffff1667ffffffffffffffff1681526020018267ffffffffffffffff1667ffffffffffffffff168152602001935050505060405180910390a45050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561312f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806134f36026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600046905060405180806135d360529139605201905060405180910390206040518060400160405280601581526020017f4665646572617465644174746573746174696f6e7300000000000000000000008152508051906020012060405180807f312e300000000000000000000000000000000000000000000000000000000000815250600301905060405180910390208330604051602001808681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200195505050505050604051602081830303815290604052805190602001206004819055507ffc0bad7bd2704c62e2e5e69325dc36cb761ace9063381f1bf0152485a052526e6004546040518082815260200191505060405180910390a150565b600033905090565b6000606060009150600083516040519080825280602002602001820160405280156133725781602001602082028038833980820191505090505b50915060008090505b8451811015613436576001600087815260200190815260200160002060008683815181106133a557fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509150613400828561294090919063ffffffff16565b93508183828151811061340f57fe5b60200260200101818152505061342f60018261294090919063ffffffff16565b905061337b565b50828292509250509250929050565b6040518060800160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600067ffffffffffffffff168152602001600067ffffffffffffffff168152509056fe5369676e6572206973206e6f7420612063757272656e746c7920617574686f72697a6564204174746573746174696f6e5369676e657220666f7220746865206973737565724f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734174746573746174696f6e20666f722074686973206163636f756e7420616c7265616479206578697374734d6178206964656e7469666965727320616c7265616479207265676973746572656420666f72206163636f756e7461646472657373206163636f756e742c61646472657373207369676e65722c75696e743634206973737565644f6e294d6178206174746573746174696f6e7320616c7265616479207265676973746572656420666f72206964656e746966696572454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429556e657175616c206e756d626572206f66206964656e7469666965727320616e64206163636f756e74734174746573746174696f6e20746f206265207265766f6b656420646f6573206e6f7420657869737453656e64657220646f6573206e6f742068617665207065726d697373696f6e20746f207265766f6b65206174746573746174696f6e732066726f6d2074686973206973737565724f776e6572736869704174746573746174696f6e2862797465733332206964656e7469666965722c61646472657373206973737565722c53656e64657220646f6573206e6f742068617665207065726d697373696f6e20746f207265766f6b652074686973206174746573746174696f6ea265627a7a723158208fe7cc7fcc0e3c7393958ca715425f1f1852054571ceb1b99e778c1302f593d064736f6c634300050d0032