This nametag was submitted by Kleros Scout.
Latest 25 from a total of 100,012 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Register Voters | 44471139 | 1 hr ago | IN | 0 XDAI | 0.00005711 | ||||
| Authorize Voters | 44471127 | 1 hr ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44469747 | 3 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44469736 | 3 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44468354 | 5 hrs ago | IN | 0 XDAI | 0.00005711 | ||||
| Authorize Voters | 44468342 | 5 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44466949 | 7 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44466937 | 7 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44465545 | 9 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44465534 | 9 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44464159 | 11 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44464147 | 11 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44462763 | 13 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44462751 | 13 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44461365 | 15 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44461353 | 15 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44459976 | 17 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44459964 | 17 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44458595 | 19 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44458584 | 19 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44457206 | 21 hrs ago | IN | 0 XDAI | 0.0000571 | ||||
| Authorize Voters | 44457195 | 21 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44455797 | 23 hrs ago | IN | 0 XDAI | 0.00005712 | ||||
| Authorize Voters | 44455785 | 23 hrs ago | IN | 0 XDAI | 0.00003891 | ||||
| Register Voters | 44454382 | 25 hrs ago | IN | 0 XDAI | 0.00005712 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 44471133 | 1 hr ago | 0 XDAI | ||||
| 44469741 | 3 hrs ago | 0 XDAI | ||||
| 44468348 | 5 hrs ago | 0 XDAI | ||||
| 44466943 | 7 hrs ago | 0 XDAI | ||||
| 44465540 | 9 hrs ago | 0 XDAI | ||||
| 44464153 | 11 hrs ago | 0 XDAI | ||||
| 44462757 | 13 hrs ago | 0 XDAI | ||||
| 44461359 | 15 hrs ago | 0 XDAI | ||||
| 44459971 | 17 hrs ago | 0 XDAI | ||||
| 44458589 | 19 hrs ago | 0 XDAI | ||||
| 44457200 | 21 hrs ago | 0 XDAI | ||||
| 44455791 | 23 hrs ago | 0 XDAI | ||||
| 44454376 | 25 hrs ago | 0 XDAI | ||||
| 44452979 | 27 hrs ago | 0 XDAI | ||||
| 44451573 | 29 hrs ago | 0 XDAI | ||||
| 44450184 | 31 hrs ago | 0 XDAI | ||||
| 44448786 | 33 hrs ago | 0 XDAI | ||||
| 44447379 | 35 hrs ago | 0 XDAI | ||||
| 44445965 | 37 hrs ago | 0 XDAI | ||||
| 44444559 | 39 hrs ago | 0 XDAI | ||||
| 44443157 | 41 hrs ago | 0 XDAI | ||||
| 44441764 | 43 hrs ago | 0 XDAI | ||||
| 44440358 | 45 hrs ago | 0 XDAI | ||||
| 44438946 | 47 hrs ago | 0 XDAI | ||||
| 44437560 | 2 days ago | 0 XDAI |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OpnVote
Compiler Version
v0.8.27+commit.40a35a09
Optimization Enabled:
No with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import {ERC2771Context, Context} from "@openzeppelin/contracts/metatx/ERC2771Context.sol";
import {
Election,
AuthorizationProvider,
Register,
SignatureValidationServer,
ElectionStatus,
RsaPublicKeyRaw
} from "./Structs.sol";
contract OpnVote is Ownable, ERC2771Context {
using ECDSA for bytes32;
using MessageHashUtils for bytes32;
string public constant VERSION = "0.1.0";
/// @return Current contract version
function version() external pure returns (string memory) {
return VERSION;
}
uint256 public nextElectionId;
constructor(address _trustedForwarder, uint256 startId) Ownable(msg.sender) ERC2771Context(_trustedForwarder) {
nextElectionId = startId;
}
mapping(uint8 => Register) public registers;
mapping(uint8 => SignatureValidationServer) public svss;
mapping(uint8 => AuthorizationProvider) public aps;
mapping(uint256 => Election) public elections;
/**
* Events *
*/
// AP Events
event VoterAuthorized(uint8 indexed apId, uint256 indexed electionId, uint256 indexed voterId);
event VotersAuthorized(uint8 indexed apId, uint256 indexed electionId, uint256[] voterIds);
// Register Events
event VoterRegistered(
uint8 indexed registerId,
uint256 indexed electionId,
uint256 indexed voterId,
bytes blindedSignature,
bytes blindedElectionToken
);
event VotersRegistered(
uint8 indexed registerId,
uint256 indexed electionId,
uint256[] voterIds,
bytes[] blindedSignatures,
bytes[] blindedElectionTokens
);
event ElectionRegisterPublicKeySet(uint256 indexed electionId, bytes n, bytes e);
// Voter Events
event VoteCast(
uint256 indexed electionId,
address indexed voter,
bytes svsSignature,
bytes voteEncrypted,
bytes voteEncryptedUser,
bytes unblindedElectionToken,
bytes unblindedSignature
);
event VoteUpdated(uint256 indexed electionId, address indexed voter, bytes voteEncrypted, bytes voteEncryptedUser);
// Admin Events
event ElectionCreated(
uint256 indexed electionId,
uint256 votingStartTime,
uint256 votingEndTime,
uint256 registrationStartTime,
uint256 registrationEndTime,
uint8 registerId,
uint8 authProviderId,
uint8 svsId,
string descriptionIpfsCid,
bytes publicKey
);
event ElectionUpdated(
uint256 indexed electionId,
uint256 votingStartTime,
uint256 votingEndTime,
uint256 registrationStartTime,
uint256 registrationEndTime,
uint8 registerId,
uint8 authProviderId,
uint8 svsId,
string descriptionIpfsCid,
bytes publicKey
);
event ElectionStatusChanged(uint256 indexed electionId, ElectionStatus oldStatus, ElectionStatus newStatus);
event ElectionCanceled(uint256 indexed electionId, string cancelReasonIpfsCid);
event ElectionResultsPublished(
uint256 indexed electionId, uint256[] yesVotes, uint256[] noVotes, uint256[] invalidVotes, bytes privateKey
);
/**
* AP Methods *
*/
// voterId will not be stored or validated onchain as register & Ap might publish them in no specific order
function authorizeVoter(uint256 electionId, uint256 voterId) external {
uint8 apId = elections[electionId].authProviderId;
require(msg.sender == aps[apId].owner, "Only AP Owner");
require(elections[electionId].votingStartTime != 0, "Election unknown");
elections[electionId].totalAuthorized += 1;
emit VoterAuthorized(apId, electionId, voterId);
}
function authorizeVoters(uint256 electionId, uint256[] calldata voterIds) external {
uint8 apId = elections[electionId].authProviderId;
require(msg.sender == aps[apId].owner, "Only AP Owner");
require(elections[electionId].votingStartTime != 0, "Election unknown");
elections[electionId].totalAuthorized += voterIds.length;
emit VotersAuthorized(apId, electionId, voterIds);
}
/**
* Register Methods *
*/
function registerVoter(
uint256 electionId,
uint256 voterId,
bytes calldata blindedSignature,
bytes calldata blindedElectionToken
) external {
uint8 registerId = elections[electionId].registerId;
require(msg.sender == registers[registerId].owner, "Only Register Owner");
require(blindedSignature.length > 0, "Blinded Signature required"); //todo: Specify expected Length
require(blindedElectionToken.length > 0, "Blinded Signature required"); //todo: Specify expected Length
require(elections[electionId].votingStartTime != 0, "Election unknown");
elections[electionId].totalRegistered += 1;
emit VoterRegistered(registerId, electionId, voterId, blindedSignature, blindedElectionToken);
}
function registerVoters(
uint256 electionId,
uint256[] calldata voterIds,
bytes[] calldata blindedSignatures,
bytes[] calldata blindedElectionTokens
) external {
uint8 registerId = elections[electionId].registerId;
require(msg.sender == registers[registerId].owner, "Only Register Owner");
require(blindedSignatures.length > 0, "Blinded Signature required"); //todo: Specify expected Length
require(blindedElectionTokens.length > 0, "Blinded Signature required"); //todo: Specify expected Length
require(voterIds.length > 0, "voterIds required"); //todo: Specify expected Length
require(elections[electionId].votingStartTime != 0, "Election unknown");
elections[electionId].totalRegistered += voterIds.length;
emit VotersRegistered(registerId, electionId, voterIds, blindedSignatures, blindedElectionTokens);
}
function setElectionRegisterPublicKey(uint256 electionId, bytes memory n, bytes memory e) external {
uint8 registerId = elections[electionId].registerId;
require(registers[registerId].owner == msg.sender, "Only Register");
require(
elections[electionId].status == ElectionStatus.Pending
|| elections[electionId].status == ElectionStatus.Active,
"Election not active or pending"
);
elections[electionId].registerPubKey = RsaPublicKeyRaw({n: n, e: e});
emit ElectionRegisterPublicKeySet(electionId, n, e);
}
/**
* Voter Methods *
*/
function vote(
uint256 electionId,
address voter,
bytes calldata svsSignature,
bytes calldata voteEncrypted,
bytes calldata voteEncryptedUser,
bytes calldata unblindedElectionToken,
bytes calldata unblindedSignature
) external {
Election storage election = elections[electionId];
require(election.votingStartTime != 0, "Election unknown");
require(voteEncrypted.length == 256 || voteEncrypted.length == 512, "Invalid voteEncrypted length"); // Allowing RSA 2048 and 4096
require(voteEncryptedUser.length > 0 && voteEncryptedUser.length <= 512, "Invalid voteEncryptedUser length"); // Allowing symmetric enc and up to RSA 4096
require(election.status == ElectionStatus.Active, "Election is not active");
require(election.votingEndTime >= block.timestamp, "Election ended");
if (svsSignature.length == 65) {
address svsOwner = svss[election.svsId].owner;
require(svsOwner != address(0), "SVS not specified");
require(unblindedElectionToken.length == 32, "Invalid unblindedElectionToken length");
require(
unblindedSignature.length == 256 || unblindedSignature.length == 512,
"Invalid unblindedSignature length"
); // Allowing RSA 2048 and 4096
require(!election.hasVoted[voter], "Already voted");
bool isValidSig = _verify(
keccak256(
abi.encode(
electionId, voter, voteEncrypted, voteEncryptedUser, unblindedElectionToken, unblindedSignature
)
),
svsSignature,
svsOwner
);
require(isValidSig, "Sig invalid");
election.totalVotes += 1;
election.hasVoted[voter] = true;
//First vote
emit VoteCast(
electionId,
voter,
svsSignature,
voteEncrypted,
voteEncryptedUser,
unblindedElectionToken,
unblindedSignature
);
} else {
//Vote recasting
require(election.hasVoted[_msgSender()], "voter unknown");
emit VoteUpdated(electionId, _msgSender(), voteEncrypted, voteEncryptedUser);
}
}
/**
* Admin Methods *
*/
function addRegister(Register memory newRegister) external onlyOwner {
require(registers[newRegister.id].owner == address(0), "Id already used");
require(newRegister.owner != address(0), "No owner specified");
registers[newRegister.id] = newRegister;
}
function addSvs(SignatureValidationServer memory newSvs) external onlyOwner {
require(svss[newSvs.id].owner == address(0), "Id already used");
require(newSvs.owner != address(0), "No owner specified");
svss[newSvs.id] = newSvs;
}
function addAp(AuthorizationProvider memory newAp) external onlyOwner {
require(aps[newAp.id].owner == address(0), "Id already used");
require(newAp.owner != address(0), "No owner specified");
aps[newAp.id] = newAp;
}
/**
* Admin Election Methods *
*/
function startElection(uint256 electionId) external onlyOwner {
Election storage election = elections[electionId];
require(election.votingStartTime != 0, "Election unknown");
require(election.status == ElectionStatus.Pending, "Not pending");
require(election.votingStartTime <= block.timestamp, "too early");
require(election.votingEndTime > block.timestamp, "too late");
require(election.registerPubKey.n.length > 0 && election.registerPubKey.e.length > 0, "Register Key required"); //todo: Specify expected Length
ElectionStatus oldStatus = election.status;
election.status = ElectionStatus.Active;
emit ElectionStatusChanged(electionId, oldStatus, ElectionStatus.Active);
}
function endElection(uint256 electionId) external onlyOwner {
Election storage election = elections[electionId];
require(election.votingStartTime != 0, "Election unknown");
require(election.votingEndTime <= block.timestamp, "too early");
require(
election.status == ElectionStatus.Active || election.status == ElectionStatus.Pending,
"Not active or pending"
);
ElectionStatus oldStatus = election.status;
election.status = ElectionStatus.Ended;
emit ElectionStatusChanged(electionId, oldStatus, ElectionStatus.Ended);
}
function cancelElection(uint256 electionId, string memory cancelReasonIpfsCid) external onlyOwner {
Election storage election = elections[electionId];
require(election.votingStartTime != 0, "Election unknown");
ElectionStatus oldStatus = election.status;
election.status = ElectionStatus.Canceled;
election.cancelReasonIpfsCid = cancelReasonIpfsCid;
emit ElectionCanceled(electionId, cancelReasonIpfsCid);
emit ElectionStatusChanged(electionId, oldStatus, ElectionStatus.Canceled);
}
function createOrUpdateElection(
uint256 manualElectionId,
uint256 votingStartTime,
uint256 votingEndTime,
uint256 registrationStartTime,
uint256 registrationEndTime,
uint8 registerId,
uint8 authProviderId,
uint8 svsId,
string memory descriptionIpfsCid,
bytes memory publicKey
) external onlyOwner returns (uint256 electionId) {
require(votingStartTime < votingEndTime, "Start time must be before end time.");
require(votingStartTime > block.timestamp, "Start time in past");
require(registers[registerId].owner != address(0), "Invalid registerId");
require(aps[authProviderId].owner != address(0), "Invalid authProviderId");
require(svss[svsId].owner != address(0), "Invalid svsId");
require(bytes(descriptionIpfsCid).length > 0, "Invalid description cid"); //todo: Specify expected Length
require(publicKey.length > 0, "Invalid election PubKey"); //todo: Specify expected Length
electionId = manualElectionId == 0 ? nextElectionId++ : manualElectionId;
if (manualElectionId != 0 && manualElectionId >= nextElectionId) {
nextElectionId = manualElectionId + 1;
}
Election storage election = elections[electionId];
bool isNewElection = election.votingStartTime == 0;
require(isNewElection || election.status == ElectionStatus.Pending, "Already started");
election.status = ElectionStatus.Pending;
election.electionId = electionId;
election.descriptionIpfsCid = descriptionIpfsCid;
election.votingStartTime = votingStartTime;
election.votingEndTime = votingEndTime;
election.registerId = registerId;
election.authProviderId = authProviderId;
election.svsId = svsId;
election.publicKey = publicKey;
if (isNewElection) {
emit ElectionCreated(
electionId,
votingStartTime,
votingEndTime,
registrationStartTime,
registrationEndTime,
registerId,
authProviderId,
svsId,
descriptionIpfsCid,
publicKey
);
} else {
emit ElectionUpdated(
electionId,
votingStartTime,
votingEndTime,
registrationStartTime,
registrationEndTime,
registerId,
authProviderId,
svsId,
descriptionIpfsCid,
publicKey
);
}
return electionId;
}
function publishElectionResults(
uint256 electionId,
uint256[] calldata yesVotes,
uint256[] calldata noVotes,
uint256[] calldata invalidVotes,
bytes memory privateKey
) external onlyOwner {
Election storage election = elections[electionId];
require(election.votingStartTime != 0, "Election unknown");
require(election.status == ElectionStatus.Ended, "Election not ended");
require(
yesVotes.length > 0 && yesVotes.length == noVotes.length && yesVotes.length == invalidVotes.length,
"Array length mismatch"
);
election.status = ElectionStatus.ResultsPublished;
election.privateKey = privateKey;
emit ElectionResultsPublished(electionId, yesVotes, noVotes, invalidVotes, privateKey);
emit ElectionStatusChanged(electionId, ElectionStatus.Ended, ElectionStatus.ResultsPublished);
}
function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) {
return data.toEthSignedMessageHash().recover(signature) == account;
}
/**
* OZ Overrides *
*/
function _msgSender() internal view override(Context, ERC2771Context) returns (address) {
return ERC2771Context._msgSender();
}
function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) {
return ERC2771Context._msgData();
}
function _contextSuffixLength() internal pure override(Context, ERC2771Context) returns (uint256) {
return 20;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/cryptography/MessageHashUtils.sol)
pragma solidity ^0.8.20;
import {Strings} from "../Strings.sol";
/**
* @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
*
* The library provides methods for generating a hash of a message that conforms to the
* https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
* specifications.
*/
library MessageHashUtils {
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing a bytes32 `messageHash` with
* `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
* keccak256, although any bytes32 value can be safely used because the final digest will
* be re-hashed.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
}
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x45` (`personal_sign` messages).
*
* The digest is calculated by prefixing an arbitrary `message` with
* `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
* hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.
*
* See {ECDSA-recover}.
*/
function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
return
keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
}
/**
* @dev Returns the keccak256 digest of an ERC-191 signed data with version
* `0x00` (data with intended validator).
*
* The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
* `validator` address. Then hashing the result.
*
* See {ECDSA-recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(hex"19_00", validator, data));
}
/**
* @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.
*/
function toDataWithIntendedValidatorHash(
address validator,
bytes32 messageHash
) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
mstore(0x00, hex"19_00")
mstore(0x02, shl(96, validator))
mstore(0x16, messageHash)
digest := keccak256(0x00, 0x36)
}
}
/**
* @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).
*
* The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
* `\x19\x01` and hashing the result. It corresponds to the hash signed by the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
*
* See {ECDSA-recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore(ptr, hex"19_01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
digest := keccak256(ptr, 0x42)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (metatx/ERC2771Context.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Context variant with ERC-2771 support.
*
* WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll
* be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC-2771
* specification adding the address size in bytes (20) to the calldata size. An example of an unexpected
* behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive`
* function only accessible if `msg.data.length == 0`.
*
* WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption.
* Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender}
* recovery.
*/
abstract contract ERC2771Context is Context {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable _trustedForwarder;
/**
* @dev Initializes the contract with a trusted forwarder, which will be able to
* invoke functions on this contract on behalf of other accounts.
*
* NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}.
*/
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address trustedForwarder_) {
_trustedForwarder = trustedForwarder_;
}
/**
* @dev Returns the address of the trusted forwarder.
*/
function trustedForwarder() public view virtual returns (address) {
return _trustedForwarder;
}
/**
* @dev Indicates whether any particular address is the trusted forwarder.
*/
function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
return forwarder == trustedForwarder();
}
/**
* @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever
* a call is not performed by the trusted forwarder or the calldata length is less than
* 20 bytes (an address length).
*/
function _msgSender() internal view virtual override returns (address) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
} else {
return super._msgSender();
}
}
/**
* @dev Override for `msg.data`. Defaults to the original `msg.data` whenever
* a call is not performed by the trusted forwarder or the calldata length is less than
* 20 bytes (an address length).
*/
function _msgData() internal view virtual override returns (bytes calldata) {
uint256 calldataLength = msg.data.length;
uint256 contextSuffixLength = _contextSuffixLength();
if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
return msg.data[:calldataLength - contextSuffixLength];
} else {
return super._msgData();
}
}
/**
* @dev ERC-2771 specifies the context as being a single address (20 bytes).
*/
function _contextSuffixLength() internal view virtual override returns (uint256) {
return 20;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
enum ElectionStatus {
Pending,
Active,
Ended,
ResultsPublished,
Canceled
}
struct AuthorizationProvider {
uint8 id;
address owner;
string apName;
string apUri;
}
// struct ElectionResult {
// uint256 yesVotes;
// uint256 noVotes;
// uint256 invalidVotes;
// }
struct SignatureValidationServer {
uint8 id;
address owner;
string svsName;
string svsUri;
}
struct Register {
uint8 id;
address owner;
string registerName;
string registerUri;
}
struct Election {
uint256 electionId;
uint256 votingStartTime;
uint256 votingEndTime;
uint256 totalVotes;
uint256 totalAuthorized;
uint256 totalRegistered;
uint8 registerId;
uint8 authProviderId;
uint8 svsId;
ElectionStatus status;
// ElectionResult[] results;
mapping(address => bool) hasVoted;
string cancelReasonIpfsCid;
string descriptionIpfsCid;
bytes publicKey;
bytes privateKey;
RsaPublicKeyRaw registerPubKey;
}
struct RsaPublicKeyRaw {
bytes n; // RSA modulus
bytes e; // RSA public exponent
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SafeCast} from "./math/SafeCast.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
using SafeCast for *;
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
uint256 private constant SPECIAL_CHARS_LOOKUP =
(1 << 0x08) | // backspace
(1 << 0x09) | // tab
(1 << 0x0a) | // newline
(1 << 0x0c) | // form feed
(1 << 0x0d) | // carriage return
(1 << 0x22) | // double quote
(1 << 0x5c); // backslash
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev The string being parsed contains characters that are not in scope of the given base.
*/
error StringsInvalidChar();
/**
* @dev The string being parsed is not a properly formatted address.
*/
error StringsInvalidAddressFormat();
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
assembly ("memory-safe") {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
assembly ("memory-safe") {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal
* representation, according to EIP-55.
*/
function toChecksumHexString(address addr) internal pure returns (string memory) {
bytes memory buffer = bytes(toHexString(addr));
// hash the hex part of buffer (skip length + 2 bytes, length 40)
uint256 hashValue;
assembly ("memory-safe") {
hashValue := shr(96, keccak256(add(buffer, 0x22), 40))
}
for (uint256 i = 41; i > 1; --i) {
// possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)
if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {
// case shift by xoring with 0x20
buffer[i] ^= 0x20;
}
hashValue >>= 4;
}
return string(buffer);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
/**
* @dev Parse a decimal string and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input) internal pure returns (uint256) {
return parseUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[0-9]*`
* - The result must fit into an `uint256` type
*/
function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
uint256 result = 0;
for (uint256 i = begin; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 9) return (false, 0);
result *= 10;
result += chr;
}
return (true, result);
}
/**
* @dev Parse a decimal string and returns the value as a `int256`.
*
* Requirements:
* - The string must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input) internal pure returns (int256) {
return parseInt(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `[-+]?[0-9]*`
* - The result must fit in an `int256` type.
*/
function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {
(bool success, int256 value) = tryParseInt(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if
* the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {
return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);
}
uint256 private constant ABS_MIN_INT256 = 2 ** 255;
/**
* @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid
* character or if the result does not fit in a `int256`.
*
* NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.
*/
function tryParseInt(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, int256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseIntUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseIntUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, int256 value) {
bytes memory buffer = bytes(input);
// Check presence of a negative sign.
bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
bool positiveSign = sign == bytes1("+");
bool negativeSign = sign == bytes1("-");
uint256 offset = (positiveSign || negativeSign).toUint();
(bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);
if (absSuccess && absValue < ABS_MIN_INT256) {
return (true, negativeSign ? -int256(absValue) : int256(absValue));
} else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {
return (true, type(int256).min);
} else return (false, 0);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as a `uint256`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input) internal pure returns (uint256) {
return parseHexUint(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]*`
* - The result must fit in an `uint256` type.
*/
function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {
(bool success, uint256 value) = tryParseHexUint(input, begin, end);
if (!success) revert StringsInvalidChar();
return value;
}
/**
* @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {
return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an
* invalid character.
*
* NOTE: This function will revert if the result does not fit in a `uint256`.
*/
function tryParseHexUint(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, uint256 value) {
if (end > bytes(input).length || begin > end) return (false, 0);
return _tryParseHexUintUncheckedBounds(input, begin, end);
}
/**
* @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that
* `begin <= end <= input.length`. Other inputs would result in undefined behavior.
*/
function _tryParseHexUintUncheckedBounds(
string memory input,
uint256 begin,
uint256 end
) private pure returns (bool success, uint256 value) {
bytes memory buffer = bytes(input);
// skip 0x prefix if present
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 offset = hasPrefix.toUint() * 2;
uint256 result = 0;
for (uint256 i = begin + offset; i < end; ++i) {
uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));
if (chr > 15) return (false, 0);
result *= 16;
unchecked {
// Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).
// This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.
result += chr;
}
}
return (true, result);
}
/**
* @dev Parse a hexadecimal string (with or without "0x" prefix), and returns the value as an `address`.
*
* Requirements:
* - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input) internal pure returns (address) {
return parseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and
* `end` (excluded).
*
* Requirements:
* - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`
*/
function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {
(bool success, address value) = tryParseAddress(input, begin, end);
if (!success) revert StringsInvalidAddressFormat();
return value;
}
/**
* @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly
* formatted address. See {parseAddress-string} requirements.
*/
function tryParseAddress(string memory input) internal pure returns (bool success, address value) {
return tryParseAddress(input, 0, bytes(input).length);
}
/**
* @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly
* formatted address. See {parseAddress-string-uint256-uint256} requirements.
*/
function tryParseAddress(
string memory input,
uint256 begin,
uint256 end
) internal pure returns (bool success, address value) {
if (end > bytes(input).length || begin > end) return (false, address(0));
bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2("0x"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty
uint256 expectedLength = 40 + hasPrefix.toUint() * 2;
// check that input is the correct length
if (end - begin == expectedLength) {
// length guarantees that this does not overflow, and value is at most type(uint160).max
(bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);
return (s, address(uint160(v)));
} else {
return (false, address(0));
}
}
function _tryParseChr(bytes1 chr) private pure returns (uint8) {
uint8 value = uint8(chr);
// Try to parse `chr`:
// - Case 1: [0-9]
// - Case 2: [a-f]
// - Case 3: [A-F]
// - otherwise not supported
unchecked {
if (value > 47 && value < 58) value -= 48;
else if (value > 96 && value < 103) value -= 87;
else if (value > 64 && value < 71) value -= 55;
else return type(uint8).max;
}
return value;
}
/**
* @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.
*
* WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.
*
* NOTE: This function escapes all unicode characters, and not just the ones in ranges defined in section 2.5 of
* RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). ECMAScript's `JSON.parse` does recover escaped unicode
* characters that are not in this range, but other tooling may provide different results.
*/
function escapeJSON(string memory input) internal pure returns (string memory) {
bytes memory buffer = bytes(input);
bytes memory output = new bytes(2 * buffer.length); // worst case scenario
uint256 outputLength = 0;
for (uint256 i; i < buffer.length; ++i) {
bytes1 char = bytes1(_unsafeReadBytesOffset(buffer, i));
if (((SPECIAL_CHARS_LOOKUP & (1 << uint8(char))) != 0)) {
output[outputLength++] = "\\";
if (char == 0x08) output[outputLength++] = "b";
else if (char == 0x09) output[outputLength++] = "t";
else if (char == 0x0a) output[outputLength++] = "n";
else if (char == 0x0c) output[outputLength++] = "f";
else if (char == 0x0d) output[outputLength++] = "r";
else if (char == 0x5c) output[outputLength++] = "\\";
else if (char == 0x22) {
// solhint-disable-next-line quotes
output[outputLength++] = '"';
}
} else {
output[outputLength++] = char;
}
}
// write the actual length and deallocate unused memory
assembly ("memory-safe") {
mstore(output, outputLength)
mstore(0x40, add(output, shl(5, shr(5, add(outputLength, 63)))))
}
return string(output);
}
/**
* @dev Reads a bytes32 from a bytes array without bounds checking.
*
* NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the
* assembly block as such would prevent some optimizations.
*/
function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {
// This is not memory safe in the general case, but all calls to this private function are within bounds.
assembly ("memory-safe") {
value := mload(add(buffer, add(0x20, offset)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Return the 512-bit addition of two uint256.
*
* The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.
*/
function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
assembly ("memory-safe") {
low := add(a, b)
high := lt(low, a)
}
}
/**
* @dev Return the 512-bit multiplication of two uint256.
*
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
*/
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = high * 2²⁵⁶ + low.
assembly ("memory-safe") {
let mm := mulmod(a, b, not(0))
low := mul(a, b)
high := sub(sub(mm, low), lt(mm, low))
}
}
/**
* @dev Returns the addition of two unsigned integers, with a success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
success = c >= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a - b;
success = c <= a;
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a * b;
assembly ("memory-safe") {
// Only true when the multiplication doesn't overflow
// (c / a == b) || (a == 0)
success := or(eq(div(c, a), b), iszero(a))
}
// equivalent to: success ? c : 0
result = c * SafeCast.toUint(success);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `DIV` opcode returns zero when the denominator is 0.
result := div(a, b)
}
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
success = b > 0;
assembly ("memory-safe") {
// The `MOD` opcode returns zero when the denominator is 0.
result := mod(a, b)
}
}
}
/**
* @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryAdd(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.
*/
function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {
(, uint256 result) = trySub(a, b);
return result;
}
/**
* @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.
*/
function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {
(bool success, uint256 result) = tryMul(a, b);
return ternary(success, result, type(uint256).max);
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
// Handle non-overflow cases, 256 by 256 division.
if (high == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return low / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= high) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [high low].
uint256 remainder;
assembly ("memory-safe") {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
high := sub(high, gt(remainder, low))
low := sub(low, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly ("memory-safe") {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [high low] by twos.
low := div(low, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from high into low.
low |= high * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
// is no longer required.
result = low * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.
*/
function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {
unchecked {
(uint256 high, uint256 low) = mul512(x, y);
if (high >= 1 << n) {
Panic.panic(Panic.UNDER_OVERFLOW);
}
return (high << (256 - n)) | (low >> n);
}
}
/**
* @dev Calculates x * y >> n with full precision, following the selected rounding direction.
*/
function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {
return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// If upper 8 bits of 16-bit half set, add 8 to result
r |= SafeCast.toUint((x >> r) > 0xff) << 3;
// If upper 4 bits of 8-bit half set, add 4 to result
r |= SafeCast.toUint((x >> r) > 0xf) << 2;
// Shifts value right by the current result and use it as an index into this lookup table:
//
// | x (4 bits) | index | table[index] = MSB position |
// |------------|---------|-----------------------------|
// | 0000 | 0 | table[0] = 0 |
// | 0001 | 1 | table[1] = 0 |
// | 0010 | 2 | table[2] = 1 |
// | 0011 | 3 | table[3] = 1 |
// | 0100 | 4 | table[4] = 2 |
// | 0101 | 5 | table[5] = 2 |
// | 0110 | 6 | table[6] = 2 |
// | 0111 | 7 | table[7] = 2 |
// | 1000 | 8 | table[8] = 3 |
// | 1001 | 9 | table[9] = 3 |
// | 1010 | 10 | table[10] = 3 |
// | 1011 | 11 | table[11] = 3 |
// | 1100 | 12 | table[12] = 3 |
// | 1101 | 13 | table[13] = 3 |
// | 1110 | 14 | table[14] = 3 |
// | 1111 | 15 | table[15] = 3 |
//
// The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes.
assembly ("memory-safe") {
r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))
}
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 x) internal pure returns (uint256 r) {
// If value has upper 128 bits set, log2 result is at least 128
r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;
// If upper 64 bits of 128-bit half set, add 64 to result
r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;
// If upper 32 bits of 64-bit half set, add 32 to result
r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;
// If upper 16 bits of 32-bit half set, add 16 to result
r |= SafeCast.toUint((x >> r) > 0xffff) << 4;
// Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8
return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 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.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @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) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(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) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(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) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(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) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
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) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));
}
}
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson.
// Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,
// taking advantage of the most significant (or "sign" bit) in two's complement representation.
// This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,
// the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).
int256 mask = n >> 255;
// A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.
return uint256((n + mask) ^ mask);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_trustedForwarder","type":"address"},{"internalType":"uint256","name":"startId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"string","name":"cancelReasonIpfsCid","type":"string"}],"name":"ElectionCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"votingStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"votingEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationEndTime","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"registerId","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"authProviderId","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"svsId","type":"uint8"},{"indexed":false,"internalType":"string","name":"descriptionIpfsCid","type":"string"},{"indexed":false,"internalType":"bytes","name":"publicKey","type":"bytes"}],"name":"ElectionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"n","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"e","type":"bytes"}],"name":"ElectionRegisterPublicKeySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"yesVotes","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"noVotes","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"invalidVotes","type":"uint256[]"},{"indexed":false,"internalType":"bytes","name":"privateKey","type":"bytes"}],"name":"ElectionResultsPublished","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"enum ElectionStatus","name":"oldStatus","type":"uint8"},{"indexed":false,"internalType":"enum ElectionStatus","name":"newStatus","type":"uint8"}],"name":"ElectionStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"votingStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"votingEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"registrationEndTime","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"registerId","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"authProviderId","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"svsId","type":"uint8"},{"indexed":false,"internalType":"string","name":"descriptionIpfsCid","type":"string"},{"indexed":false,"internalType":"bytes","name":"publicKey","type":"bytes"}],"name":"ElectionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bytes","name":"svsSignature","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"voteEncrypted","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"voteEncryptedUser","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"unblindedElectionToken","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"unblindedSignature","type":"bytes"}],"name":"VoteCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bytes","name":"voteEncrypted","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"voteEncryptedUser","type":"bytes"}],"name":"VoteUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"apId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voterId","type":"uint256"}],"name":"VoterAuthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"registerId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"voterId","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"blindedSignature","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"blindedElectionToken","type":"bytes"}],"name":"VoterRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"apId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"voterIds","type":"uint256[]"}],"name":"VotersAuthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"registerId","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"electionId","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"voterIds","type":"uint256[]"},{"indexed":false,"internalType":"bytes[]","name":"blindedSignatures","type":"bytes[]"},{"indexed":false,"internalType":"bytes[]","name":"blindedElectionTokens","type":"bytes[]"}],"name":"VotersRegistered","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"apName","type":"string"},{"internalType":"string","name":"apUri","type":"string"}],"internalType":"struct AuthorizationProvider","name":"newAp","type":"tuple"}],"name":"addAp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"registerName","type":"string"},{"internalType":"string","name":"registerUri","type":"string"}],"internalType":"struct Register","name":"newRegister","type":"tuple"}],"name":"addRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"svsName","type":"string"},{"internalType":"string","name":"svsUri","type":"string"}],"internalType":"struct SignatureValidationServer","name":"newSvs","type":"tuple"}],"name":"addSvs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"aps","outputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"apName","type":"string"},{"internalType":"string","name":"apUri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256","name":"voterId","type":"uint256"}],"name":"authorizeVoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256[]","name":"voterIds","type":"uint256[]"}],"name":"authorizeVoters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"string","name":"cancelReasonIpfsCid","type":"string"}],"name":"cancelElection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"manualElectionId","type":"uint256"},{"internalType":"uint256","name":"votingStartTime","type":"uint256"},{"internalType":"uint256","name":"votingEndTime","type":"uint256"},{"internalType":"uint256","name":"registrationStartTime","type":"uint256"},{"internalType":"uint256","name":"registrationEndTime","type":"uint256"},{"internalType":"uint8","name":"registerId","type":"uint8"},{"internalType":"uint8","name":"authProviderId","type":"uint8"},{"internalType":"uint8","name":"svsId","type":"uint8"},{"internalType":"string","name":"descriptionIpfsCid","type":"string"},{"internalType":"bytes","name":"publicKey","type":"bytes"}],"name":"createOrUpdateElection","outputs":[{"internalType":"uint256","name":"electionId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"elections","outputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256","name":"votingStartTime","type":"uint256"},{"internalType":"uint256","name":"votingEndTime","type":"uint256"},{"internalType":"uint256","name":"totalVotes","type":"uint256"},{"internalType":"uint256","name":"totalAuthorized","type":"uint256"},{"internalType":"uint256","name":"totalRegistered","type":"uint256"},{"internalType":"uint8","name":"registerId","type":"uint8"},{"internalType":"uint8","name":"authProviderId","type":"uint8"},{"internalType":"uint8","name":"svsId","type":"uint8"},{"internalType":"enum ElectionStatus","name":"status","type":"uint8"},{"internalType":"string","name":"cancelReasonIpfsCid","type":"string"},{"internalType":"string","name":"descriptionIpfsCid","type":"string"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"bytes","name":"privateKey","type":"bytes"},{"components":[{"internalType":"bytes","name":"n","type":"bytes"},{"internalType":"bytes","name":"e","type":"bytes"}],"internalType":"struct RsaPublicKeyRaw","name":"registerPubKey","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"}],"name":"endElection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextElectionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256[]","name":"yesVotes","type":"uint256[]"},{"internalType":"uint256[]","name":"noVotes","type":"uint256[]"},{"internalType":"uint256[]","name":"invalidVotes","type":"uint256[]"},{"internalType":"bytes","name":"privateKey","type":"bytes"}],"name":"publishElectionResults","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256","name":"voterId","type":"uint256"},{"internalType":"bytes","name":"blindedSignature","type":"bytes"},{"internalType":"bytes","name":"blindedElectionToken","type":"bytes"}],"name":"registerVoter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"uint256[]","name":"voterIds","type":"uint256[]"},{"internalType":"bytes[]","name":"blindedSignatures","type":"bytes[]"},{"internalType":"bytes[]","name":"blindedElectionTokens","type":"bytes[]"}],"name":"registerVoters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"registers","outputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"registerName","type":"string"},{"internalType":"string","name":"registerUri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"bytes","name":"n","type":"bytes"},{"internalType":"bytes","name":"e","type":"bytes"}],"name":"setElectionRegisterPublicKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"}],"name":"startElection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"svss","outputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"svsName","type":"string"},{"internalType":"string","name":"svsUri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"electionId","type":"uint256"},{"internalType":"address","name":"voter","type":"address"},{"internalType":"bytes","name":"svsSignature","type":"bytes"},{"internalType":"bytes","name":"voteEncrypted","type":"bytes"},{"internalType":"bytes","name":"voteEncryptedUser","type":"bytes"},{"internalType":"bytes","name":"unblindedElectionToken","type":"bytes"},{"internalType":"bytes","name":"unblindedSignature","type":"bytes"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a0604052346100395761001a610014610133565b906101b2565b61002261003e565b6156d56103808239608051816139f201526156d590f35b610044565b60405190565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b9061007090610048565b810190811060018060401b0382111761008857604052565b610052565b906100a061009961003e565b9283610066565b565b5f80fd5b60018060a01b031690565b6100ba906100a6565b90565b6100c6816100b1565b036100cd57565b5f80fd5b905051906100de826100bd565b565b90565b6100ec816100e0565b036100f357565b5f80fd5b90505190610104826100e3565b565b919060408382031261012e578061012261012b925f86016100d1565b936020016100f7565b90565b6100a2565b610151615a55803803806101468161008d565b928339810190610106565b9091565b5f1b90565b906101665f1991610155565b9181191691161790565b90565b61018761018261018c926100e0565b610170565b6100e0565b90565b90565b906101a76101a26101ae92610173565b61018f565b825461015a565b9055565b906101c16101c89233906101ca565b6001610192565b565b906101d490610226565b608052565b90565b6101f06101eb6101f5926101d9565b610170565b6100a6565b90565b610201906101dc565b90565b61020d906100b1565b9052565b9190610224905f60208501940190610204565b565b8061024161023b6102365f6101f8565b6100b1565b916100b1565b146102515761024f90610320565b565b61027461025d5f6101f8565b5f918291631e4fbdf760e01b835260048301610211565b0390fd5b5f1c90565b60018060a01b031690565b61029461029991610278565b61027d565b90565b6102a69054610288565b90565b906102ba60018060a01b0391610155565b9181191691161790565b6102d86102d36102dd926100a6565b610170565b6100a6565b90565b6102e9906102c4565b90565b6102f5906102e0565b90565b90565b9061031061030b610317926102ec565b6102f8565b82546102a9565b9055565b5f0190565b6103295f61029c565b610333825f6102fb565b906103676103617f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0936102ec565b916102ec565b9161037061003e565b8061037a8161031b565b0390a356fe6102006040526004361015610014575b611a89565b61001e5f356101bd565b80631c700694146101b8578063256fab2f146101b35780633ad71ded146101ae5780634a17ce11146101a95780635313837b146101a457806354fd4d501461019f578063572b6c051461019a5780635e6fef011461019557806362dc5b37146101905780636d32dc4b1461018b578063715018a6146101865780637a62e918146101815780637b7abbdc1461017c5780637da0a877146101775780638628a8bc1461017257806388c7c0731461016d5780638b9f341b146101685780638da5cb5b146101635780639c98bcbb1461015e578063a4133feb14610159578063a67e65c314610154578063ae27a99c1461014f578063e1c67af41461014a578063ed08dc3614610145578063f2fde38b146101405763ffa1ad740361000f57611a54565b6119a9565b61196c565b611879565b6117f0565b61178a565b611701565b611665565b611630565b6115fc565b61157d565b6114c0565b611341565b6112f9565b6111f7565b6110ef565b6110bc565b611088565b610fb7565b610ada565b610a60565b610a13565b610973565b610872565b61059a565b610377565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b90565b6101e1816101d5565b036101e857565b5f80fd5b905035906101f9826101d8565b565b60018060a01b031690565b61020f906101fb565b90565b61021b81610206565b0361022257565b5f80fd5b9050359061023382610212565b565b5f80fd5b5f80fd5b5f80fd5b909182601f8301121561027b5781359167ffffffffffffffff831161027657602001926001830284011161027157565b61023d565b610239565b610235565b9160e08383031261036d57610297825f85016101ec565b926102a58360208301610226565b92604082013567ffffffffffffffff811161036857816102c6918401610241565b929093606082013567ffffffffffffffff811161036357836102e9918401610241565b929093608082013567ffffffffffffffff811161035e578161030c918401610241565b92909360a082013567ffffffffffffffff8111610359578361032f918401610241565b92909360c082013567ffffffffffffffff8111610354576103509201610241565b9091565b6101d1565b6101d1565b6101d1565b6101d1565b6101d1565b6101cd565b5f0190565b346103b55761039f61038a366004610280565b9a9990999891989792979693969594956123c0565b6103a76101c3565b806103b181610372565b0390f35b6101c9565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b906103e6906103be565b810190811067ffffffffffffffff82111761040057604052565b6103c8565b906104186104116101c3565b92836103dc565b565b5f80fd5b60ff1690565b61042d8161041e565b0361043457565b5f80fd5b9050359061044582610424565b565b5f80fd5b67ffffffffffffffff8111610469576104656020916103be565b0190565b6103c8565b90825f939282370152565b9092919261048e6104898261044b565b610405565b938185526020850190828401116104aa576104a89261046e565b565b610447565b9080601f830112156104cd578160206104ca93359101610479565b90565b610235565b919091608081840312610560576104e96080610405565b926104f6815f8401610438565b5f8501526105078160208401610226565b6020850152604082013567ffffffffffffffff811161055b578161052c9184016104af565b6040850152606082013567ffffffffffffffff81116105565761054f92016104af565b6060830152565b61041a565b61041a565b6103ba565b90602082820312610595575f82013567ffffffffffffffff81116105905761058d92016104d2565b90565b6101d1565b6101cd565b346105c8576105b26105ad366004610565565b612ce1565b6105ba6101c3565b806105c481610372565b0390f35b6101c9565b906020828203126105e6576105e3915f01610438565b90565b6101cd565b90565b6106026105fd6106079261041e565b6105eb565b61041e565b90565b90610614906105ee565b5f5260205260405f2090565b5f1c90565b60ff1690565b61063761063c91610620565b610625565b90565b610649905461062b565b90565b60081c90565b60018060a01b031690565b61066961066e9161064c565b610652565b90565b61067b905461065d565b90565b634e487b7160e01b5f52602260045260245ffd5b90600160028304921680156106b2575b60208310146106ad57565b61067e565b91607f16916106a2565b60209181520190565b5f5260205f2090565b905f92918054906106e86106e183610692565b80946106bc565b916001811690815f1461073f5750600114610703575b505050565b61071091929394506106c5565b915f925b81841061072757505001905f80806106fe565b60018160209295939554848601520191019290610714565b92949550505060ff19168252151560200201905f80806106fe565b90610764916106ce565b90565b90610787610780926107776101c3565b9384809261075a565b03836103dc565b565b61079490600361060a565b906107a05f830161063f565b916107ac5f8201610671565b916107c560026107be60018501610767565b9301610767565b90565b6107d19061041e565b9052565b6107de90610206565b9052565b5190565b60209181520190565b90825f9392825e0152565b61081961082260209361082793610810816107e2565b938480936107e6565b958691016107ef565b6103be565b0190565b92906108619161085461086f969461084a60808801945f8901906107c8565b60208701906107d5565b84820360408601526107fa565b9160608184039101526107fa565b90565b346108a6576108a261088d6108883660046105cd565b610789565b906108999492946101c3565b9485948561082b565b0390f35b6101c9565b919091608081840312610939576108c26080610405565b926108cf815f8401610438565b5f8501526108e08160208401610226565b6020850152604082013567ffffffffffffffff811161093457816109059184016104af565b6040850152606082013567ffffffffffffffff811161092f5761092892016104af565b6060830152565b61041a565b61041a565b6103ba565b9060208282031261096e575f82013567ffffffffffffffff81116109695761096692016108ab565b90565b6101d1565b6101cd565b346109a15761098b61098636600461093e565b612e04565b6109936101c3565b8061099d81610372565b0390f35b6101c9565b5f9103126109b057565b6101cd565b1c90565b90565b6109cc9060086109d193026109b5565b6109b9565b90565b906109df91546109bc565b90565b6109ee60015f906109d4565b90565b6109fa906101d5565b9052565b9190610a11905f602085019401906109f1565b565b34610a4357610a233660046109a6565b610a3f610a2e6109e2565b610a366101c3565b918291826109fe565b0390f35b6101c9565b610a5d9160208201915f8184039101526107fa565b90565b34610a9057610a703660046109a6565b610a8c610a7b612e14565b610a836101c3565b91829182610a48565b0390f35b6101c9565b90602082820312610aae57610aab915f01610226565b90565b6101cd565b151590565b610ac190610ab3565b9052565b9190610ad8905f60208501940190610ab8565b565b34610b0a57610b06610af5610af0366004610a95565b612e2c565b610afd6101c3565b91829182610ac5565b0390f35b6101c9565b90602082820312610b2857610b25915f016101ec565b90565b6101cd565b610b41610b3c610b46926101d5565b6105eb565b6101d5565b90565b90610b5390610b2d565b5f5260205260405f2090565b610b6b610b7091610620565b6109b9565b90565b610b7d9054610b5f565b90565b610b8c610b919161064c565b610625565b90565b610b9e9054610b80565b90565b60101c90565b610bb3610bb891610ba1565b610625565b90565b610bc59054610ba7565b90565b60181c90565b60ff1690565b610be0610be591610bc8565b610bce565b90565b610bf29054610bd4565b90565b60209181520190565b5f5260205f2090565b905f9291805490610c21610c1a83610692565b8094610bf5565b916001811690815f14610c785750600114610c3c575b505050565b610c499192939450610bfe565b915f925b818410610c6057505001905f8080610c37565b60018160209295939554848601520191019290610c4d565b92949550505060ff19168252151560200201905f8080610c37565b90610c9d91610c07565b90565b90610cc0610cb992610cb06101c3565b93848092610c93565b03836103dc565b565b52565b610ccf6040610405565b90565b90610d09610d006001610ce3610cc5565b94610cfa610cf25f8301610ca0565b5f8801610cc2565b01610ca0565b60208401610cc2565b565b610d16906005610b49565b610d215f8201610b73565b91610d2e60018301610b73565b91610d3b60028201610b73565b91610d4860038301610b73565b91610d5560048201610b73565b91610d6260058301610b73565b91610d6f6006820161063f565b91610d7c60068301610b94565b91610d8960068201610bbb565b91610d9660068301610be8565b91610da360088201610767565b91610db060098301610767565b91610dbd600a8201610ca0565b91610dd6600c610dcf600b8501610ca0565b9301610cd2565b90565b634e487b7160e01b5f52602160045260245ffd5b60051115610df757565b610dd9565b90610e0682610ded565b565b610e1190610dfc565b90565b610e1d90610e08565b9052565b5190565b60209181520190565b610e4d610e56602093610e5b93610e4481610e21565b93848093610e25565b958691016107ef565b6103be565b0190565b610e7e610e87602093610e8c93610e7581610e21565b93848093610bf5565b958691016107ef565b6103be565b0190565b610ebe916020610ead604083015f8501518482035f860152610e5f565b920151906020818403910152610e5f565b90565b809e9d9c9b9a989694929997959391996101e082019a5f8301610ee3916109f1565b60208201610ef0916109f1565b604001610efc916109f1565b60608d01610f09916109f1565b60808c01610f16916109f1565b60a08b01610f23916109f1565b60c08a01610f30916107c8565b60e08901610f3d916107c8565b6101008801610f4b916107c8565b6101208701610f5991610e14565b858103610140870152610f6b916107fa565b848103610160860152610f7d916107fa565b838103610180850152610f8f91610e2e565b8281036101a0840152610fa191610e2e565b90808203906101c00152610fb491610e90565b90565b34610ffe5736610fc8906004610b0f565b610fd190610d0b565b9a610fec9e9c9e9a919a9992999893989794979695966101c3565b9e8f9e8f9e610ffa9f610ec1565b0390f35b6101c9565b909182601f8301121561103d5781359167ffffffffffffffff831161103857602001926020830284011161103357565b61023d565b610239565b610235565b9190916040818403126110835761105b835f83016101ec565b92602082013567ffffffffffffffff811161107e5761107a9201611003565b9091565b6101d1565b6101cd565b346110b7576110a161109b366004611042565b91612f37565b6110a96101c3565b806110b381610372565b0390f35b6101c9565b346110ea576110d46110cf366004610b0f565b613441565b6110dc6101c3565b806110e681610372565b0390f35b6101c9565b3461111d576110ff3660046109a6565b611107613471565b61110f6101c3565b8061111981610372565b0390f35b6101c9565b909182601f8301121561115c5781359167ffffffffffffffff831161115757602001926020830284011161115257565b61023d565b610239565b610235565b9190916080818403126111f25761117a835f83016101ec565b92602082013567ffffffffffffffff81116111ed578161119b918401611003565b929093604082013567ffffffffffffffff81116111e857836111be918401611122565b929093606082013567ffffffffffffffff81116111e3576111df9201611122565b9091565b6101d1565b6101d1565b6101d1565b6101cd565b3461122c5761121661120a366004611161565b95949094939193613745565b61121e6101c3565b8061122881610372565b0390f35b6101c9565b9190916080818403126112bf576112486080610405565b92611255815f8401610438565b5f8501526112668160208401610226565b6020850152604082013567ffffffffffffffff81116112ba578161128b9184016104af565b6040850152606082013567ffffffffffffffff81116112b5576112ae92016104af565b6060830152565b61041a565b61041a565b6103ba565b906020828203126112f4575f82013567ffffffffffffffff81116112ef576112ec9201611231565b90565b6101d1565b6101cd565b346113275761131161130c3660046112c4565b6139d8565b6113196101c3565b8061132381610372565b0390f35b6101c9565b919061133f905f602085019401906107d5565b565b34611371576113513660046109a6565b61136d61135c6139e7565b6113646101c3565b9182918261132c565b0390f35b6101c9565b67ffffffffffffffff8111611394576113906020916103be565b0190565b6103c8565b909291926113ae6113a982611376565b610405565b938185526020850190828401116113ca576113c89261046e565b565b610447565b9080601f830112156113ed578160206113ea93359101611399565b90565b610235565b90610140828203126114bb5761140a815f84016101ec565b9261141882602085016101ec565b9261142683604083016101ec565b9261143481606084016101ec565b9261144282608085016101ec565b926114508360a08301610438565b9261145e8160c08401610438565b9261146c8260e08501610438565b9261010081013567ffffffffffffffff81116114b6578361148e9183016104af565b9261012082013567ffffffffffffffff81116114b1576114ae92016113cf565b90565b6101d1565b6101d1565b6101cd565b346114fd576114f96114e86114d63660046113f2565b98979097969196959295949394614435565b6114f06101c3565b918291826109fe565b0390f35b6101c9565b91906080838203126115785761151a815f85016101ec565b9261152882602083016101ec565b92604082013567ffffffffffffffff81116115735783611549918401610241565b929093606082013567ffffffffffffffff811161156e5761156a9201610241565b9091565b6101d1565b6101d1565b6101cd565b346115b25761159c611590366004611502565b94939093929192614452565b6115a46101c3565b806115ae81610372565b0390f35b6101c9565b9190916040818403126115f7576115d0835f83016101ec565b92602082013567ffffffffffffffff81116115f2576115ef92016104af565b90565b6101d1565b6101cd565b3461162b5761161561160f3660046115b7565b906146ae565b61161d6101c3565b8061162781610372565b0390f35b6101c9565b34611660576116403660046109a6565b61165c61164b6146db565b6116536101c3565b9182918261132c565b0390f35b6101c9565b346116935761167d611678366004610b0f565b6148a5565b6116856101c3565b8061168f81610372565b0390f35b6101c9565b916060838303126116fc576116af825f85016101ec565b92602081013567ffffffffffffffff81116116f757836116d09183016113cf565b92604082013567ffffffffffffffff81116116f2576116ef92016113cf565b90565b6101d1565b6101d1565b6101cd565b346117305761171a611714366004611698565b91614a2f565b6117226101c3565b8061172c81610372565b0390f35b6101c9565b9061173f906105ee565b5f5260205260405f2090565b611756906004611735565b906117625f830161063f565b9161176e5f8201610671565b91611787600261178060018501610767565b9301610767565b90565b346117be576117ba6117a56117a03660046105cd565b61174b565b906117b19492946101c3565b9485948561082b565b0390f35b6101c9565b91906040838203126117eb57806117df6117e8925f86016101ec565b936020016101ec565b90565b6101cd565b3461181f576118096118033660046117c3565b90614b64565b6118116101c3565b8061181b81610372565b0390f35b6101c9565b9061182e906105ee565b5f5260205260405f2090565b611845906002611824565b906118515f830161063f565b9161185d5f8201610671565b91611876600261186f60018501610767565b9301610767565b90565b346118ad576118a961189461188f3660046105cd565b61183a565b906118a09492946101c3565b9485948561082b565b0390f35b6101c9565b60a081830312611967576118c8825f83016101ec565b92602082013567ffffffffffffffff811161196257836118e9918401611003565b929093604082013567ffffffffffffffff811161195d578161190c918401611003565b929093606082013567ffffffffffffffff8111611958578361192f918401611003565b929093608082013567ffffffffffffffff81116119535761195092016113cf565b90565b6101d1565b6101d1565b6101d1565b6101d1565b6101cd565b346119a45761198e61197f3660046118b2565b96959095949194939293614f87565b6119966101c3565b806119a081610372565b0390f35b6101c9565b346119d7576119c16119bc366004610a95565b614ffe565b6119c96101c3565b806119d381610372565b0390f35b6101c9565b906119ee6119e98361044b565b610405565b918252565b5f7f302e312e30000000000000000000000000000000000000000000000000000000910152565b611a2460056119dc565b90611a31602083016119f3565b565b611a3b611a1a565b90565b611a46611a33565b90565b611a51611a3e565b90565b34611a8457611a643660046109a6565b611a80611a6f611a49565b611a776101c3565b91829182610a48565b0390f35b6101c9565b5f80fd5b90565b90565b611aa7611aa2611aac92611a90565b6105eb565b6101d5565b90565b5f7f456c656374696f6e20756e6b6e6f776e00000000000000000000000000000000910152565b611ae360106020926107e6565b611aec81611aaf565b0190565b611b059060208101905f818303910152611ad6565b90565b15611b0f57565b611b176101c3565b62461bcd60e51b815280611b2d60048201611af0565b0390fd5b5090565b90565b611b4c611b47611b5192611b35565b6105eb565b6101d5565b90565b90565b611b6b611b66611b7092611b54565b6105eb565b6101d5565b90565b5f7f496e76616c696420766f7465456e63727970746564206c656e67746800000000910152565b611ba7601c6020926107e6565b611bb081611b73565b0190565b611bc99060208101905f818303910152611b9a565b90565b15611bd357565b611bdb6101c3565b62461bcd60e51b815280611bf160048201611bb4565b0390fd5b5f7f496e76616c696420766f7465456e6372797074656455736572206c656e677468910152565b611c28602080926107e6565b611c3181611bf5565b0190565b611c4a9060208101905f818303910152611c1c565b90565b15611c5457565b611c5c6101c3565b62461bcd60e51b815280611c7260048201611c35565b0390fd5b5f7f456c656374696f6e206973206e6f742061637469766500000000000000000000910152565b611caa60166020926107e6565b611cb381611c76565b0190565b611ccc9060208101905f818303910152611c9d565b90565b15611cd657565b611cde6101c3565b62461bcd60e51b815280611cf460048201611cb7565b0390fd5b5f7f456c656374696f6e20656e646564000000000000000000000000000000000000910152565b611d2c600e6020926107e6565b611d3581611cf8565b0190565b611d4e9060208101905f818303910152611d1f565b90565b15611d5857565b611d606101c3565b62461bcd60e51b815280611d7660048201611d39565b0390fd5b90565b611d91611d8c611d9692611d7a565b6105eb565b6101d5565b90565b611dad611da8611db2926101fb565b6105eb565b6101fb565b90565b611dbe90611d99565b90565b611dca90611db5565b90565b90611dd790611dc1565b5f5260205260405f2090565b60ff1690565b611df5611dfa91610620565b611de3565b90565b611e079054611de9565b90565b5f7f766f74657220756e6b6e6f776e00000000000000000000000000000000000000910152565b611e3e600d6020926107e6565b611e4781611e0a565b0190565b611e609060208101905f818303910152611e31565b90565b15611e6a57565b611e726101c3565b62461bcd60e51b815280611e8860048201611e4b565b0390fd5b9190611ea681611e9f81611eab95610e25565b809561046e565b6103be565b0190565b9290611ecb90611ed9959360408601918683035f880152611e8c565b926020818503910152611e8c565b90565b611ef0611eeb611ef592611a90565b6105eb565b6101fb565b90565b611f0190611edc565b90565b5f7f535653206e6f7420737065636966696564000000000000000000000000000000910152565b611f3860116020926107e6565b611f4181611f04565b0190565b611f5a9060208101905f818303910152611f2b565b90565b15611f6457565b611f6c6101c3565b62461bcd60e51b815280611f8260048201611f45565b0390fd5b90565b611f9d611f98611fa292611f86565b6105eb565b6101d5565b90565b60207f656e677468000000000000000000000000000000000000000000000000000000917f496e76616c696420756e626c696e646564456c656374696f6e546f6b656e206c5f8201520152565b611fff60256040926107e6565b61200881611fa5565b0190565b6120219060208101905f818303910152611ff2565b90565b1561202b57565b6120336101c3565b62461bcd60e51b8152806120496004820161200c565b0390fd5b60207f6800000000000000000000000000000000000000000000000000000000000000917f496e76616c696420756e626c696e6465645369676e6174757265206c656e67745f8201520152565b6120a760216040926107e6565b6120b08161204d565b0190565b6120c99060208101905f81830391015261209a565b90565b156120d357565b6120db6101c3565b62461bcd60e51b8152806120f1600482016120b4565b0390fd5b5f7f416c726561647920766f74656400000000000000000000000000000000000000910152565b612129600d6020926107e6565b612132816120f5565b0190565b61214b9060208101905f81830391015261211c565b90565b1561215557565b61215d6101c3565b62461bcd60e51b81528061217360048201612136565b0390fd5b989694916121d696916121e49b99956121c8956121ac6121ba9460208f6121a560c08201975f8301906109f1565b01906107d5565b8c6040818503910152611e8c565b9189830360608b0152611e8c565b918683036080880152611e8c565b9260a0818503910152611e8c565b90565b60200190565b6121f8913691611399565b90565b5f7f53696720696e76616c6964000000000000000000000000000000000000000000910152565b61222f600b6020926107e6565b612238816121fb565b0190565b6122519060208101905f818303910152612222565b90565b1561225b57565b6122636101c3565b62461bcd60e51b8152806122796004820161223c565b0390fd5b90565b61229461228f6122999261227d565b6105eb565b6101d5565b90565b634e487b7160e01b5f52601160045260245ffd5b6122bf6122c5919392936101d5565b926101d5565b82018092116122d057565b61229c565b5f1b90565b906122e65f19916122d5565b9181191691161790565b90565b9061230861230361230f92610b2d565b6122f0565b82546122da565b9055565b9061231f60ff916122d5565b9181191691161790565b61233290610ab3565b90565b90565b9061234d61234861235492612329565b612335565b8254612313565b9055565b989694916123a1936123bd9b99956123848c612393946123af9b9660a08301925f818503910152611e8c565b918c6020818503910152611e8c565b9189830360408b0152611e8c565b918683036060880152611e8c565b926080818503910152611e8c565b90565b9a989694929190999795939a60e0526101c0526080526101e0526101a0526101005261012052610140526101605261018052612408612403600560e05190610b49565b611a8d565b60c05261243561241c600160c05101610b73565b61242e6124285f611a93565b916101d5565b1415611b08565b612443826101e05190611b31565b612457612451610100611b38565b916101d5565b14801561282b575b61246890611bcc565b6124796101a0516101005190611b31565b61248b6124855f611a93565b916101d5565b11806127f9575b61249b90611c4d565b6124c56124ac600660c05101610be8565b6124bf6124b96001610dfc565b91610dfc565b14611ccf565b6124ef6124d6600260c05101610b73565b6124e86124e2426101d5565b916101d5565b1015611d51565b6124ff6101c05160805190611b31565b61251261250c6041611d7d565b916101d5565b145f14612766576126796126746125425f61253c6003612536600660c05101610bbb565b9061060a565b01610671565b6125678161256061255a6125555f611ef8565b610206565b91610206565b1415611f5d565b61259461257b610120516101405190611b31565b61258e6125886020611f89565b916101d5565b14612024565b6125a5610160516101805190611b31565b6125b96125b3610100611b38565b916101d5565b1460a05260a05115612738575b6125d160a0516120cc565b6125fa6125f56125ef6125ea600760c051018890611dcd565b611dfd565b15610ab3565b61214e565b60e051612649859161263a886101e0516101a05161010051610120519061014051926101605194610180519661262e6101c3565b9b8c9a60208c01612177565b602082018103825203826103dc565b61265b61265582610e21565b916121e7565b2061266e6101c0519260805190936121ed565b9061501d565b612254565b6126a46126866001612280565b61269e600360c051019161269983610b73565b6122b0565b906122f3565b6126be60016126b9600760c051018490611dcd565b612338565b60e0516101c0519260805190936127326101e0516101a051610100516101205161014051916101605193610180519561272061271a7f15dda67fb238757385e33f7875e964eed8cce6e309dc10bb713065238ec469289c610b2d565b9c611dc1565b9c6127296101c3565b9a8b9a8b612358565b0390a35b565b612749610160516101805190611b31565b61275d612757610200611b57565b916101d5565b1460a0526125c6565b5061278e612789612784600760c0510161277e615009565b90611dcd565b611dfd565b611e63565b60e0519061279a615009565b90916101e0516101a051936127f1610100516127df6127d97fddbd2b140ce7195be58239163e94257d7dfa3ba0e91e63d09e3ee97d9eacec7c96610b2d565b96611dc1565b966127e86101c3565b94859485611eaf565b0390a3612736565b5061249b61280e6101a0516101005190611b31565b61282261281c610200611b57565b916101d5565b11159050612492565b5061246861283d836101e05190611b31565b61285161284b610200611b57565b916101d5565b14905061245f565b61286a9061286561504e565b612c4c565b565b612876905161041e565b90565b5f7f496420616c726561647920757365640000000000000000000000000000000000910152565b6128ad600f6020926107e6565b6128b681612879565b0190565b6128cf9060208101905f8183039101526128a0565b90565b156128d957565b6128e16101c3565b62461bcd60e51b8152806128f7600482016128ba565b0390fd5b6129059051610206565b90565b5f7f4e6f206f776e6572207370656369666965640000000000000000000000000000910152565b61293c60126020926107e6565b61294581612908565b0190565b61295e9060208101905f81830391015261292f565b90565b1561296857565b6129706101c3565b62461bcd60e51b81528061298660048201612949565b0390fd5b90565b906129a261299d6129a9926105ee565b61298a565b8254612313565b9055565b60081b90565b906129c6610100600160a81b03916129ad565b9181191691161790565b90565b906129e86129e36129ef92611dc1565b6129d0565b82546129b3565b9055565b5190565b601f602091010490565b1b90565b91906008612a20910291612a1a5f1984612a01565b92612a01565b9181191691161790565b9190612a40612a3b612a4893610b2d565b6122f0565b908354612a05565b9055565b5f90565b612a6291612a5c612a4c565b91612a2a565b565b5b818110612a70575050565b80612a7d5f600193612a50565b01612a65565b9190601f8111612a93575b505050565b612a9f612ac4936106c5565b906020612aab846129f7565b83019310612acc575b612abd906129f7565b0190612a64565b5f8080612a8e565b9150612abd81929050612ab4565b90612aea905f19906008026109b5565b191690565b81612af991612ada565b906002021790565b90612b0b816107e2565b9067ffffffffffffffff8211612bcb57612b2f82612b298554610692565b85612a83565b602090601f8311600114612b6357918091612b52935f92612b57575b5050612aef565b90555b565b90915001515f80612b4b565b601f19831691612b72856106c5565b925f5b818110612bb357509160029391856001969410612b99575b50505002019055612b55565b612ba9910151601f841690612ada565b90555f8080612b8d565b91936020600181928787015181550195019201612b75565b6103c8565b90612bda91612b01565b565b90612c3860606002612c3e94612bff5f8201612bf95f880161286c565b9061298d565b612c175f8201612c11602088016128fb565b906129d3565b612c3060018201612c2a604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90612c4a91612bdc565b565b612cdf90612c93612c735f612c6d6002612c6783870161286c565b90611824565b01610671565b612c8d612c87612c825f611ef8565b610206565b91610206565b146128d2565b612cc3612ca2602083016128fb565b612cbc612cb6612cb15f611ef8565b610206565b91610206565b1415612961565b612cda81612cd45f6002920161286c565b90611824565b612c40565b565b612cea90612859565b565b612cfd90612cf861504e565b612d6f565b565b90612d5b60606002612d6194612d225f8201612d1c5f880161286c565b9061298d565b612d3a5f8201612d34602088016128fb565b906129d3565b612d5360018201612d4d604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90612d6d91612cff565b565b612e0290612db6612d965f612d906004612d8a83870161286c565b90611735565b01610671565b612db0612daa612da55f611ef8565b610206565b91610206565b146128d2565b612de6612dc5602083016128fb565b612ddf612dd9612dd45f611ef8565b610206565b91610206565b1415612961565b612dfd81612df75f6004920161286c565b90611735565b612d63565b565b612e0d90612cec565b565b606090565b612e1c612e0f565b50612e25611a3e565b90565b5f90565b612e34612e28565b50612e4e612e48612e436139e7565b610206565b91610206565b1490565b5f7f4f6e6c79204150204f776e657200000000000000000000000000000000000000910152565b612e86600d6020926107e6565b612e8f81612e52565b0190565b612ea89060208101905f818303910152612e79565b90565b15612eb257565b612eba6101c3565b62461bcd60e51b815280612ed060048201612e93565b0390fd5b5090565b60209181520190565b5f80fd5b9037565b909182612ef591612ed8565b9160018060fb1b038111612f185782916020612f149202938491612ee5565b0190565b612ee1565b9091612f349260208301925f818503910152612ee9565b90565b612f4e6006612f4860058490610b49565b01610b94565b612f7f33612f79612f73612f6e5f612f6860048890611735565b01610671565b610206565b91610206565b14612eab565b612fb2612f996001612f9360058690610b49565b01610b73565b612fab612fa55f611a93565b916101d5565b1415611b08565b612fe7612fc0848690612ed4565b612fe16004612fd160058790610b49565b0191612fdc83610b73565b6122b0565b906122f3565b90919261301d6130177f47550b38d402ab5b8c36108531d53c27431e781a73ddd07f9812b44dcee47da7936105ee565b93610b2d565b936130326130296101c3565b92839283612f1d565b0390a3565b6130489061304361504e565b6132d0565b565b5f7f4e6f742070656e64696e67000000000000000000000000000000000000000000910152565b61307e600b6020926107e6565b6130878161304a565b0190565b6130a09060208101905f818303910152613071565b90565b156130aa57565b6130b26101c3565b62461bcd60e51b8152806130c86004820161308b565b0390fd5b5f7f746f6f206561726c790000000000000000000000000000000000000000000000910152565b61310060096020926107e6565b613109816130cc565b0190565b6131229060208101905f8183039101526130f3565b90565b1561312c57565b6131346101c3565b62461bcd60e51b81528061314a6004820161310d565b0390fd5b5f7f746f6f206c617465000000000000000000000000000000000000000000000000910152565b61318260086020926107e6565b61318b8161314e565b0190565b6131a49060208101905f818303910152613175565b90565b156131ae57565b6131b66101c3565b62461bcd60e51b8152806131cc6004820161318f565b0390fd5b6131da9054610692565b90565b5f7f5265676973746572204b65792072657175697265640000000000000000000000910152565b61321160156020926107e6565b61321a816131dd565b0190565b6132339060208101905f818303910152613204565b90565b1561323d57565b6132456101c3565b62461bcd60e51b81528061325b6004820161321e565b0390fd5b60181b90565b9061327463ff0000009161325f565b9181191691161790565b61328790610dfc565b90565b90565b906132a261329d6132a99261327e565b61328a565b8254613265565b9055565b9160206132ce9294936132c760408201965f830190610e14565b0190610e14565b565b6132e46132df60058390610b49565b611a8d565b9061330d6132f460018401610b73565b6133066133005f611a93565b916101d5565b1415611b08565b61333461331c60068401610be8565b61332e6133285f610dfc565b91610dfc565b146130a3565b61335c61334360018401610b73565b61335561334f426101d5565b916101d5565b1115613125565b61338361336b60028401610b73565b61337d613377426101d5565b916101d5565b116131a7565b6133915f600c8401016131d0565b6133a361339d5f611a93565b916101d5565b1180613414575b6133b390613236565b6133ce6133c260068401610be8565b9260066001910161328d565b60016133fa7f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b9261340f6134066101c3565b928392836132ad565b0390a2565b506133b36134276001600c8501016131d0565b6134396134335f611a93565b916101d5565b1190506133aa565b61344a90613037565b565b61345461504e565b61345c61345e565b565b61346f61346a5f611ef8565b6150d7565b565b61347961344c565b565b5f7f4f6e6c79205265676973746572204f776e657200000000000000000000000000910152565b6134af60136020926107e6565b6134b88161347b565b0190565b6134d19060208101905f8183039101526134a2565b90565b156134db57565b6134e36101c3565b62461bcd60e51b8152806134f9600482016134bc565b0390fd5b5090565b5f7f426c696e646564205369676e6174757265207265717569726564000000000000910152565b613535601a6020926107e6565b61353e81613501565b0190565b6135579060208101905f818303910152613528565b90565b1561356157565b6135696101c3565b62461bcd60e51b81528061357f60048201613542565b0390fd5b5f7f766f746572496473207265717569726564000000000000000000000000000000910152565b6135b760116020926107e6565b6135c081613583565b0190565b6135d99060208101905f8183039101526135aa565b90565b156135e357565b6135eb6101c3565b62461bcd60e51b815280613601600482016135c4565b0390fd5b60209181520190565b90565b919061362b816136248161363095610bf5565b809561046e565b6103be565b0190565b9061363f9291613611565b90565b5f80fd5b5f80fd5b5f80fd5b903560016020038236030381121561368f57016020813591019167ffffffffffffffff821161368a57600182023603831361368557565b613646565b613642565b61364a565b60200190565b91816136a591613605565b90816136b66020830284019461360e565b92835f925b8484106136cb5750505050505090565b90919293949560206136f76136f183856001950388526136eb8b8861364e565b90613634565b98613694565b9401940192949391906136bb565b9492909361372661374297956137349460608901918983035f8b0152612ee9565b91868303602088015261369a565b92604081850391015261369a565b90565b9395946138bb9195613764600661375e60058990610b49565b0161063f565b6137953361378f6137896137845f61377e60028890611824565b01610671565b610206565b91610206565b146134d4565b6137bb6137a3878b906134fd565b6137b56137af5f611a93565b916101d5565b1161355a565b6137e16137c98484906134fd565b6137db6137d55f611a93565b916101d5565b1161355a565b6138076137ef898790612ed4565b6138016137fb5f611a93565b916101d5565b116135dc565b61383a613821600161381b60058b90610b49565b01610b73565b61383361382d5f611a93565b916101d5565b1415611b08565b61386e613848898790612ed4565b6138686005613858818c90610b49565b019161386383610b73565b6122b0565b906122f3565b95969394979190916138a96138a37ffed4b441535e6743c1c93426bb96dd86fb223583d3da43316d9d7a552474d32b986105ee565b98610b2d565b986138b26101c3565b96879687613705565b0390a3565b6138d1906138cc61504e565b613943565b565b9061392f60606002613935946138f65f82016138f05f880161286c565b9061298d565b61390e5f8201613908602088016128fb565b906129d3565b61392760018201613921604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90613941916138d3565b565b6139d69061398a61396a5f613964600361395e83870161286c565b9061060a565b01610671565b61398461397e6139795f611ef8565b610206565b91610206565b146128d2565b6139ba613999602083016128fb565b6139b36139ad6139a85f611ef8565b610206565b91610206565b1415612961565b6139d1816139cb5f6003920161286c565b9061060a565b613937565b565b6139e1906138c0565b565b5f90565b6139ef6139e3565b507f000000000000000000000000000000000000000000000000000000000000000090565b90613a2f9a999897969594939291613a2a61504e565b6140bd565b90565b60207f6d652e0000000000000000000000000000000000000000000000000000000000917f53746172742074696d65206d757374206265206265666f726520656e642074695f8201520152565b613a8c60236040926107e6565b613a9581613a32565b0190565b613aae9060208101905f818303910152613a7f565b90565b15613ab857565b613ac06101c3565b62461bcd60e51b815280613ad660048201613a99565b0390fd5b5f7f53746172742074696d6520696e20706173740000000000000000000000000000910152565b613b0e60126020926107e6565b613b1781613ada565b0190565b613b309060208101905f818303910152613b01565b90565b15613b3a57565b613b426101c3565b62461bcd60e51b815280613b5860048201613b1b565b0390fd5b5f7f496e76616c696420726567697374657249640000000000000000000000000000910152565b613b9060126020926107e6565b613b9981613b5c565b0190565b613bb29060208101905f818303910152613b83565b90565b15613bbc57565b613bc46101c3565b62461bcd60e51b815280613bda60048201613b9d565b0390fd5b5f7f496e76616c6964206175746850726f7669646572496400000000000000000000910152565b613c1260166020926107e6565b613c1b81613bde565b0190565b613c349060208101905f818303910152613c05565b90565b15613c3e57565b613c466101c3565b62461bcd60e51b815280613c5c60048201613c1f565b0390fd5b5f7f496e76616c696420737673496400000000000000000000000000000000000000910152565b613c94600d6020926107e6565b613c9d81613c60565b0190565b613cb69060208101905f818303910152613c87565b90565b15613cc057565b613cc86101c3565b62461bcd60e51b815280613cde60048201613ca1565b0390fd5b90565b5f7f496e76616c6964206465736372697074696f6e20636964000000000000000000910152565b613d1960176020926107e6565b613d2281613ce5565b0190565b613d3b9060208101905f818303910152613d0c565b90565b15613d4557565b613d4d6101c3565b62461bcd60e51b815280613d6360048201613d26565b0390fd5b5f7f496e76616c696420656c656374696f6e205075624b6579000000000000000000910152565b613d9b60176020926107e6565b613da481613d67565b0190565b613dbd9060208101905f818303910152613d8e565b90565b15613dc757565b613dcf6101c3565b62461bcd60e51b815280613de560048201613da8565b0390fd5b613df2906101d5565b5f198114613e005760010190565b61229c565b5f7f416c726561647920737461727465640000000000000000000000000000000000910152565b613e39600f6020926107e6565b613e4281613e05565b0190565b613e5b9060208101905f818303910152613e2c565b90565b15613e6557565b613e6d6101c3565b62461bcd60e51b815280613e8360048201613e46565b0390fd5b90613e9461ff00916129ad565b9181191691161790565b90613eb3613eae613eba926105ee565b61298a565b8254613e87565b9055565b60101b90565b90613ed262ff000091613ebe565b9181191691161790565b90613ef1613eec613ef8926105ee565b61298a565b8254613ec4565b9055565b9190601f8111613f0c575b505050565b613f18613f3d93610bfe565b906020613f24846129f7565b83019310613f45575b613f36906129f7565b0190612a64565b5f8080613f07565b9150613f3681929050613f2d565b90613f5d81610e21565b9067ffffffffffffffff821161401d57613f8182613f7b8554610692565b85613efc565b602090601f8311600114613fb557918091613fa4935f92613fa9575b5050612aef565b90555b565b90915001515f80613f9d565b601f19831691613fc485610bfe565b925f5b81811061400557509160029391856001969410613feb575b50505002019055613fa7565b613ffb910151601f841690612ada565b90555f8080613fdf565b91936020600181928787015181550195019201613fc7565b6103c8565b9061402c91613f53565b565b97969492909593916101208901965f8a01614048916109f1565b60208901614055916109f1565b60408801614062916109f1565b6060870161406f916109f1565b6080860161407c916107c8565b60a08501614089916107c8565b60c08401614096916107c8565b82810360e08401526140a7916107fa565b908082039061010001526140ba91610e2e565b90565b9992959396949891979099506140e5886140df6140d9896101d5565b916101d5565b10613ab1565b614101886140fb6140f5426101d5565b916101d5565b11613b33565b61413b61411a5f61411460028890611824565b01610671565b61413461412e6141295f611ef8565b610206565b91610206565b1415613bb5565b6141756141545f61414e60048990611735565b01610671565b61416e6141686141635f611ef8565b610206565b91610206565b1415613c37565b6141af61418e5f6141886003859061060a565b01610671565b6141a86141a261419d5f611ef8565b610206565b91610206565b1415613cb9565b6141db6141c36141be84613ce2565b610e21565b6141d56141cf5f611a93565b916101d5565b11613d3e565b6141ff6141e784610e21565b6141f96141f35f611a93565b916101d5565b11613dc0565b8961421261420c5f611a93565b916101d5565b145f1461442f576142236001610b73565b61423661422f82613de9565b60016122f3565b5b998061424b6142455f611a93565b916101d5565b14158061440b575b6143e7575b5061426d61426860058c90610b49565b611a8d565b61431261427c60018301610b73565b61428e6142885f611a93565b916101d5565b14918280156143bd575b6142a190613e5e565b6142ae5f6006830161328d565b6142ba8d5f83016122f3565b6142c78560098301612bd0565b6142d48b600183016122f3565b6142e189600283016122f3565b6142ee876006830161298d565b6142fb8860068301613e9e565b6143088460068301613edc565b600a869101614022565b5f1461436a57614363948a989697999490919293946143517f64793360e65c496ec24f3e041ea18618308610a342ec4b80561a067f596ae24f9a610b2d565b9a61435a6101c3565b998a998a61402e565b0390a25b90565b6143b5948a989697999490919293946143a37f675c24ce14b9c24aee51df73c1db1039e34de2896a4f0045dcc1a53352c2111f9a610b2d565b9a6143ac6101c3565b998a998a61402e565b0390a2614367565b506142a16143cd60068301610be8565b6143df6143d95f610dfc565b91610dfc565b149050614298565b6143fe614405916143f86001612280565b906122b0565b60016122f3565b5f614258565b508061442861442261441d6001610b73565b6101d5565b916101d5565b1015614253565b89614237565b9061444f99989796959493929161444a612a4c565b613a14565b90565b919390926145a7614470600661446a60058790610b49565b0161063f565b6144a13361449b6144956144905f61448a60028890611824565b01610671565b610206565b91610206565b146134d4565b6144c76144af888590611b31565b6144c16144bb5f611a93565b916101d5565b1161355a565b6144ed6144d5858a90611b31565b6144e76144e15f611a93565b916101d5565b1161355a565b614520614507600161450160058990610b49565b01610b73565b6145196145135f611a93565b916101d5565b1415611b08565b61455361452d6001612280565b61454d600561453d818a90610b49565b019161454883610b73565b6122b0565b906122f3565b93949591929661459561458f6145897f9eca82030d6f3f327790a7579c2c8903421bf9cff8a13ce2edc692f099e0b100976105ee565b97610b2d565b97610b2d565b9761459e6101c3565b94859485611eaf565b0390a4565b906145be916145b961504e565b6145c0565b565b6145d46145cf60058390610b49565b611a8d565b916145fd6145e460018501610b73565b6145f66145f05f611a93565b916101d5565b1415611b08565b61462561460c60068501610be8565b9361461b60046006830161328d565b6008839101612bd0565b816146656146537f16855b8fd590df07334beb9055e3e43a8856ad0a085241abb0fd4071c4b440bf92610b2d565b9261465c6101c3565b91829182610a48565b0390a260046146947f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b926146a96146a06101c3565b928392836132ad565b0390a2565b906146b8916145ac565b565b6146c66146cb91610620565b610652565b90565b6146d890546146ba565b90565b6146e36139e3565b506146ed5f6146ce565b90565b614701906146fc61504e565b614785565b565b5f7f4e6f7420616374697665206f722070656e64696e670000000000000000000000910152565b61473760156020926107e6565b61474081614703565b0190565b6147599060208101905f81830391015261472a565b90565b1561476357565b61476b6101c3565b62461bcd60e51b81528061478160048201614744565b0390fd5b61479961479460058390610b49565b611a8d565b906147c26147a960018401610b73565b6147bb6147b55f611a93565b916101d5565b1415611b08565b6147ea6147d160028401610b73565b6147e36147dd426101d5565b916101d5565b1115613125565b6147f660068301610be8565b6148096148036001610dfc565b91610dfc565b14801561487b575b61481a9061475c565b61483561482960068401610be8565b9260066002910161328d565b60026148617f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b9261487661486d6101c3565b928392836132ad565b0390a2565b5061481a61488b60068401610be8565b61489d6148975f610dfc565b91610dfc565b149050614811565b6148ae906146f0565b565b5f7f4f6e6c7920526567697374657200000000000000000000000000000000000000910152565b6148e4600d6020926107e6565b6148ed816148b0565b0190565b6149069060208101905f8183039101526148d7565b90565b1561491057565b6149186101c3565b62461bcd60e51b81528061492e600482016148f1565b0390fd5b5f7f456c656374696f6e206e6f7420616374697665206f722070656e64696e670000910152565b614966601e6020926107e6565b61496f81614932565b0190565b6149889060208101905f818303910152614959565b90565b1561499257565b61499a6101c3565b62461bcd60e51b8152806149b060048201614973565b0390fd5b6149be6040610405565b90565b5190565b906149f0602060016149f6946149e85f82016149e25f88016149c1565b90614022565b0192016149c1565b90614022565b565b90614a02916149c5565b565b9091614a1e614a2c9360408401908482035f860152610e2e565b916020818403910152610e2e565b90565b614a75614a5d5f614a57614a506006614a4a60058890610b49565b0161063f565b6002611824565b01610671565b614a6f614a6933610206565b91610206565b14614909565b614a8c6006614a8660058490610b49565b01610be8565b614a9e614a985f610dfc565b91610dfc565b148015614b2e575b614aaf9061498b565b614ae882614ad485614acb614ac26149b4565b935f8501610cc2565b60208301610cc2565b600c614ae260058590610b49565b016149f8565b9091614b147fd564ae0c19e7c4abf1a013f9e736abe2695aa574026614ed29237392b84fa02f92610b2d565b92614b29614b206101c3565b92839283614a04565b0390a2565b50614aaf614b496006614b4360058590610b49565b01610be8565b614b5c614b566001610dfc565b91610dfc565b149050614aa6565b90614b7c6006614b7660058590610b49565b01610b94565b614bad33614ba7614ba1614b9c5f614b9660048890611735565b01610671565b610206565b91610206565b14612eab565b614be0614bc76001614bc160058790610b49565b01610b73565b614bd9614bd35f611a93565b916101d5565b1415611b08565b614c14614bed6001612280565b614c0e6004614bfe60058890610b49565b0191614c0983610b73565b6122b0565b906122f3565b91614c51614c4b614c457f82d04e43f313a2777a6868b9b6104462501c44b93e000811fb1a52b0790e8dfd956105ee565b92610b2d565b92610b2d565b92614c5a6101c3565b80614c6481610372565b0390a4565b90614c8197969594939291614c7c61504e565b614dd9565b565b5f7f456c656374696f6e206e6f7420656e6465640000000000000000000000000000910152565b614cb760126020926107e6565b614cc081614c83565b0190565b614cd99060208101905f818303910152614caa565b90565b15614ce357565b614ceb6101c3565b62461bcd60e51b815280614d0160048201614cc4565b0390fd5b5f7f4172726179206c656e677468206d69736d617463680000000000000000000000910152565b614d3960156020926107e6565b614d4281614d05565b0190565b614d5b9060208101905f818303910152614d2c565b90565b15614d6557565b614d6d6101c3565b62461bcd60e51b815280614d8360048201614d46565b0390fd5b959192614dc894614dac614dba93614dd69a989660808b01918b83035f8d0152612ee9565b9188830360208a0152612ee9565b918583036040870152612ee9565b916060818403910152610e2e565b90565b96614edb92939496959195614e96614dfb614df660058c90610b49565b611a8d565b614e23614e0a60018301610b73565b614e1c614e165f611a93565b916101d5565b1415611b08565b614e4b614e3260068301610be8565b614e45614e3f6002610dfc565b91610dfc565b14614cdc565b614e56898890612ed4565b614e68614e625f611a93565b916101d5565b1180614f5a575b80614f27575b614e7e90614d5e565b614e8c60036006830161328d565b600b849101614022565b889694959792909192614ec97fbdb1df71a7d425561df6e178e20c02d68fc55733318c8b1503f354b360ff101d98610b2d565b98614ed26101c3565b97889788614d87565b0390a26002906003614f0d7f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b92614f22614f196101c3565b928392836132ad565b0390a2565b50614e7e614f368a8990612ed4565b614f52614f4c614f47898890612ed4565b6101d5565b916101d5565b149050614e75565b50614f66898890612ed4565b614f81614f7b614f768d8c612ed4565b6101d5565b916101d5565b14614e6f565b90614f9797969594939291614c69565b565b614faa90614fa561504e565b614fac565b565b80614fc7614fc1614fbc5f611ef8565b610206565b91610206565b14614fd757614fd5906150d7565b565b614ffa614fe35f611ef8565b5f918291631e4fbdf760e01b83526004830161132c565b0390fd5b61500790614f99565b565b6150116139e3565b5061501a615208565b90565b61503e61504a9261503961504493615033612e28565b50615292565b6152c8565b92610206565b91610206565b1490565b6150566146db565b61506f615069615064615009565b610206565b91610206565b0361507657565b615098615081615009565b5f91829163118cdaa760e01b83526004830161132c565b0390fd5b906150ad60018060a01b03916122d5565b9181191691161790565b906150cc6150c76150d392611dc1565b6129d0565b825461509c565b9055565b6150e05f6146ce565b6150ea825f6150b7565b9061511e6151187f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e093611dc1565b91611dc1565b916151276101c3565b8061513181610372565b0390a3565b61514561514b919392936101d5565b926101d5565b820391821161515657565b61229c565b5f80fd5b5f80fd5b9093929384831161518357841161517e576001820201920390565b61515f565b61515b565b6bffffffffffffffffffffffff191690565b906151a86151af9183611b31565b9135615188565b90601481106151bd575b5090565b6151db906bffffffffffffffffffffffff1990601403600802612a01565b165f6151b9565b60601c90565b6151f46151f9916151e2565b611d99565b90565b615205906151e8565b90565b6152106139e3565b5061521c5f3690611b31565b615224615309565b61522d33612e2c565b80615273575b5f146152665761525861525e91615263936152505f923692615136565b908092615163565b9061519a565b6151fc565b90565b505061527061531f565b90565b5081615287615281836101d5565b916101d5565b1015615233565b5f90565b61529a61528e565b507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f2090565b6152e7916152de916152d86139e3565b50615353565b90929192615449565b90565b90565b6153016152fc615306926152ea565b6105eb565b6101d5565b90565b615311612a4c565b5061531c60146152ed565b90565b6153276139e3565b503390565b5f90565b90565b61534761534261534c926101d5565b6122d5565b615330565b90565b5f90565b91909161535e6139e3565b5061536761532c565b5061537061528e565b5061537a83610e21565b61538d6153876041611d7d565b916101d5565b145f146153d4576153cd91926153a161528e565b506153aa61528e565b506153b361534f565b506020810151606060408301519201515f1a9091926155a3565b9192909190565b506153de5f611ef8565b906153f26153ed600294610e21565b615333565b91929190565b6004111561540257565b610dd9565b90615411826153f8565b565b61541c90615330565b9052565b9190615433905f60208501940190615413565b565b61544161544691610620565b610b2d565b90565b8061545c6154565f615407565b91615407565b145f14615467575050565b8061547b6154756001615407565b91615407565b145f1461549e575f63f645eedf60e01b81528061549a60048201610372565b0390fd5b806154b26154ac6002615407565b91615407565b145f146154e0576154dc6154c583615435565b5f91829163fce698f760e01b8352600483016109fe565b0390fd5b6154f36154ed6003615407565b91615407565b146154fb5750565b615516905f9182916335e2f38360e21b835260048301615420565b0390fd5b90565b61553161552c6155369261551a565b6105eb565b6101d5565b90565b61556e6155759461556460609498979561555a608086019a5f870190615413565b60208501906107c8565b6040830190615413565b0190615413565b565b61557f6101c3565b3d5f823e3d90fd5b61559b6155966155a092611a90565b6122d5565b615330565b90565b9392936155ae6139e3565b506155b761532c565b506155c061528e565b506155ca85615435565b6155fc6155f67f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a061551d565b916101d5565b11615689579061561f602094955f949392936156166101c3565b94859485615539565b838052039060015afa15615684576156375f516122d5565b8061565261564c6156475f611ef8565b610206565b91610206565b14615668575f916156625f615587565b91929190565b506156725f611ef8565b60019161567e5f615587565b91929190565b615577565b5050506156955f611ef8565b906003929192919056fea2646970667358221220834600c55ec0ad0cc7dad583a11b7aa80b18464cf5a688523371163bcc80f1dc64736f6c634300081b0033000000000000000000000000d8253782c45a12053594b9deb72d8e8ab2fca54c0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6102006040526004361015610014575b611a89565b61001e5f356101bd565b80631c700694146101b8578063256fab2f146101b35780633ad71ded146101ae5780634a17ce11146101a95780635313837b146101a457806354fd4d501461019f578063572b6c051461019a5780635e6fef011461019557806362dc5b37146101905780636d32dc4b1461018b578063715018a6146101865780637a62e918146101815780637b7abbdc1461017c5780637da0a877146101775780638628a8bc1461017257806388c7c0731461016d5780638b9f341b146101685780638da5cb5b146101635780639c98bcbb1461015e578063a4133feb14610159578063a67e65c314610154578063ae27a99c1461014f578063e1c67af41461014a578063ed08dc3614610145578063f2fde38b146101405763ffa1ad740361000f57611a54565b6119a9565b61196c565b611879565b6117f0565b61178a565b611701565b611665565b611630565b6115fc565b61157d565b6114c0565b611341565b6112f9565b6111f7565b6110ef565b6110bc565b611088565b610fb7565b610ada565b610a60565b610a13565b610973565b610872565b61059a565b610377565b60e01c90565b60405190565b5f80fd5b5f80fd5b5f80fd5b90565b6101e1816101d5565b036101e857565b5f80fd5b905035906101f9826101d8565b565b60018060a01b031690565b61020f906101fb565b90565b61021b81610206565b0361022257565b5f80fd5b9050359061023382610212565b565b5f80fd5b5f80fd5b5f80fd5b909182601f8301121561027b5781359167ffffffffffffffff831161027657602001926001830284011161027157565b61023d565b610239565b610235565b9160e08383031261036d57610297825f85016101ec565b926102a58360208301610226565b92604082013567ffffffffffffffff811161036857816102c6918401610241565b929093606082013567ffffffffffffffff811161036357836102e9918401610241565b929093608082013567ffffffffffffffff811161035e578161030c918401610241565b92909360a082013567ffffffffffffffff8111610359578361032f918401610241565b92909360c082013567ffffffffffffffff8111610354576103509201610241565b9091565b6101d1565b6101d1565b6101d1565b6101d1565b6101d1565b6101cd565b5f0190565b346103b55761039f61038a366004610280565b9a9990999891989792979693969594956123c0565b6103a76101c3565b806103b181610372565b0390f35b6101c9565b5f80fd5b601f801991011690565b634e487b7160e01b5f52604160045260245ffd5b906103e6906103be565b810190811067ffffffffffffffff82111761040057604052565b6103c8565b906104186104116101c3565b92836103dc565b565b5f80fd5b60ff1690565b61042d8161041e565b0361043457565b5f80fd5b9050359061044582610424565b565b5f80fd5b67ffffffffffffffff8111610469576104656020916103be565b0190565b6103c8565b90825f939282370152565b9092919261048e6104898261044b565b610405565b938185526020850190828401116104aa576104a89261046e565b565b610447565b9080601f830112156104cd578160206104ca93359101610479565b90565b610235565b919091608081840312610560576104e96080610405565b926104f6815f8401610438565b5f8501526105078160208401610226565b6020850152604082013567ffffffffffffffff811161055b578161052c9184016104af565b6040850152606082013567ffffffffffffffff81116105565761054f92016104af565b6060830152565b61041a565b61041a565b6103ba565b90602082820312610595575f82013567ffffffffffffffff81116105905761058d92016104d2565b90565b6101d1565b6101cd565b346105c8576105b26105ad366004610565565b612ce1565b6105ba6101c3565b806105c481610372565b0390f35b6101c9565b906020828203126105e6576105e3915f01610438565b90565b6101cd565b90565b6106026105fd6106079261041e565b6105eb565b61041e565b90565b90610614906105ee565b5f5260205260405f2090565b5f1c90565b60ff1690565b61063761063c91610620565b610625565b90565b610649905461062b565b90565b60081c90565b60018060a01b031690565b61066961066e9161064c565b610652565b90565b61067b905461065d565b90565b634e487b7160e01b5f52602260045260245ffd5b90600160028304921680156106b2575b60208310146106ad57565b61067e565b91607f16916106a2565b60209181520190565b5f5260205f2090565b905f92918054906106e86106e183610692565b80946106bc565b916001811690815f1461073f5750600114610703575b505050565b61071091929394506106c5565b915f925b81841061072757505001905f80806106fe565b60018160209295939554848601520191019290610714565b92949550505060ff19168252151560200201905f80806106fe565b90610764916106ce565b90565b90610787610780926107776101c3565b9384809261075a565b03836103dc565b565b61079490600361060a565b906107a05f830161063f565b916107ac5f8201610671565b916107c560026107be60018501610767565b9301610767565b90565b6107d19061041e565b9052565b6107de90610206565b9052565b5190565b60209181520190565b90825f9392825e0152565b61081961082260209361082793610810816107e2565b938480936107e6565b958691016107ef565b6103be565b0190565b92906108619161085461086f969461084a60808801945f8901906107c8565b60208701906107d5565b84820360408601526107fa565b9160608184039101526107fa565b90565b346108a6576108a261088d6108883660046105cd565b610789565b906108999492946101c3565b9485948561082b565b0390f35b6101c9565b919091608081840312610939576108c26080610405565b926108cf815f8401610438565b5f8501526108e08160208401610226565b6020850152604082013567ffffffffffffffff811161093457816109059184016104af565b6040850152606082013567ffffffffffffffff811161092f5761092892016104af565b6060830152565b61041a565b61041a565b6103ba565b9060208282031261096e575f82013567ffffffffffffffff81116109695761096692016108ab565b90565b6101d1565b6101cd565b346109a15761098b61098636600461093e565b612e04565b6109936101c3565b8061099d81610372565b0390f35b6101c9565b5f9103126109b057565b6101cd565b1c90565b90565b6109cc9060086109d193026109b5565b6109b9565b90565b906109df91546109bc565b90565b6109ee60015f906109d4565b90565b6109fa906101d5565b9052565b9190610a11905f602085019401906109f1565b565b34610a4357610a233660046109a6565b610a3f610a2e6109e2565b610a366101c3565b918291826109fe565b0390f35b6101c9565b610a5d9160208201915f8184039101526107fa565b90565b34610a9057610a703660046109a6565b610a8c610a7b612e14565b610a836101c3565b91829182610a48565b0390f35b6101c9565b90602082820312610aae57610aab915f01610226565b90565b6101cd565b151590565b610ac190610ab3565b9052565b9190610ad8905f60208501940190610ab8565b565b34610b0a57610b06610af5610af0366004610a95565b612e2c565b610afd6101c3565b91829182610ac5565b0390f35b6101c9565b90602082820312610b2857610b25915f016101ec565b90565b6101cd565b610b41610b3c610b46926101d5565b6105eb565b6101d5565b90565b90610b5390610b2d565b5f5260205260405f2090565b610b6b610b7091610620565b6109b9565b90565b610b7d9054610b5f565b90565b610b8c610b919161064c565b610625565b90565b610b9e9054610b80565b90565b60101c90565b610bb3610bb891610ba1565b610625565b90565b610bc59054610ba7565b90565b60181c90565b60ff1690565b610be0610be591610bc8565b610bce565b90565b610bf29054610bd4565b90565b60209181520190565b5f5260205f2090565b905f9291805490610c21610c1a83610692565b8094610bf5565b916001811690815f14610c785750600114610c3c575b505050565b610c499192939450610bfe565b915f925b818410610c6057505001905f8080610c37565b60018160209295939554848601520191019290610c4d565b92949550505060ff19168252151560200201905f8080610c37565b90610c9d91610c07565b90565b90610cc0610cb992610cb06101c3565b93848092610c93565b03836103dc565b565b52565b610ccf6040610405565b90565b90610d09610d006001610ce3610cc5565b94610cfa610cf25f8301610ca0565b5f8801610cc2565b01610ca0565b60208401610cc2565b565b610d16906005610b49565b610d215f8201610b73565b91610d2e60018301610b73565b91610d3b60028201610b73565b91610d4860038301610b73565b91610d5560048201610b73565b91610d6260058301610b73565b91610d6f6006820161063f565b91610d7c60068301610b94565b91610d8960068201610bbb565b91610d9660068301610be8565b91610da360088201610767565b91610db060098301610767565b91610dbd600a8201610ca0565b91610dd6600c610dcf600b8501610ca0565b9301610cd2565b90565b634e487b7160e01b5f52602160045260245ffd5b60051115610df757565b610dd9565b90610e0682610ded565b565b610e1190610dfc565b90565b610e1d90610e08565b9052565b5190565b60209181520190565b610e4d610e56602093610e5b93610e4481610e21565b93848093610e25565b958691016107ef565b6103be565b0190565b610e7e610e87602093610e8c93610e7581610e21565b93848093610bf5565b958691016107ef565b6103be565b0190565b610ebe916020610ead604083015f8501518482035f860152610e5f565b920151906020818403910152610e5f565b90565b809e9d9c9b9a989694929997959391996101e082019a5f8301610ee3916109f1565b60208201610ef0916109f1565b604001610efc916109f1565b60608d01610f09916109f1565b60808c01610f16916109f1565b60a08b01610f23916109f1565b60c08a01610f30916107c8565b60e08901610f3d916107c8565b6101008801610f4b916107c8565b6101208701610f5991610e14565b858103610140870152610f6b916107fa565b848103610160860152610f7d916107fa565b838103610180850152610f8f91610e2e565b8281036101a0840152610fa191610e2e565b90808203906101c00152610fb491610e90565b90565b34610ffe5736610fc8906004610b0f565b610fd190610d0b565b9a610fec9e9c9e9a919a9992999893989794979695966101c3565b9e8f9e8f9e610ffa9f610ec1565b0390f35b6101c9565b909182601f8301121561103d5781359167ffffffffffffffff831161103857602001926020830284011161103357565b61023d565b610239565b610235565b9190916040818403126110835761105b835f83016101ec565b92602082013567ffffffffffffffff811161107e5761107a9201611003565b9091565b6101d1565b6101cd565b346110b7576110a161109b366004611042565b91612f37565b6110a96101c3565b806110b381610372565b0390f35b6101c9565b346110ea576110d46110cf366004610b0f565b613441565b6110dc6101c3565b806110e681610372565b0390f35b6101c9565b3461111d576110ff3660046109a6565b611107613471565b61110f6101c3565b8061111981610372565b0390f35b6101c9565b909182601f8301121561115c5781359167ffffffffffffffff831161115757602001926020830284011161115257565b61023d565b610239565b610235565b9190916080818403126111f25761117a835f83016101ec565b92602082013567ffffffffffffffff81116111ed578161119b918401611003565b929093604082013567ffffffffffffffff81116111e857836111be918401611122565b929093606082013567ffffffffffffffff81116111e3576111df9201611122565b9091565b6101d1565b6101d1565b6101d1565b6101cd565b3461122c5761121661120a366004611161565b95949094939193613745565b61121e6101c3565b8061122881610372565b0390f35b6101c9565b9190916080818403126112bf576112486080610405565b92611255815f8401610438565b5f8501526112668160208401610226565b6020850152604082013567ffffffffffffffff81116112ba578161128b9184016104af565b6040850152606082013567ffffffffffffffff81116112b5576112ae92016104af565b6060830152565b61041a565b61041a565b6103ba565b906020828203126112f4575f82013567ffffffffffffffff81116112ef576112ec9201611231565b90565b6101d1565b6101cd565b346113275761131161130c3660046112c4565b6139d8565b6113196101c3565b8061132381610372565b0390f35b6101c9565b919061133f905f602085019401906107d5565b565b34611371576113513660046109a6565b61136d61135c6139e7565b6113646101c3565b9182918261132c565b0390f35b6101c9565b67ffffffffffffffff8111611394576113906020916103be565b0190565b6103c8565b909291926113ae6113a982611376565b610405565b938185526020850190828401116113ca576113c89261046e565b565b610447565b9080601f830112156113ed578160206113ea93359101611399565b90565b610235565b90610140828203126114bb5761140a815f84016101ec565b9261141882602085016101ec565b9261142683604083016101ec565b9261143481606084016101ec565b9261144282608085016101ec565b926114508360a08301610438565b9261145e8160c08401610438565b9261146c8260e08501610438565b9261010081013567ffffffffffffffff81116114b6578361148e9183016104af565b9261012082013567ffffffffffffffff81116114b1576114ae92016113cf565b90565b6101d1565b6101d1565b6101cd565b346114fd576114f96114e86114d63660046113f2565b98979097969196959295949394614435565b6114f06101c3565b918291826109fe565b0390f35b6101c9565b91906080838203126115785761151a815f85016101ec565b9261152882602083016101ec565b92604082013567ffffffffffffffff81116115735783611549918401610241565b929093606082013567ffffffffffffffff811161156e5761156a9201610241565b9091565b6101d1565b6101d1565b6101cd565b346115b25761159c611590366004611502565b94939093929192614452565b6115a46101c3565b806115ae81610372565b0390f35b6101c9565b9190916040818403126115f7576115d0835f83016101ec565b92602082013567ffffffffffffffff81116115f2576115ef92016104af565b90565b6101d1565b6101cd565b3461162b5761161561160f3660046115b7565b906146ae565b61161d6101c3565b8061162781610372565b0390f35b6101c9565b34611660576116403660046109a6565b61165c61164b6146db565b6116536101c3565b9182918261132c565b0390f35b6101c9565b346116935761167d611678366004610b0f565b6148a5565b6116856101c3565b8061168f81610372565b0390f35b6101c9565b916060838303126116fc576116af825f85016101ec565b92602081013567ffffffffffffffff81116116f757836116d09183016113cf565b92604082013567ffffffffffffffff81116116f2576116ef92016113cf565b90565b6101d1565b6101d1565b6101cd565b346117305761171a611714366004611698565b91614a2f565b6117226101c3565b8061172c81610372565b0390f35b6101c9565b9061173f906105ee565b5f5260205260405f2090565b611756906004611735565b906117625f830161063f565b9161176e5f8201610671565b91611787600261178060018501610767565b9301610767565b90565b346117be576117ba6117a56117a03660046105cd565b61174b565b906117b19492946101c3565b9485948561082b565b0390f35b6101c9565b91906040838203126117eb57806117df6117e8925f86016101ec565b936020016101ec565b90565b6101cd565b3461181f576118096118033660046117c3565b90614b64565b6118116101c3565b8061181b81610372565b0390f35b6101c9565b9061182e906105ee565b5f5260205260405f2090565b611845906002611824565b906118515f830161063f565b9161185d5f8201610671565b91611876600261186f60018501610767565b9301610767565b90565b346118ad576118a961189461188f3660046105cd565b61183a565b906118a09492946101c3565b9485948561082b565b0390f35b6101c9565b60a081830312611967576118c8825f83016101ec565b92602082013567ffffffffffffffff811161196257836118e9918401611003565b929093604082013567ffffffffffffffff811161195d578161190c918401611003565b929093606082013567ffffffffffffffff8111611958578361192f918401611003565b929093608082013567ffffffffffffffff81116119535761195092016113cf565b90565b6101d1565b6101d1565b6101d1565b6101d1565b6101cd565b346119a45761198e61197f3660046118b2565b96959095949194939293614f87565b6119966101c3565b806119a081610372565b0390f35b6101c9565b346119d7576119c16119bc366004610a95565b614ffe565b6119c96101c3565b806119d381610372565b0390f35b6101c9565b906119ee6119e98361044b565b610405565b918252565b5f7f302e312e30000000000000000000000000000000000000000000000000000000910152565b611a2460056119dc565b90611a31602083016119f3565b565b611a3b611a1a565b90565b611a46611a33565b90565b611a51611a3e565b90565b34611a8457611a643660046109a6565b611a80611a6f611a49565b611a776101c3565b91829182610a48565b0390f35b6101c9565b5f80fd5b90565b90565b611aa7611aa2611aac92611a90565b6105eb565b6101d5565b90565b5f7f456c656374696f6e20756e6b6e6f776e00000000000000000000000000000000910152565b611ae360106020926107e6565b611aec81611aaf565b0190565b611b059060208101905f818303910152611ad6565b90565b15611b0f57565b611b176101c3565b62461bcd60e51b815280611b2d60048201611af0565b0390fd5b5090565b90565b611b4c611b47611b5192611b35565b6105eb565b6101d5565b90565b90565b611b6b611b66611b7092611b54565b6105eb565b6101d5565b90565b5f7f496e76616c696420766f7465456e63727970746564206c656e67746800000000910152565b611ba7601c6020926107e6565b611bb081611b73565b0190565b611bc99060208101905f818303910152611b9a565b90565b15611bd357565b611bdb6101c3565b62461bcd60e51b815280611bf160048201611bb4565b0390fd5b5f7f496e76616c696420766f7465456e6372797074656455736572206c656e677468910152565b611c28602080926107e6565b611c3181611bf5565b0190565b611c4a9060208101905f818303910152611c1c565b90565b15611c5457565b611c5c6101c3565b62461bcd60e51b815280611c7260048201611c35565b0390fd5b5f7f456c656374696f6e206973206e6f742061637469766500000000000000000000910152565b611caa60166020926107e6565b611cb381611c76565b0190565b611ccc9060208101905f818303910152611c9d565b90565b15611cd657565b611cde6101c3565b62461bcd60e51b815280611cf460048201611cb7565b0390fd5b5f7f456c656374696f6e20656e646564000000000000000000000000000000000000910152565b611d2c600e6020926107e6565b611d3581611cf8565b0190565b611d4e9060208101905f818303910152611d1f565b90565b15611d5857565b611d606101c3565b62461bcd60e51b815280611d7660048201611d39565b0390fd5b90565b611d91611d8c611d9692611d7a565b6105eb565b6101d5565b90565b611dad611da8611db2926101fb565b6105eb565b6101fb565b90565b611dbe90611d99565b90565b611dca90611db5565b90565b90611dd790611dc1565b5f5260205260405f2090565b60ff1690565b611df5611dfa91610620565b611de3565b90565b611e079054611de9565b90565b5f7f766f74657220756e6b6e6f776e00000000000000000000000000000000000000910152565b611e3e600d6020926107e6565b611e4781611e0a565b0190565b611e609060208101905f818303910152611e31565b90565b15611e6a57565b611e726101c3565b62461bcd60e51b815280611e8860048201611e4b565b0390fd5b9190611ea681611e9f81611eab95610e25565b809561046e565b6103be565b0190565b9290611ecb90611ed9959360408601918683035f880152611e8c565b926020818503910152611e8c565b90565b611ef0611eeb611ef592611a90565b6105eb565b6101fb565b90565b611f0190611edc565b90565b5f7f535653206e6f7420737065636966696564000000000000000000000000000000910152565b611f3860116020926107e6565b611f4181611f04565b0190565b611f5a9060208101905f818303910152611f2b565b90565b15611f6457565b611f6c6101c3565b62461bcd60e51b815280611f8260048201611f45565b0390fd5b90565b611f9d611f98611fa292611f86565b6105eb565b6101d5565b90565b60207f656e677468000000000000000000000000000000000000000000000000000000917f496e76616c696420756e626c696e646564456c656374696f6e546f6b656e206c5f8201520152565b611fff60256040926107e6565b61200881611fa5565b0190565b6120219060208101905f818303910152611ff2565b90565b1561202b57565b6120336101c3565b62461bcd60e51b8152806120496004820161200c565b0390fd5b60207f6800000000000000000000000000000000000000000000000000000000000000917f496e76616c696420756e626c696e6465645369676e6174757265206c656e67745f8201520152565b6120a760216040926107e6565b6120b08161204d565b0190565b6120c99060208101905f81830391015261209a565b90565b156120d357565b6120db6101c3565b62461bcd60e51b8152806120f1600482016120b4565b0390fd5b5f7f416c726561647920766f74656400000000000000000000000000000000000000910152565b612129600d6020926107e6565b612132816120f5565b0190565b61214b9060208101905f81830391015261211c565b90565b1561215557565b61215d6101c3565b62461bcd60e51b81528061217360048201612136565b0390fd5b989694916121d696916121e49b99956121c8956121ac6121ba9460208f6121a560c08201975f8301906109f1565b01906107d5565b8c6040818503910152611e8c565b9189830360608b0152611e8c565b918683036080880152611e8c565b9260a0818503910152611e8c565b90565b60200190565b6121f8913691611399565b90565b5f7f53696720696e76616c6964000000000000000000000000000000000000000000910152565b61222f600b6020926107e6565b612238816121fb565b0190565b6122519060208101905f818303910152612222565b90565b1561225b57565b6122636101c3565b62461bcd60e51b8152806122796004820161223c565b0390fd5b90565b61229461228f6122999261227d565b6105eb565b6101d5565b90565b634e487b7160e01b5f52601160045260245ffd5b6122bf6122c5919392936101d5565b926101d5565b82018092116122d057565b61229c565b5f1b90565b906122e65f19916122d5565b9181191691161790565b90565b9061230861230361230f92610b2d565b6122f0565b82546122da565b9055565b9061231f60ff916122d5565b9181191691161790565b61233290610ab3565b90565b90565b9061234d61234861235492612329565b612335565b8254612313565b9055565b989694916123a1936123bd9b99956123848c612393946123af9b9660a08301925f818503910152611e8c565b918c6020818503910152611e8c565b9189830360408b0152611e8c565b918683036060880152611e8c565b926080818503910152611e8c565b90565b9a989694929190999795939a60e0526101c0526080526101e0526101a0526101005261012052610140526101605261018052612408612403600560e05190610b49565b611a8d565b60c05261243561241c600160c05101610b73565b61242e6124285f611a93565b916101d5565b1415611b08565b612443826101e05190611b31565b612457612451610100611b38565b916101d5565b14801561282b575b61246890611bcc565b6124796101a0516101005190611b31565b61248b6124855f611a93565b916101d5565b11806127f9575b61249b90611c4d565b6124c56124ac600660c05101610be8565b6124bf6124b96001610dfc565b91610dfc565b14611ccf565b6124ef6124d6600260c05101610b73565b6124e86124e2426101d5565b916101d5565b1015611d51565b6124ff6101c05160805190611b31565b61251261250c6041611d7d565b916101d5565b145f14612766576126796126746125425f61253c6003612536600660c05101610bbb565b9061060a565b01610671565b6125678161256061255a6125555f611ef8565b610206565b91610206565b1415611f5d565b61259461257b610120516101405190611b31565b61258e6125886020611f89565b916101d5565b14612024565b6125a5610160516101805190611b31565b6125b96125b3610100611b38565b916101d5565b1460a05260a05115612738575b6125d160a0516120cc565b6125fa6125f56125ef6125ea600760c051018890611dcd565b611dfd565b15610ab3565b61214e565b60e051612649859161263a886101e0516101a05161010051610120519061014051926101605194610180519661262e6101c3565b9b8c9a60208c01612177565b602082018103825203826103dc565b61265b61265582610e21565b916121e7565b2061266e6101c0519260805190936121ed565b9061501d565b612254565b6126a46126866001612280565b61269e600360c051019161269983610b73565b6122b0565b906122f3565b6126be60016126b9600760c051018490611dcd565b612338565b60e0516101c0519260805190936127326101e0516101a051610100516101205161014051916101605193610180519561272061271a7f15dda67fb238757385e33f7875e964eed8cce6e309dc10bb713065238ec469289c610b2d565b9c611dc1565b9c6127296101c3565b9a8b9a8b612358565b0390a35b565b612749610160516101805190611b31565b61275d612757610200611b57565b916101d5565b1460a0526125c6565b5061278e612789612784600760c0510161277e615009565b90611dcd565b611dfd565b611e63565b60e0519061279a615009565b90916101e0516101a051936127f1610100516127df6127d97fddbd2b140ce7195be58239163e94257d7dfa3ba0e91e63d09e3ee97d9eacec7c96610b2d565b96611dc1565b966127e86101c3565b94859485611eaf565b0390a3612736565b5061249b61280e6101a0516101005190611b31565b61282261281c610200611b57565b916101d5565b11159050612492565b5061246861283d836101e05190611b31565b61285161284b610200611b57565b916101d5565b14905061245f565b61286a9061286561504e565b612c4c565b565b612876905161041e565b90565b5f7f496420616c726561647920757365640000000000000000000000000000000000910152565b6128ad600f6020926107e6565b6128b681612879565b0190565b6128cf9060208101905f8183039101526128a0565b90565b156128d957565b6128e16101c3565b62461bcd60e51b8152806128f7600482016128ba565b0390fd5b6129059051610206565b90565b5f7f4e6f206f776e6572207370656369666965640000000000000000000000000000910152565b61293c60126020926107e6565b61294581612908565b0190565b61295e9060208101905f81830391015261292f565b90565b1561296857565b6129706101c3565b62461bcd60e51b81528061298660048201612949565b0390fd5b90565b906129a261299d6129a9926105ee565b61298a565b8254612313565b9055565b60081b90565b906129c6610100600160a81b03916129ad565b9181191691161790565b90565b906129e86129e36129ef92611dc1565b6129d0565b82546129b3565b9055565b5190565b601f602091010490565b1b90565b91906008612a20910291612a1a5f1984612a01565b92612a01565b9181191691161790565b9190612a40612a3b612a4893610b2d565b6122f0565b908354612a05565b9055565b5f90565b612a6291612a5c612a4c565b91612a2a565b565b5b818110612a70575050565b80612a7d5f600193612a50565b01612a65565b9190601f8111612a93575b505050565b612a9f612ac4936106c5565b906020612aab846129f7565b83019310612acc575b612abd906129f7565b0190612a64565b5f8080612a8e565b9150612abd81929050612ab4565b90612aea905f19906008026109b5565b191690565b81612af991612ada565b906002021790565b90612b0b816107e2565b9067ffffffffffffffff8211612bcb57612b2f82612b298554610692565b85612a83565b602090601f8311600114612b6357918091612b52935f92612b57575b5050612aef565b90555b565b90915001515f80612b4b565b601f19831691612b72856106c5565b925f5b818110612bb357509160029391856001969410612b99575b50505002019055612b55565b612ba9910151601f841690612ada565b90555f8080612b8d565b91936020600181928787015181550195019201612b75565b6103c8565b90612bda91612b01565b565b90612c3860606002612c3e94612bff5f8201612bf95f880161286c565b9061298d565b612c175f8201612c11602088016128fb565b906129d3565b612c3060018201612c2a604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90612c4a91612bdc565b565b612cdf90612c93612c735f612c6d6002612c6783870161286c565b90611824565b01610671565b612c8d612c87612c825f611ef8565b610206565b91610206565b146128d2565b612cc3612ca2602083016128fb565b612cbc612cb6612cb15f611ef8565b610206565b91610206565b1415612961565b612cda81612cd45f6002920161286c565b90611824565b612c40565b565b612cea90612859565b565b612cfd90612cf861504e565b612d6f565b565b90612d5b60606002612d6194612d225f8201612d1c5f880161286c565b9061298d565b612d3a5f8201612d34602088016128fb565b906129d3565b612d5360018201612d4d604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90612d6d91612cff565b565b612e0290612db6612d965f612d906004612d8a83870161286c565b90611735565b01610671565b612db0612daa612da55f611ef8565b610206565b91610206565b146128d2565b612de6612dc5602083016128fb565b612ddf612dd9612dd45f611ef8565b610206565b91610206565b1415612961565b612dfd81612df75f6004920161286c565b90611735565b612d63565b565b612e0d90612cec565b565b606090565b612e1c612e0f565b50612e25611a3e565b90565b5f90565b612e34612e28565b50612e4e612e48612e436139e7565b610206565b91610206565b1490565b5f7f4f6e6c79204150204f776e657200000000000000000000000000000000000000910152565b612e86600d6020926107e6565b612e8f81612e52565b0190565b612ea89060208101905f818303910152612e79565b90565b15612eb257565b612eba6101c3565b62461bcd60e51b815280612ed060048201612e93565b0390fd5b5090565b60209181520190565b5f80fd5b9037565b909182612ef591612ed8565b9160018060fb1b038111612f185782916020612f149202938491612ee5565b0190565b612ee1565b9091612f349260208301925f818503910152612ee9565b90565b612f4e6006612f4860058490610b49565b01610b94565b612f7f33612f79612f73612f6e5f612f6860048890611735565b01610671565b610206565b91610206565b14612eab565b612fb2612f996001612f9360058690610b49565b01610b73565b612fab612fa55f611a93565b916101d5565b1415611b08565b612fe7612fc0848690612ed4565b612fe16004612fd160058790610b49565b0191612fdc83610b73565b6122b0565b906122f3565b90919261301d6130177f47550b38d402ab5b8c36108531d53c27431e781a73ddd07f9812b44dcee47da7936105ee565b93610b2d565b936130326130296101c3565b92839283612f1d565b0390a3565b6130489061304361504e565b6132d0565b565b5f7f4e6f742070656e64696e67000000000000000000000000000000000000000000910152565b61307e600b6020926107e6565b6130878161304a565b0190565b6130a09060208101905f818303910152613071565b90565b156130aa57565b6130b26101c3565b62461bcd60e51b8152806130c86004820161308b565b0390fd5b5f7f746f6f206561726c790000000000000000000000000000000000000000000000910152565b61310060096020926107e6565b613109816130cc565b0190565b6131229060208101905f8183039101526130f3565b90565b1561312c57565b6131346101c3565b62461bcd60e51b81528061314a6004820161310d565b0390fd5b5f7f746f6f206c617465000000000000000000000000000000000000000000000000910152565b61318260086020926107e6565b61318b8161314e565b0190565b6131a49060208101905f818303910152613175565b90565b156131ae57565b6131b66101c3565b62461bcd60e51b8152806131cc6004820161318f565b0390fd5b6131da9054610692565b90565b5f7f5265676973746572204b65792072657175697265640000000000000000000000910152565b61321160156020926107e6565b61321a816131dd565b0190565b6132339060208101905f818303910152613204565b90565b1561323d57565b6132456101c3565b62461bcd60e51b81528061325b6004820161321e565b0390fd5b60181b90565b9061327463ff0000009161325f565b9181191691161790565b61328790610dfc565b90565b90565b906132a261329d6132a99261327e565b61328a565b8254613265565b9055565b9160206132ce9294936132c760408201965f830190610e14565b0190610e14565b565b6132e46132df60058390610b49565b611a8d565b9061330d6132f460018401610b73565b6133066133005f611a93565b916101d5565b1415611b08565b61333461331c60068401610be8565b61332e6133285f610dfc565b91610dfc565b146130a3565b61335c61334360018401610b73565b61335561334f426101d5565b916101d5565b1115613125565b61338361336b60028401610b73565b61337d613377426101d5565b916101d5565b116131a7565b6133915f600c8401016131d0565b6133a361339d5f611a93565b916101d5565b1180613414575b6133b390613236565b6133ce6133c260068401610be8565b9260066001910161328d565b60016133fa7f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b9261340f6134066101c3565b928392836132ad565b0390a2565b506133b36134276001600c8501016131d0565b6134396134335f611a93565b916101d5565b1190506133aa565b61344a90613037565b565b61345461504e565b61345c61345e565b565b61346f61346a5f611ef8565b6150d7565b565b61347961344c565b565b5f7f4f6e6c79205265676973746572204f776e657200000000000000000000000000910152565b6134af60136020926107e6565b6134b88161347b565b0190565b6134d19060208101905f8183039101526134a2565b90565b156134db57565b6134e36101c3565b62461bcd60e51b8152806134f9600482016134bc565b0390fd5b5090565b5f7f426c696e646564205369676e6174757265207265717569726564000000000000910152565b613535601a6020926107e6565b61353e81613501565b0190565b6135579060208101905f818303910152613528565b90565b1561356157565b6135696101c3565b62461bcd60e51b81528061357f60048201613542565b0390fd5b5f7f766f746572496473207265717569726564000000000000000000000000000000910152565b6135b760116020926107e6565b6135c081613583565b0190565b6135d99060208101905f8183039101526135aa565b90565b156135e357565b6135eb6101c3565b62461bcd60e51b815280613601600482016135c4565b0390fd5b60209181520190565b90565b919061362b816136248161363095610bf5565b809561046e565b6103be565b0190565b9061363f9291613611565b90565b5f80fd5b5f80fd5b5f80fd5b903560016020038236030381121561368f57016020813591019167ffffffffffffffff821161368a57600182023603831361368557565b613646565b613642565b61364a565b60200190565b91816136a591613605565b90816136b66020830284019461360e565b92835f925b8484106136cb5750505050505090565b90919293949560206136f76136f183856001950388526136eb8b8861364e565b90613634565b98613694565b9401940192949391906136bb565b9492909361372661374297956137349460608901918983035f8b0152612ee9565b91868303602088015261369a565b92604081850391015261369a565b90565b9395946138bb9195613764600661375e60058990610b49565b0161063f565b6137953361378f6137896137845f61377e60028890611824565b01610671565b610206565b91610206565b146134d4565b6137bb6137a3878b906134fd565b6137b56137af5f611a93565b916101d5565b1161355a565b6137e16137c98484906134fd565b6137db6137d55f611a93565b916101d5565b1161355a565b6138076137ef898790612ed4565b6138016137fb5f611a93565b916101d5565b116135dc565b61383a613821600161381b60058b90610b49565b01610b73565b61383361382d5f611a93565b916101d5565b1415611b08565b61386e613848898790612ed4565b6138686005613858818c90610b49565b019161386383610b73565b6122b0565b906122f3565b95969394979190916138a96138a37ffed4b441535e6743c1c93426bb96dd86fb223583d3da43316d9d7a552474d32b986105ee565b98610b2d565b986138b26101c3565b96879687613705565b0390a3565b6138d1906138cc61504e565b613943565b565b9061392f60606002613935946138f65f82016138f05f880161286c565b9061298d565b61390e5f8201613908602088016128fb565b906129d3565b61392760018201613921604088016129f3565b90612bd0565b0192016129f3565b90612bd0565b565b90613941916138d3565b565b6139d69061398a61396a5f613964600361395e83870161286c565b9061060a565b01610671565b61398461397e6139795f611ef8565b610206565b91610206565b146128d2565b6139ba613999602083016128fb565b6139b36139ad6139a85f611ef8565b610206565b91610206565b1415612961565b6139d1816139cb5f6003920161286c565b9061060a565b613937565b565b6139e1906138c0565b565b5f90565b6139ef6139e3565b507f000000000000000000000000d8253782c45a12053594b9deb72d8e8ab2fca54c90565b90613a2f9a999897969594939291613a2a61504e565b6140bd565b90565b60207f6d652e0000000000000000000000000000000000000000000000000000000000917f53746172742074696d65206d757374206265206265666f726520656e642074695f8201520152565b613a8c60236040926107e6565b613a9581613a32565b0190565b613aae9060208101905f818303910152613a7f565b90565b15613ab857565b613ac06101c3565b62461bcd60e51b815280613ad660048201613a99565b0390fd5b5f7f53746172742074696d6520696e20706173740000000000000000000000000000910152565b613b0e60126020926107e6565b613b1781613ada565b0190565b613b309060208101905f818303910152613b01565b90565b15613b3a57565b613b426101c3565b62461bcd60e51b815280613b5860048201613b1b565b0390fd5b5f7f496e76616c696420726567697374657249640000000000000000000000000000910152565b613b9060126020926107e6565b613b9981613b5c565b0190565b613bb29060208101905f818303910152613b83565b90565b15613bbc57565b613bc46101c3565b62461bcd60e51b815280613bda60048201613b9d565b0390fd5b5f7f496e76616c6964206175746850726f7669646572496400000000000000000000910152565b613c1260166020926107e6565b613c1b81613bde565b0190565b613c349060208101905f818303910152613c05565b90565b15613c3e57565b613c466101c3565b62461bcd60e51b815280613c5c60048201613c1f565b0390fd5b5f7f496e76616c696420737673496400000000000000000000000000000000000000910152565b613c94600d6020926107e6565b613c9d81613c60565b0190565b613cb69060208101905f818303910152613c87565b90565b15613cc057565b613cc86101c3565b62461bcd60e51b815280613cde60048201613ca1565b0390fd5b90565b5f7f496e76616c6964206465736372697074696f6e20636964000000000000000000910152565b613d1960176020926107e6565b613d2281613ce5565b0190565b613d3b9060208101905f818303910152613d0c565b90565b15613d4557565b613d4d6101c3565b62461bcd60e51b815280613d6360048201613d26565b0390fd5b5f7f496e76616c696420656c656374696f6e205075624b6579000000000000000000910152565b613d9b60176020926107e6565b613da481613d67565b0190565b613dbd9060208101905f818303910152613d8e565b90565b15613dc757565b613dcf6101c3565b62461bcd60e51b815280613de560048201613da8565b0390fd5b613df2906101d5565b5f198114613e005760010190565b61229c565b5f7f416c726561647920737461727465640000000000000000000000000000000000910152565b613e39600f6020926107e6565b613e4281613e05565b0190565b613e5b9060208101905f818303910152613e2c565b90565b15613e6557565b613e6d6101c3565b62461bcd60e51b815280613e8360048201613e46565b0390fd5b90613e9461ff00916129ad565b9181191691161790565b90613eb3613eae613eba926105ee565b61298a565b8254613e87565b9055565b60101b90565b90613ed262ff000091613ebe565b9181191691161790565b90613ef1613eec613ef8926105ee565b61298a565b8254613ec4565b9055565b9190601f8111613f0c575b505050565b613f18613f3d93610bfe565b906020613f24846129f7565b83019310613f45575b613f36906129f7565b0190612a64565b5f8080613f07565b9150613f3681929050613f2d565b90613f5d81610e21565b9067ffffffffffffffff821161401d57613f8182613f7b8554610692565b85613efc565b602090601f8311600114613fb557918091613fa4935f92613fa9575b5050612aef565b90555b565b90915001515f80613f9d565b601f19831691613fc485610bfe565b925f5b81811061400557509160029391856001969410613feb575b50505002019055613fa7565b613ffb910151601f841690612ada565b90555f8080613fdf565b91936020600181928787015181550195019201613fc7565b6103c8565b9061402c91613f53565b565b97969492909593916101208901965f8a01614048916109f1565b60208901614055916109f1565b60408801614062916109f1565b6060870161406f916109f1565b6080860161407c916107c8565b60a08501614089916107c8565b60c08401614096916107c8565b82810360e08401526140a7916107fa565b908082039061010001526140ba91610e2e565b90565b9992959396949891979099506140e5886140df6140d9896101d5565b916101d5565b10613ab1565b614101886140fb6140f5426101d5565b916101d5565b11613b33565b61413b61411a5f61411460028890611824565b01610671565b61413461412e6141295f611ef8565b610206565b91610206565b1415613bb5565b6141756141545f61414e60048990611735565b01610671565b61416e6141686141635f611ef8565b610206565b91610206565b1415613c37565b6141af61418e5f6141886003859061060a565b01610671565b6141a86141a261419d5f611ef8565b610206565b91610206565b1415613cb9565b6141db6141c36141be84613ce2565b610e21565b6141d56141cf5f611a93565b916101d5565b11613d3e565b6141ff6141e784610e21565b6141f96141f35f611a93565b916101d5565b11613dc0565b8961421261420c5f611a93565b916101d5565b145f1461442f576142236001610b73565b61423661422f82613de9565b60016122f3565b5b998061424b6142455f611a93565b916101d5565b14158061440b575b6143e7575b5061426d61426860058c90610b49565b611a8d565b61431261427c60018301610b73565b61428e6142885f611a93565b916101d5565b14918280156143bd575b6142a190613e5e565b6142ae5f6006830161328d565b6142ba8d5f83016122f3565b6142c78560098301612bd0565b6142d48b600183016122f3565b6142e189600283016122f3565b6142ee876006830161298d565b6142fb8860068301613e9e565b6143088460068301613edc565b600a869101614022565b5f1461436a57614363948a989697999490919293946143517f64793360e65c496ec24f3e041ea18618308610a342ec4b80561a067f596ae24f9a610b2d565b9a61435a6101c3565b998a998a61402e565b0390a25b90565b6143b5948a989697999490919293946143a37f675c24ce14b9c24aee51df73c1db1039e34de2896a4f0045dcc1a53352c2111f9a610b2d565b9a6143ac6101c3565b998a998a61402e565b0390a2614367565b506142a16143cd60068301610be8565b6143df6143d95f610dfc565b91610dfc565b149050614298565b6143fe614405916143f86001612280565b906122b0565b60016122f3565b5f614258565b508061442861442261441d6001610b73565b6101d5565b916101d5565b1015614253565b89614237565b9061444f99989796959493929161444a612a4c565b613a14565b90565b919390926145a7614470600661446a60058790610b49565b0161063f565b6144a13361449b6144956144905f61448a60028890611824565b01610671565b610206565b91610206565b146134d4565b6144c76144af888590611b31565b6144c16144bb5f611a93565b916101d5565b1161355a565b6144ed6144d5858a90611b31565b6144e76144e15f611a93565b916101d5565b1161355a565b614520614507600161450160058990610b49565b01610b73565b6145196145135f611a93565b916101d5565b1415611b08565b61455361452d6001612280565b61454d600561453d818a90610b49565b019161454883610b73565b6122b0565b906122f3565b93949591929661459561458f6145897f9eca82030d6f3f327790a7579c2c8903421bf9cff8a13ce2edc692f099e0b100976105ee565b97610b2d565b97610b2d565b9761459e6101c3565b94859485611eaf565b0390a4565b906145be916145b961504e565b6145c0565b565b6145d46145cf60058390610b49565b611a8d565b916145fd6145e460018501610b73565b6145f66145f05f611a93565b916101d5565b1415611b08565b61462561460c60068501610be8565b9361461b60046006830161328d565b6008839101612bd0565b816146656146537f16855b8fd590df07334beb9055e3e43a8856ad0a085241abb0fd4071c4b440bf92610b2d565b9261465c6101c3565b91829182610a48565b0390a260046146947f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b926146a96146a06101c3565b928392836132ad565b0390a2565b906146b8916145ac565b565b6146c66146cb91610620565b610652565b90565b6146d890546146ba565b90565b6146e36139e3565b506146ed5f6146ce565b90565b614701906146fc61504e565b614785565b565b5f7f4e6f7420616374697665206f722070656e64696e670000000000000000000000910152565b61473760156020926107e6565b61474081614703565b0190565b6147599060208101905f81830391015261472a565b90565b1561476357565b61476b6101c3565b62461bcd60e51b81528061478160048201614744565b0390fd5b61479961479460058390610b49565b611a8d565b906147c26147a960018401610b73565b6147bb6147b55f611a93565b916101d5565b1415611b08565b6147ea6147d160028401610b73565b6147e36147dd426101d5565b916101d5565b1115613125565b6147f660068301610be8565b6148096148036001610dfc565b91610dfc565b14801561487b575b61481a9061475c565b61483561482960068401610be8565b9260066002910161328d565b60026148617f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b9261487661486d6101c3565b928392836132ad565b0390a2565b5061481a61488b60068401610be8565b61489d6148975f610dfc565b91610dfc565b149050614811565b6148ae906146f0565b565b5f7f4f6e6c7920526567697374657200000000000000000000000000000000000000910152565b6148e4600d6020926107e6565b6148ed816148b0565b0190565b6149069060208101905f8183039101526148d7565b90565b1561491057565b6149186101c3565b62461bcd60e51b81528061492e600482016148f1565b0390fd5b5f7f456c656374696f6e206e6f7420616374697665206f722070656e64696e670000910152565b614966601e6020926107e6565b61496f81614932565b0190565b6149889060208101905f818303910152614959565b90565b1561499257565b61499a6101c3565b62461bcd60e51b8152806149b060048201614973565b0390fd5b6149be6040610405565b90565b5190565b906149f0602060016149f6946149e85f82016149e25f88016149c1565b90614022565b0192016149c1565b90614022565b565b90614a02916149c5565b565b9091614a1e614a2c9360408401908482035f860152610e2e565b916020818403910152610e2e565b90565b614a75614a5d5f614a57614a506006614a4a60058890610b49565b0161063f565b6002611824565b01610671565b614a6f614a6933610206565b91610206565b14614909565b614a8c6006614a8660058490610b49565b01610be8565b614a9e614a985f610dfc565b91610dfc565b148015614b2e575b614aaf9061498b565b614ae882614ad485614acb614ac26149b4565b935f8501610cc2565b60208301610cc2565b600c614ae260058590610b49565b016149f8565b9091614b147fd564ae0c19e7c4abf1a013f9e736abe2695aa574026614ed29237392b84fa02f92610b2d565b92614b29614b206101c3565b92839283614a04565b0390a2565b50614aaf614b496006614b4360058590610b49565b01610be8565b614b5c614b566001610dfc565b91610dfc565b149050614aa6565b90614b7c6006614b7660058590610b49565b01610b94565b614bad33614ba7614ba1614b9c5f614b9660048890611735565b01610671565b610206565b91610206565b14612eab565b614be0614bc76001614bc160058790610b49565b01610b73565b614bd9614bd35f611a93565b916101d5565b1415611b08565b614c14614bed6001612280565b614c0e6004614bfe60058890610b49565b0191614c0983610b73565b6122b0565b906122f3565b91614c51614c4b614c457f82d04e43f313a2777a6868b9b6104462501c44b93e000811fb1a52b0790e8dfd956105ee565b92610b2d565b92610b2d565b92614c5a6101c3565b80614c6481610372565b0390a4565b90614c8197969594939291614c7c61504e565b614dd9565b565b5f7f456c656374696f6e206e6f7420656e6465640000000000000000000000000000910152565b614cb760126020926107e6565b614cc081614c83565b0190565b614cd99060208101905f818303910152614caa565b90565b15614ce357565b614ceb6101c3565b62461bcd60e51b815280614d0160048201614cc4565b0390fd5b5f7f4172726179206c656e677468206d69736d617463680000000000000000000000910152565b614d3960156020926107e6565b614d4281614d05565b0190565b614d5b9060208101905f818303910152614d2c565b90565b15614d6557565b614d6d6101c3565b62461bcd60e51b815280614d8360048201614d46565b0390fd5b959192614dc894614dac614dba93614dd69a989660808b01918b83035f8d0152612ee9565b9188830360208a0152612ee9565b918583036040870152612ee9565b916060818403910152610e2e565b90565b96614edb92939496959195614e96614dfb614df660058c90610b49565b611a8d565b614e23614e0a60018301610b73565b614e1c614e165f611a93565b916101d5565b1415611b08565b614e4b614e3260068301610be8565b614e45614e3f6002610dfc565b91610dfc565b14614cdc565b614e56898890612ed4565b614e68614e625f611a93565b916101d5565b1180614f5a575b80614f27575b614e7e90614d5e565b614e8c60036006830161328d565b600b849101614022565b889694959792909192614ec97fbdb1df71a7d425561df6e178e20c02d68fc55733318c8b1503f354b360ff101d98610b2d565b98614ed26101c3565b97889788614d87565b0390a26002906003614f0d7f12b37df6c3e196249962cd4347a3d9d9e6444d63d7f1bd286129f93ca919fb3d92610b2d565b92614f22614f196101c3565b928392836132ad565b0390a2565b50614e7e614f368a8990612ed4565b614f52614f4c614f47898890612ed4565b6101d5565b916101d5565b149050614e75565b50614f66898890612ed4565b614f81614f7b614f768d8c612ed4565b6101d5565b916101d5565b14614e6f565b90614f9797969594939291614c69565b565b614faa90614fa561504e565b614fac565b565b80614fc7614fc1614fbc5f611ef8565b610206565b91610206565b14614fd757614fd5906150d7565b565b614ffa614fe35f611ef8565b5f918291631e4fbdf760e01b83526004830161132c565b0390fd5b61500790614f99565b565b6150116139e3565b5061501a615208565b90565b61503e61504a9261503961504493615033612e28565b50615292565b6152c8565b92610206565b91610206565b1490565b6150566146db565b61506f615069615064615009565b610206565b91610206565b0361507657565b615098615081615009565b5f91829163118cdaa760e01b83526004830161132c565b0390fd5b906150ad60018060a01b03916122d5565b9181191691161790565b906150cc6150c76150d392611dc1565b6129d0565b825461509c565b9055565b6150e05f6146ce565b6150ea825f6150b7565b9061511e6151187f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e093611dc1565b91611dc1565b916151276101c3565b8061513181610372565b0390a3565b61514561514b919392936101d5565b926101d5565b820391821161515657565b61229c565b5f80fd5b5f80fd5b9093929384831161518357841161517e576001820201920390565b61515f565b61515b565b6bffffffffffffffffffffffff191690565b906151a86151af9183611b31565b9135615188565b90601481106151bd575b5090565b6151db906bffffffffffffffffffffffff1990601403600802612a01565b165f6151b9565b60601c90565b6151f46151f9916151e2565b611d99565b90565b615205906151e8565b90565b6152106139e3565b5061521c5f3690611b31565b615224615309565b61522d33612e2c565b80615273575b5f146152665761525861525e91615263936152505f923692615136565b908092615163565b9061519a565b6151fc565b90565b505061527061531f565b90565b5081615287615281836101d5565b916101d5565b1015615233565b5f90565b61529a61528e565b507f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f52601c52603c5f2090565b6152e7916152de916152d86139e3565b50615353565b90929192615449565b90565b90565b6153016152fc615306926152ea565b6105eb565b6101d5565b90565b615311612a4c565b5061531c60146152ed565b90565b6153276139e3565b503390565b5f90565b90565b61534761534261534c926101d5565b6122d5565b615330565b90565b5f90565b91909161535e6139e3565b5061536761532c565b5061537061528e565b5061537a83610e21565b61538d6153876041611d7d565b916101d5565b145f146153d4576153cd91926153a161528e565b506153aa61528e565b506153b361534f565b506020810151606060408301519201515f1a9091926155a3565b9192909190565b506153de5f611ef8565b906153f26153ed600294610e21565b615333565b91929190565b6004111561540257565b610dd9565b90615411826153f8565b565b61541c90615330565b9052565b9190615433905f60208501940190615413565b565b61544161544691610620565b610b2d565b90565b8061545c6154565f615407565b91615407565b145f14615467575050565b8061547b6154756001615407565b91615407565b145f1461549e575f63f645eedf60e01b81528061549a60048201610372565b0390fd5b806154b26154ac6002615407565b91615407565b145f146154e0576154dc6154c583615435565b5f91829163fce698f760e01b8352600483016109fe565b0390fd5b6154f36154ed6003615407565b91615407565b146154fb5750565b615516905f9182916335e2f38360e21b835260048301615420565b0390fd5b90565b61553161552c6155369261551a565b6105eb565b6101d5565b90565b61556e6155759461556460609498979561555a608086019a5f870190615413565b60208501906107c8565b6040830190615413565b0190615413565b565b61557f6101c3565b3d5f823e3d90fd5b61559b6155966155a092611a90565b6122d5565b615330565b90565b9392936155ae6139e3565b506155b761532c565b506155c061528e565b506155ca85615435565b6155fc6155f67f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a061551d565b916101d5565b11615689579061561f602094955f949392936156166101c3565b94859485615539565b838052039060015afa15615684576156375f516122d5565b8061565261564c6156475f611ef8565b610206565b91610206565b14615668575f916156625f615587565b91929190565b506156725f611ef8565b60019161567e5f615587565b91929190565b615577565b5050506156955f611ef8565b906003929192919056fea2646970667358221220834600c55ec0ad0cc7dad583a11b7aa80b18464cf5a688523371163bcc80f1dc64736f6c634300081b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d8253782c45a12053594b9deb72d8e8ab2fca54c0000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _trustedForwarder (address): 0xd8253782c45a12053594b9deB72d8e8aB2Fca54c
Arg [1] : startId (uint256): 0
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000d8253782c45a12053594b9deb72d8e8ab2fca54c
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in XDAI
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.