Latest 25 from a total of 1,230,718 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add For | 145186336 | 56 secs ago | IN | 0 ETH | 0.000000181104 | ||||
| Add For | 145186308 | 1 min ago | IN | 0 ETH | 0.00000018111 | ||||
| Add For | 145186282 | 2 mins ago | IN | 0 ETH | 0.000000181115 | ||||
| Add For | 145186279 | 2 mins ago | IN | 0 ETH | 0.000000181316 | ||||
| Add For | 145186202 | 5 mins ago | IN | 0 ETH | 0.000000181367 | ||||
| Add For | 145186201 | 5 mins ago | IN | 0 ETH | 0.00000019869 | ||||
| Add For | 145186183 | 6 mins ago | IN | 0 ETH | 0.000000181634 | ||||
| Add For | 145186164 | 6 mins ago | IN | 0 ETH | 0.000000181321 | ||||
| Add For | 145186125 | 7 mins ago | IN | 0 ETH | 0.000000181407 | ||||
| Add For | 145186104 | 8 mins ago | IN | 0 ETH | 0.00000018145 | ||||
| Add For | 145186089 | 9 mins ago | IN | 0 ETH | 0.000000181318 | ||||
| Add For | 145186086 | 9 mins ago | IN | 0 ETH | 0.000000181313 | ||||
| Add For | 145186083 | 9 mins ago | IN | 0 ETH | 0.000000181309 | ||||
| Add For | 145186080 | 9 mins ago | IN | 0 ETH | 0.000000181431 | ||||
| Add For | 145186001 | 12 mins ago | IN | 0 ETH | 0.000000181645 | ||||
| Add For | 145185942 | 14 mins ago | IN | 0 ETH | 0.000000181108 | ||||
| Add For | 145185922 | 14 mins ago | IN | 0 ETH | 0.000000181207 | ||||
| Add For | 145185877 | 16 mins ago | IN | 0 ETH | 0.000000181135 | ||||
| Add For | 145185866 | 16 mins ago | IN | 0 ETH | 0.000000181408 | ||||
| Add For | 145185857 | 16 mins ago | IN | 0 ETH | 0.000000181165 | ||||
| Add For | 145185850 | 17 mins ago | IN | 0 ETH | 0.000000198245 | ||||
| Add For | 145185838 | 17 mins ago | IN | 0 ETH | 0.00000019828 | ||||
| Add For | 145185803 | 18 mins ago | IN | 0 ETH | 0.000000181219 | ||||
| Add For | 145185756 | 20 mins ago | IN | 0 ETH | 0.000000181488 | ||||
| Add For | 145185724 | 21 mins ago | IN | 0 ETH | 0.000000181502 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 111816361 | 772 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
KeyGateway
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 100000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {IKeyGateway} from "./interfaces/IKeyGateway.sol";
import {IKeyRegistry} from "./interfaces/IKeyRegistry.sol";
import {EIP712} from "./abstract/EIP712.sol";
import {Nonces} from "./abstract/Nonces.sol";
import {Guardians} from "./abstract/Guardians.sol";
import {Signatures} from "./abstract/Signatures.sol";
/**
* @title Farcaster KeyGateway
*
* @notice See https://github.com/farcasterxyz/contracts/blob/v3.1.0/docs/docs.md for an overview.
*
* @custom:security-contact [email protected]
*/
contract KeyGateway is IKeyGateway, Guardians, Signatures, EIP712, Nonces {
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IKeyGateway
*/
string public constant VERSION = "2023.11.15";
/**
* @inheritdoc IKeyGateway
*/
bytes32 public constant ADD_TYPEHASH = keccak256(
"Add(address owner,uint32 keyType,bytes key,uint8 metadataType,bytes metadata,uint256 nonce,uint256 deadline)"
);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IKeyGateway
*/
IKeyRegistry public immutable keyRegistry;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Configure the address of the KeyRegistry contract.
* Set the initial owner address.
*
* @param _keyRegistry Address of the KeyRegistry contract.
* @param _initialOwner Address of the inital owner.
*/
constructor(
address _keyRegistry,
address _initialOwner
) Guardians(_initialOwner) EIP712("Farcaster KeyGateway", "1") {
keyRegistry = IKeyRegistry(_keyRegistry);
}
/*//////////////////////////////////////////////////////////////
REGISTRATION
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IKeyGateway
*/
function add(
uint32 keyType,
bytes calldata key,
uint8 metadataType,
bytes calldata metadata
) external whenNotPaused {
keyRegistry.add(msg.sender, keyType, key, metadataType, metadata);
}
/**
* @inheritdoc IKeyGateway
*/
function addFor(
address fidOwner,
uint32 keyType,
bytes calldata key,
uint8 metadataType,
bytes calldata metadata,
uint256 deadline,
bytes calldata sig
) external whenNotPaused {
_verifyAddSig(fidOwner, keyType, key, metadataType, metadata, deadline, sig);
keyRegistry.add(fidOwner, keyType, key, metadataType, metadata);
}
/*//////////////////////////////////////////////////////////////
SIGNATURE VERIFICATION HELPERS
//////////////////////////////////////////////////////////////*/
function _verifyAddSig(
address fidOwner,
uint32 keyType,
bytes memory key,
uint8 metadataType,
bytes memory metadata,
uint256 deadline,
bytes memory sig
) internal {
_verifySig(
_hashTypedDataV4(
keccak256(
abi.encode(
ADD_TYPEHASH,
fidOwner,
keyType,
keccak256(key),
metadataType,
keccak256(metadata),
_useNonce(fidOwner),
deadline
)
)
),
fidOwner,
deadline,
sig
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {IKeyRegistry} from "./IKeyRegistry.sol";
interface IKeyGateway {
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Contract version specified in the Farcaster protocol version scheme.
*/
function VERSION() external view returns (string memory);
/**
* @notice EIP-712 typehash for Add signatures.
*/
function ADD_TYPEHASH() external view returns (bytes32);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @notice The KeyRegistry contract.
*/
function keyRegistry() external view returns (IKeyRegistry);
/*//////////////////////////////////////////////////////////////
REGISTRATION
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a key associated with the caller's fid, setting the key state to ADDED.
*
* @param keyType The key's numeric keyType.
* @param key Bytes of the key to add.
* @param metadataType Metadata type ID.
* @param metadata Metadata about the key, which is not stored and only emitted in an event.
*/
function add(uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata) external;
/**
* @notice Add a key on behalf of another fid owner, setting the key state to ADDED.
* caller must supply a valid EIP-712 Add signature from the fid owner.
*
* @param fidOwner The fid owner address.
* @param keyType The key's numeric keyType.
* @param key Bytes of the key to add.
* @param metadataType Metadata type ID.
* @param metadata Metadata about the key, which is not stored and only emitted in an event.
* @param deadline Deadline after which the signature expires.
* @param sig EIP-712 Add signature generated by fid owner.
*/
function addFor(
address fidOwner,
uint32 keyType,
bytes calldata key,
uint8 metadataType,
bytes calldata metadata,
uint256 deadline,
bytes calldata sig
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {IMetadataValidator} from "./IMetadataValidator.sol";
import {IdRegistryLike} from "./IdRegistryLike.sol";
interface IKeyRegistry {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @dev Revert if a key violates KeyState transition rules.
error InvalidState();
/// @dev Revert if adding a key exceeds the maximum number of allowed keys per fid.
error ExceedsMaximum();
/// @dev Revert if a validator has not been registered for this keyType and metadataType.
error ValidatorNotFound(uint32 keyType, uint8 metadataType);
/// @dev Revert if metadata validation failed.
error InvalidMetadata();
/// @dev Revert if the admin sets a validator for keyType 0.
error InvalidKeyType();
/// @dev Revert if the admin sets a validator for metadataType 0.
error InvalidMetadataType();
/// @dev Revert if the caller does not have the authority to perform the action.
error Unauthorized();
/// @dev Revert if the owner sets maxKeysPerFid equal to or below its current value.
error InvalidMaxKeys();
/// @dev Revert when the gateway dependency is permanently frozen.
error GatewayFrozen();
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @dev Emit an event when an admin or fid adds a new key.
*
* Hubs listen for this, validate that keyBytes is an EdDSA pub key and keyType == 1 and
* add keyBytes to its SignerStore. Messages signed by keyBytes with `fid` are now valid
* and accepted over gossip, sync and client apis. Hubs assume the invariants:
*
* 1. Add(fid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with
* Add(fid, ..., key, keyBytes, ...) and no AdminReset(fid, key, keyBytes) inbetween.
*
* 2. Add(fid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with
* Remove(fid, key, keyBytes).
*
* 3. For all Add(..., ..., key, keyBytes, ...), key = keccak(keyBytes)
*
* @param fid The fid associated with the key.
* @param keyType The type of the key.
* @param key The key being registered. (indexed as hash)
* @param keyBytes The bytes of the key being registered.
* @param metadataType The type of the metadata.
* @param metadata Metadata about the key.
*/
event Add(
uint256 indexed fid,
uint32 indexed keyType,
bytes indexed key,
bytes keyBytes,
uint8 metadataType,
bytes metadata
);
/**
* @dev Emit an event when an fid removes an added key.
*
* Hubs listen for this, validate that keyType == 1 and keyBytes exists in its SignerStore.
* keyBytes is marked as removed, messages signed by keyBytes with `fid` are invalid,
* dropped immediately and no longer accepted. Hubs assume the invariants:
*
* 1. Remove(fid, key, keyBytes) cannot emit if there is no earlier emit with
* Add(fid, ..., key, keyBytes, ...)
*
* 2. Remove(fid, key, keyBytes) cannot emit if there is an earlier emit with
* Remove(fid, key, keyBytes)
*
* 3. For all Remove(..., key, keyBytes), key = keccak(keyBytes)
*
* @param fid The fid associated with the key.
* @param key The key being registered. (indexed as hash)
* @param keyBytes The bytes of the key being registered.
*/
event Remove(uint256 indexed fid, bytes indexed key, bytes keyBytes);
/**
* @dev Emit an event when an admin resets an added key.
*
* Hubs listen for this, validate that keyType == 1 and that keyBytes exists in its SignerStore.
* keyBytes is no longer tracked, messages signed by keyBytes with `fid` are invalid, dropped
* immediately and not accepted. Hubs assume the following invariants:
*
* 1. AdminReset(fid, key, keyBytes) cannot emit unless the most recent event for the fid
* was Add(fid, ..., key, keyBytes, ...).
*
* 2. For all AdminReset(..., key, keyBytes), key = keccak(keyBytes).
*
* 3. AdminReset() cannot emit after Migrated().
*
* @param fid The fid associated with the key.
* @param key The key being reset. (indexed as hash)
* @param keyBytes The bytes of the key being registered.
*/
event AdminReset(uint256 indexed fid, bytes indexed key, bytes keyBytes);
/**
* @dev Emit an event when the admin sets a metadata validator contract for a given
* keyType and metadataType.
*
* @param keyType The numeric keyType associated with this validator.
* @param metadataType The metadataType associated with this validator.
* @param oldValidator The previous validator contract address.
* @param newValidator The new validator contract address.
*/
event SetValidator(uint32 keyType, uint8 metadataType, address oldValidator, address newValidator);
/**
* @dev Emit an event when the admin sets a new IdRegistry contract address.
*
* @param oldIdRegistry The previous IdRegistry address.
* @param newIdRegistry The new IdRegistry address.
*/
event SetIdRegistry(address oldIdRegistry, address newIdRegistry);
/**
* @dev Emit an event when the admin sets a new KeyGateway address.
*
* @param oldKeyGateway The previous KeyGateway address.
* @param newKeyGateway The new KeyGateway address.
*/
event SetKeyGateway(address oldKeyGateway, address newKeyGateway);
/**
* @dev Emit an event when the admin sets a new maximum keys per fid.
*
* @param oldMax The previous maximum.
* @param newMax The new maximum.
*/
event SetMaxKeysPerFid(uint256 oldMax, uint256 newMax);
/**
* @dev Emit an event when the contract owner permanently freezes the KeyGateway address.
*
* @param keyGateway The permanent KeyGateway address.
*/
event FreezeKeyGateway(address keyGateway);
/*//////////////////////////////////////////////////////////////
STRUCTS
//////////////////////////////////////////////////////////////*/
/**
* @notice State enumeration for a key in the registry. During migration, an admin can change
* the state of any fids key from NULL to ADDED or ADDED to NULL. After migration, an
* fid can change the state of a key from NULL to ADDED or ADDED to REMOVED only.
*
* - NULL: The key is not in the registry.
* - ADDED: The key has been added to the registry.
* - REMOVED: The key was added to the registry but is now removed.
*/
enum KeyState {
NULL,
ADDED,
REMOVED
}
/**
* @notice Data about a key.
*
* @param state The current state of the key.
* @param keyType Numeric ID representing the manner in which the key should be used.
*/
struct KeyData {
KeyState state;
uint32 keyType;
}
/**
* @dev Struct argument for bulk add function, representing an FID
* and its associated keys.
*
* @param fid Fid associated with provided keys to add.
* @param keys Array of BulkAddKey structs, including key and metadata.
*/
struct BulkAddData {
uint256 fid;
BulkAddKey[] keys;
}
/**
* @dev Struct argument for bulk add function, representing a key
* and its associated metadata.
*
* @param key Bytes of the signer key.
* @param keys Metadata metadata of the signer key.
*/
struct BulkAddKey {
bytes key;
bytes metadata;
}
/**
* @dev Struct argument for bulk reset function, representing an FID
* and its associated keys.
*
* @param fid Fid associated with provided keys to reset.
* @param keys Array of keys to reset.
*/
struct BulkResetData {
uint256 fid;
bytes[] keys;
}
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Contract version specified in the Farcaster protocol version scheme.
*/
function VERSION() external view returns (string memory);
/**
* @notice EIP-712 typehash for Remove signatures.
*/
function REMOVE_TYPEHASH() external view returns (bytes32);
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @notice The IdRegistry contract.
*/
function idRegistry() external view returns (IdRegistryLike);
/**
* @notice The KeyGateway address.
*/
function keyGateway() external view returns (address);
/**
* @notice Whether the KeyGateway address is permanently frozen.
*/
function gatewayFrozen() external view returns (bool);
/**
* @notice Maximum number of keys per fid.
*/
function maxKeysPerFid() external view returns (uint256);
/*//////////////////////////////////////////////////////////////
VIEWS
//////////////////////////////////////////////////////////////*/
/**
* @notice Return number of active keys for a given fid.
*
* @param fid the fid associated with the keys.
*
* @return uint256 total number of active keys associated with the fid.
*/
function totalKeys(uint256 fid, KeyState state) external view returns (uint256);
/**
* @notice Return key at the given index in the fid's key set. Can be
* called to enumerate all active keys for a given fid.
*
* @param fid the fid associated with the key.
* @param index index of the key in the fid's key set. Must be a value
* less than totalKeys(fid). Note that because keys are
* stored in an underlying enumerable set, the ordering of
* keys is not guaranteed to be stable.
*
* @return bytes Bytes of the key.
*/
function keyAt(uint256 fid, KeyState state, uint256 index) external view returns (bytes memory);
/**
* @notice Return an array of all active keys for a given fid.
* @dev WARNING: This function will copy the entire key set to memory,
* which can be quite expensive. This is intended to be called
* offchain with eth_call, not onchain.
*
* @param fid the fid associated with the keys.
*
* @return bytes[] Array of all keys.
*/
function keysOf(uint256 fid, KeyState state) external view returns (bytes[] memory);
/**
* @notice Return an array of all active keys for a given fid,
* paged by index and batch size.
*
* @param fid The fid associated with the keys.
* @param startIdx Start index of lookup.
* @param batchSize Number of items to return.
*
* @return page Array of keys.
* @return nextIdx Next index in the set of all keys.
*/
function keysOf(
uint256 fid,
KeyState state,
uint256 startIdx,
uint256 batchSize
) external view returns (bytes[] memory page, uint256 nextIdx);
/**
* @notice Retrieve state and type data for a given key.
*
* @param fid The fid associated with the key.
* @param key Bytes of the key.
*
* @return KeyData struct that contains the state and keyType.
*/
function keyDataOf(uint256 fid, bytes calldata key) external view returns (KeyData memory);
/*//////////////////////////////////////////////////////////////
REMOVE KEYS
//////////////////////////////////////////////////////////////*/
/**
* @notice Remove a key associated with the caller's fid, setting the key state to REMOVED.
* The key must be in the ADDED state.
*
* @param key Bytes of the key to remove.
*/
function remove(bytes calldata key) external;
/**
* @notice Remove a key on behalf of another fid owner, setting the key state to REMOVED.
* caller must supply a valid EIP-712 Remove signature from the fid owner.
*
* @param fidOwner The fid owner address.
* @param key Bytes of the key to remove.
* @param deadline Deadline after which the signature expires.
* @param sig EIP-712 Remove signature generated by fid owner.
*/
function removeFor(address fidOwner, bytes calldata key, uint256 deadline, bytes calldata sig) external;
/*//////////////////////////////////////////////////////////////
PERMISSIONED ACTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Add a key associated with fidOwner's fid, setting the key state to ADDED.
* Can only be called by the keyGateway address.
*
* @param keyType The key's numeric keyType.
* @param key Bytes of the key to add.
* @param metadataType Metadata type ID.
* @param metadata Metadata about the key, which is not stored and only emitted in an event.
*/
function add(
address fidOwner,
uint32 keyType,
bytes calldata key,
uint8 metadataType,
bytes calldata metadata
) external;
/**
* @notice Add multiple keys as part of the initial migration. Only callable by the contract owner.
*
* @param items An array of BulkAddData structs including fid and array of BulkAddKey structs.
*/
function bulkAddKeysForMigration(BulkAddData[] calldata items) external;
/**
* @notice Reset multiple keys as part of the initial migration. Only callable by the contract owner.
* Reset is not the same as removal: this function sets the key state back to NULL,
* rather than REMOVED. This allows the owner to correct any errors in the initial migration until
* the grace period expires.
*
* @param items A list of BulkResetData structs including an fid and array of keys.
*/
function bulkResetKeysForMigration(BulkResetData[] calldata items) external;
/**
* @notice Set a metadata validator contract for the given keyType and metadataType. Only callable by owner.
*
* @param keyType The numeric key type ID associated with this validator.
* @param metadataType The numeric metadata type ID associated with this validator.
* @param validator Contract implementing IMetadataValidator.
*/
function setValidator(uint32 keyType, uint8 metadataType, IMetadataValidator validator) external;
/**
* @notice Set the IdRegistry contract address. Only callable by owner.
*
* @param _idRegistry The new IdRegistry address.
*/
function setIdRegistry(address _idRegistry) external;
/**
* @notice Set the KeyGateway address allowed to add keys. Only callable by owner.
*
* @param _keyGateway The new KeyGateway address.
*/
function setKeyGateway(address _keyGateway) external;
/**
* @notice Permanently freeze the KeyGateway address. Only callable by owner.
*/
function freezeKeyGateway() external;
/**
* @notice Set the maximum number of keys allowed per fid. Only callable by owner.
*
* @param _maxKeysPerFid The new max keys per fid.
*/
function setMaxKeysPerFid(uint256 _maxKeysPerFid) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {EIP712 as EIP712Base} from "openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {IEIP712} from "../interfaces/abstract/IEIP712.sol";
abstract contract EIP712 is IEIP712, EIP712Base {
constructor(string memory name, string memory version) EIP712Base(name, version) {}
/*//////////////////////////////////////////////////////////////
EIP-712 HELPERS
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IEIP712
*/
function domainSeparatorV4() external view returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @inheritdoc IEIP712
*/
function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) {
return _hashTypedDataV4(structHash);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {Nonces as NoncesBase} from "openzeppelin-latest/contracts/utils/Nonces.sol";
import {INonces} from "../interfaces/abstract/INonces.sol";
abstract contract Nonces is INonces, NoncesBase {
/*//////////////////////////////////////////////////////////////
NONCE MANAGEMENT
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc INonces
*/
function useNonce() external returns (uint256) {
return _useNonce(msg.sender);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {Ownable2Step} from "openzeppelin/contracts/access/Ownable2Step.sol";
import {Pausable} from "openzeppelin/contracts/security/Pausable.sol";
import {IGuardians} from "../interfaces/abstract/IGuardians.sol";
abstract contract Guardians is IGuardians, Ownable2Step, Pausable {
/**
* @notice Mapping of addresses to guardian status.
*/
mapping(address guardian => bool isGuardian) public guardians;
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Allow only the owner or a guardian to call the
* protected function.
*/
modifier onlyGuardian() {
if (msg.sender != owner() && !guardians[msg.sender]) {
revert OnlyGuardian();
}
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/**
* @notice Set the initial owner address.
*
* @param _initialOwner Address of the contract owner.
*/
constructor(address _initialOwner) {
_transferOwnership(_initialOwner);
}
/*//////////////////////////////////////////////////////////////
PERMISSIONED FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @inheritdoc IGuardians
*/
function addGuardian(address guardian) external onlyOwner {
guardians[guardian] = true;
emit Add(guardian);
}
/**
* @inheritdoc IGuardians
*/
function removeGuardian(address guardian) external onlyOwner {
guardians[guardian] = false;
emit Remove(guardian);
}
/**
* @inheritdoc IGuardians
*/
function pause() external onlyGuardian {
_pause();
}
/**
* @inheritdoc IGuardians
*/
function unpause() external onlyOwner {
_unpause();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import {SignatureChecker} from "openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {ISignatures} from "../interfaces/abstract/ISignatures.sol";
abstract contract Signatures is ISignatures {
/*//////////////////////////////////////////////////////////////
SIGNATURE VERIFICATION HELPERS
//////////////////////////////////////////////////////////////*/
function _verifySig(bytes32 digest, address signer, uint256 deadline, bytes memory sig) internal view {
if (block.timestamp > deadline) revert SignatureExpired();
if (!SignatureChecker.isValidSignatureNow(signer, digest, sig)) {
revert InvalidSignature();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface IMetadataValidator {
/**
* @notice Validate metadata associated with a key.
*
* @param userFid The fid associated with the key.
* @param key Bytes of the key.
* @param metadata Metadata about the key.
*
* @return bool Whether the provided key and metadata are valid.
*/
function validate(uint256 userFid, bytes memory key, bytes memory metadata) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
/**
* @dev Minimal interface for IdRegistry, used by the KeyRegistry.
*/
interface IdRegistryLike {
/*//////////////////////////////////////////////////////////////
STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @notice Maps each address to an fid, or zero if it does not own an fid.
*/
function idOf(address fidOwner) external view returns (uint256);
/*//////////////////////////////////////////////////////////////
VIEWS
//////////////////////////////////////////////////////////////*/
/**
* @notice Verify that a signature was produced by the custody address that owns an fid.
*
* @param custodyAddress The address to check the signature of.
* @param fid The fid to check the signature of.
* @param digest The digest that was signed.
* @param sig The signature to check.
*
* @return isValid Whether provided signature is valid.
*/
function verifyFidSignature(
address custodyAddress,
uint256 fid,
bytes32 digest,
bytes calldata sig
) external view returns (bool isValid);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "./ECDSA.sol";
import "../ShortStrings.sol";
import "../../interfaces/IERC5267.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
* separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the
* separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
*
* _Available since v3.4._
*
* @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
*/
abstract contract EIP712 is IERC5267 {
using ShortStrings for *;
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _cachedDomainSeparator;
uint256 private immutable _cachedChainId;
address private immutable _cachedThis;
bytes32 private immutable _hashedName;
bytes32 private immutable _hashedVersion;
ShortString private immutable _name;
ShortString private immutable _version;
string private _nameFallback;
string private _versionFallback;
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
_name = name.toShortStringWithFallback(_nameFallback);
_version = version.toShortStringWithFallback(_versionFallback);
_hashedName = keccak256(bytes(name));
_hashedVersion = keccak256(bytes(version));
_cachedChainId = block.chainid;
_cachedDomainSeparator = _buildDomainSeparator();
_cachedThis = address(this);
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
return _cachedDomainSeparator;
} else {
return _buildDomainSeparator();
}
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
/**
* @dev See {EIP-5267}.
*
* _Available since v4.9._
*/
function eip712Domain()
public
view
virtual
override
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
)
{
return (
hex"0f", // 01111
_name.toStringWithFallback(_nameFallback),
_version.toStringWithFallback(_versionFallback),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
interface IEIP712 {
/*//////////////////////////////////////////////////////////////
EIP-712 HELPERS
//////////////////////////////////////////////////////////////*/
/**
* @notice Helper view to read EIP-712 domain separator.
*
* @return bytes32 domain separator hash.
*/
function domainSeparatorV4() external view returns (bytes32);
/**
* @notice Helper view to hash EIP-712 typed data onchain.
*
* @param structHash EIP-712 typed data hash.
*
* @return bytes32 EIP-712 message digest.
*/
function hashTypedDataV4(bytes32 structHash) external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @dev Provides tracking nonces for addresses. Nonces will only increment.
*/
abstract contract Nonces {
/**
* @dev The nonce used for an `account` is not the expected current nonce.
*/
error InvalidAccountNonce(address account, uint256 currentNonce);
mapping(address => uint256) private _nonces;
/**
* @dev Returns an the next unused nonce for an address.
*/
function nonces(address owner) public view virtual returns (uint256) {
return _nonces[owner];
}
/**
* @dev Consumes a nonce.
*
* Returns the current value and increments nonce.
*/
function _useNonce(address owner) internal virtual returns (uint256) {
// For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
// decremented or reset. This guarantees that the nonce never overflows.
unchecked {
// It is important to do x++ and not ++x here.
return _nonces[owner]++;
}
}
/**
* @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
*/
function _useCheckedNonce(address owner, uint256 nonce) internal virtual returns (uint256) {
uint256 current = _useNonce(owner);
if (nonce != current) {
revert InvalidAccountNonce(owner, current);
}
return current;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
interface INonces {
/*//////////////////////////////////////////////////////////////
NONCE MANAGEMENT
//////////////////////////////////////////////////////////////*/
/**
* @notice Increase caller's nonce, invalidating previous signatures.
*
* @return uint256 The caller's new nonce.
*/
function useNonce() external returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
interface IGuardians {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @dev Emit an event when owner adds a new guardian address.
*
* @param guardian Address of the added guardian.
*/
event Add(address indexed guardian);
/**
* @dev Emit an event when owner removes a guardian address.
*
* @param guardian Address of the removed guardian.
*/
event Remove(address indexed guardian);
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @dev Revert if an unauthorized caller calls a protected function.
error OnlyGuardian();
/*//////////////////////////////////////////////////////////////
PERMISSIONED FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Add an address as a guardian. Only callable by owner.
*
* @param guardian Address of the guardian.
*/
function addGuardian(address guardian) external;
/**
* @notice Remove a guardian. Only callable by owner.
*
* @param guardian Address of the guardian.
*/
function removeGuardian(address guardian) external;
/**
* @notice Pause the contract. Only callable by owner or a guardian.
*/
function pause() external;
/**
* @notice Unpause the contract. Only callable by owner.
*/
function unpause() external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
interface ISignatures {
/*//////////////////////////////////////////////////////////////
ERRORS
//////////////////////////////////////////////////////////////*/
/// @dev Revert when the signature provided is invalid.
error InvalidSignature();
/// @dev Revert when the block.timestamp is ahead of the signature deadline.
error SignatureExpired();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @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,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* 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]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
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.
/// @solidity memory-safe-assembly
assembly {
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);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
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[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
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.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// 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);
}
// 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);
}
return (signer, RecoverError.NoError);
}
/**
* @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) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)
pragma solidity ^0.8.8;
import "./StorageSlot.sol";
// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |
// | length | 0x BB |
type ShortString is bytes32;
/**
* @dev This library provides functions to convert short memory strings
* into a `ShortString` type that can be used as an immutable variable.
*
* Strings of arbitrary length can be optimized using this library if
* they are short enough (up to 31 bytes) by packing them with their
* length (1 byte) in a single EVM word (32 bytes). Additionally, a
* fallback mechanism can be used for every other case.
*
* Usage example:
*
* ```solidity
* contract Named {
* using ShortStrings for *;
*
* ShortString private immutable _name;
* string private _nameFallback;
*
* constructor(string memory contractName) {
* _name = contractName.toShortStringWithFallback(_nameFallback);
* }
*
* function name() external view returns (string memory) {
* return _name.toStringWithFallback(_nameFallback);
* }
* }
* ```
*/
library ShortStrings {
// Used as an identifier for strings longer than 31 bytes.
bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;
error StringTooLong(string str);
error InvalidShortString();
/**
* @dev Encode a string of at most 31 chars into a `ShortString`.
*
* This will trigger a `StringTooLong` error is the input string is too long.
*/
function toShortString(string memory str) internal pure returns (ShortString) {
bytes memory bstr = bytes(str);
if (bstr.length > 31) {
revert StringTooLong(str);
}
return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
}
/**
* @dev Decode a `ShortString` back to a "normal" string.
*/
function toString(ShortString sstr) internal pure returns (string memory) {
uint256 len = byteLength(sstr);
// using `new string(len)` would work locally but is not memory safe.
string memory str = new string(32);
/// @solidity memory-safe-assembly
assembly {
mstore(str, len)
mstore(add(str, 0x20), sstr)
}
return str;
}
/**
* @dev Return the length of a `ShortString`.
*/
function byteLength(ShortString sstr) internal pure returns (uint256) {
uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
if (result > 31) {
revert InvalidShortString();
}
return result;
}
/**
* @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
*/
function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
if (bytes(value).length < 32) {
return toShortString(value);
} else {
StorageSlot.getStringSlot(store).value = value;
return ShortString.wrap(_FALLBACK_SENTINEL);
}
}
/**
* @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*/
function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return toString(value);
} else {
return store;
}
}
/**
* @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
*
* WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
* actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
*/
function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
return byteLength(value);
} else {
return bytes(store).length;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267 {
/**
* @dev MAY be emitted to signal that the domain could have changed.
*/
event EIP712DomainChanged();
/**
* @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
* signature.
*/
function eip712Domain()
external
view
returns (
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @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;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(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) {
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] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
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 Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev 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 {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 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 prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// 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^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return 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 {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"remappings": [
"solmate/=lib/solmate/",
"openzeppelin/=lib/openzeppelin-contracts/",
"openzeppelin-latest/=lib/openzeppelin-latest/",
"chainlink/=lib/chainlink-brownie-contracts/contracts/src/",
"chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-latest/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_keyRegistry","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"OnlyGuardian","type":"error"},{"inputs":[],"name":"SignatureExpired","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"Add","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"Remove","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"ADD_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"keyType","type":"uint32"},{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"uint8","name":"metadataType","type":"uint8"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fidOwner","type":"address"},{"internalType":"uint32","name":"keyType","type":"uint32"},{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"uint8","name":"metadataType","type":"uint8"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"addFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"addGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparatorV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"guardians","outputs":[{"internalType":"bool","name":"isGuardian","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"structHash","type":"bytes32"}],"name":"hashTypedDataV4","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyRegistry","outputs":[{"internalType":"contract IKeyRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"removeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101806040523480156200001257600080fd5b5060405162001e6438038062001e6483398101604081905262000035916200029a565b6040518060400160405280601481526020017f466172636173746572204b657947617465776179000000000000000000000000815250604051806040016040528060018152602001603160f81b815250818184620000a26200009c6200018660201b60201c565b6200018a565b6001805460ff60a01b19169055620000ba816200018a565b50620000c8826003620001a8565b61012052620000d9816004620001a8565b61014052815160208084019190912060e052815190820120610100524660a0526200016760e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c0525050506001600160a01b031661016052620004b8565b3390565b600180546001600160a01b0319169055620001a581620001e1565b50565b6000602083511015620001c857620001c08362000231565b9050620001db565b81620001d5848262000377565b5060ff90505b92915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080829050601f8151111562000268578260405163305a27a960e01b81526004016200025f919062000443565b60405180910390fd5b8051620002758262000493565b179392505050565b80516001600160a01b03811681146200029557600080fd5b919050565b60008060408385031215620002ae57600080fd5b620002b9836200027d565b9150620002c9602084016200027d565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002fd57607f821691505b6020821081036200031e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200037257600081815260208120601f850160051c810160208610156200034d5750805b601f850160051c820191505b818110156200036e5782815560010162000359565b5050505b505050565b81516001600160401b03811115620003935762000393620002d2565b620003ab81620003a48454620002e8565b8462000324565b602080601f831160018114620003e35760008415620003ca5750858301515b600019600386901b1c1916600185901b1785556200036e565b600085815260208120601f198616915b828110156200041457888601518255948401946001909101908401620003f3565b5085821015620004335787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620004725785810183015185820160400152820162000454565b506000604082860101526040601f19601f8301168501019250505092915050565b805160208083015191908110156200031e5760001960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051610160516119386200052c600039600081816101b90152818161042c015261082f015260006106d1015260006106a601526000610cc001526000610c9801526000610bf301526000610c1d01526000610c4701526119386000f3fe608060405234801561001057600080fd5b50600436106101775760003560e01c806379ba5097116100d8578063a005d3d21161008c578063e30c397811610066578063e30c39781461036d578063f2fde38b1461038b578063ffa1ad741461039e57600080fd5b8063a005d3d214610320578063a526d83b14610333578063ab583c1b1461034657600080fd5b80638456cb59116100bd5780638456cb59146102df57806384b0196e146102e75780638da5cb5b1461030257600080fd5b806379ba5097146102a15780637ecebe00146102a957600080fd5b80635c975abb1161012f5780637140415611610114578063714041561461027e578063715018a61461029157806378e890ba1461029957600080fd5b80635c975abb1461023e57806369615a4c1461026157600080fd5b806322b1a4141161016057806322b1a414146102005780633f4ba83a146102155780634980f2881461021d57600080fd5b80630633b14a1461017c578063086b5198146101b4575b600080fd5b61019f61018a366004611453565b60026020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6101db7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ab565b61021361020e3660046114dc565b6103e7565b005b6102136104a7565b61023061022b366004611570565b6104b9565b6040519081526020016101ab565b60015474010000000000000000000000000000000000000000900460ff1661019f565b336000908152600560205260409020805460018101909155610230565b61021361028c366004611453565b6104cf565b61021361054b565b61023061055d565b610213610567565b6102306102b7366004611453565b73ffffffffffffffffffffffffffffffffffffffff1660009081526005602052604090205490565b610213610621565b6102ef610698565b6040516101ab97969594939291906115f7565b60005473ffffffffffffffffffffffffffffffffffffffff166101db565b61021361032e3660046116b6565b61073d565b610213610341366004611453565b6108ae565b6102307f4b433bd06b4af9895086805d78f8acbe4b07223722f4feff3ee4393feb4fd75481565b60015473ffffffffffffffffffffffffffffffffffffffff166101db565b610213610399366004611453565b61092d565b6103da6040518060400160405280600a81526020017f323032332e31312e31350000000000000000000000000000000000000000000081525081565b6040516101ab9190611791565b6103ef6109dd565b6040517f207e3d6900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063207e3d699061046d9033908a908a908a908a908a908a906004016117ed565b600060405180830381600087803b15801561048757600080fd5b505af115801561049b573d6000803e3d6000fd5b50505050505050505050565b6104af610a62565b6104b7610ae3565b565b60006104c482610b60565b92915050565b905090565b6104d7610a62565b73ffffffffffffffffffffffffffffffffffffffff811660008181526002602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fbe7c7ac3248df4581c206a84aab3cb4e7d521b5398b42b681757f78a5a7d411e9190a250565b610553610a62565b6104b76000610ba8565b60006104ca610bd9565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610615576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e6572000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61061e81610ba8565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331480159061065957503360009081526002602052604090205460ff16155b15610690576040517fcae1d95600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104b7610d11565b6000606080828080836106cc7f00000000000000000000000000000000000000000000000000000000000000006003610d80565b6106f77f00000000000000000000000000000000000000000000000000000000000000006004610d80565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6107456109dd565b6107f28a8a8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528d935091508b908b908190840183828082843760009201919091525050604080516020601f8c018190048102820181019092528a81528c935091508a908a9081908401838280828437600092019190915250610e2c92505050565b6040517f207e3d6900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063207e3d6990610870908d908d908d908d908d908d908d906004016117ed565b600060405180830381600087803b15801561088a57600080fd5b505af115801561089e573d6000803e3d6000fd5b5050505050505050505050505050565b6108b6610a62565b73ffffffffffffffffffffffffffffffffffffffff811660008181526002602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f87dc5eecd6d6bdeae407c426da6bfba5b7190befc554ed5d4d62dd5cf939fbae9190a250565b610935610a62565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811790915561099860005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60015474010000000000000000000000000000000000000000900460ff16156104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161060c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161060c565b610aeb610f24565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60006104c4610b6d610bd9565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561061e81610fa8565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015610c3f57507f000000000000000000000000000000000000000000000000000000000000000046145b15610c6957507f000000000000000000000000000000000000000000000000000000000000000090565b6104ca604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b610d196109dd565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b363390565b606060ff8314610d9a57610d938361101d565b90506104c4565b818054610da690611853565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd290611853565b8015610e1f5780601f10610df457610100808354040283529160200191610e1f565b820191906000526020600020905b815481529060010190602001808311610e0257829003601f168201915b5050505050905092915050565b610f1b610f137f4b433bd06b4af9895086805d78f8acbe4b07223722f4feff3ee4393feb4fd75489898980519060200120898980519060200120610e9a8f73ffffffffffffffffffffffffffffffffffffffff16600090815260056020526040902080546001810190915590565b60408051602081019890985273ffffffffffffffffffffffffffffffffffffffff9096169587019590955263ffffffff9093166060860152608085019190915260ff1660a084015260c083015260e082015261010081018590526101200160405160208183030381529060405280519060200120610b60565b88848461105c565b50505050505050565b60015474010000000000000000000000000000000000000000900460ff166104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161060c565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060600061102a836110dd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b81421115611096576040517f0819bdcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a183858361111e565b6110d7576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b600060ff8216601f8111156104c4576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600061112d8585611199565b90925090506000816004811115611146576111466118a6565b14801561117e57508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b8061118f575061118f8686866111de565b9695505050505050565b60008082516041036111cf5760208301516040840151606085015160001a6111c38782858561133b565b945094505050506111d7565b506000905060025b9250929050565b60008060008573ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b86866040516024016112159291906118d5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161129e91906118f6565b600060405180830381855afa9150503d80600081146112d9576040519150601f19603f3d011682016040523d82523d6000602084013e6112de565b606091505b50915091508180156112f257506020815110155b801561118f575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906113309083016020908101908401611912565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156113725750600090506003611421565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156113c6573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661141a57600060019250925050611421565b9150600090505b94509492505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461144e57600080fd5b919050565b60006020828403121561146557600080fd5b61146e8261142a565b9392505050565b803563ffffffff8116811461144e57600080fd5b60008083601f84011261149b57600080fd5b50813567ffffffffffffffff8111156114b357600080fd5b6020830191508360208285010111156111d757600080fd5b803560ff8116811461144e57600080fd5b600080600080600080608087890312156114f557600080fd5b6114fe87611475565b9550602087013567ffffffffffffffff8082111561151b57600080fd5b6115278a838b01611489565b909750955085915061153b60408a016114cb565b9450606089013591508082111561155157600080fd5b5061155e89828a01611489565b979a9699509497509295939492505050565b60006020828403121561158257600080fd5b5035919050565b60005b838110156115a457818101518382015260200161158c565b50506000910152565b600081518084526115c5816020860160208601611589565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e08184015261163360e084018a6115ad565b8381036040850152611645818a6115ad565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156116a457835183529284019291840191600101611688565b50909c9b505050505050505050505050565b60008060008060008060008060008060e08b8d0312156116d557600080fd5b6116de8b61142a565b99506116ec60208c01611475565b985060408b013567ffffffffffffffff8082111561170957600080fd5b6117158e838f01611489565b909a50985088915061172960608e016114cb565b975060808d013591508082111561173f57600080fd5b61174b8e838f01611489565b909750955060a08d0135945060c08d013591508082111561176b57600080fd5b506117788d828e01611489565b915080935050809150509295989b9194979a5092959850565b60208152600061146e60208301846115ad565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8816815263ffffffff8716602082015260a06040820152600061182960a0830187896117a4565b60ff8616606084015282810360808401526118458185876117a4565b9a9950505050505050505050565b600181811c9082168061186757607f821691505b6020821081036118a0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8281526040602082015260006118ee60408301846115ad565b949350505050565b60008251611908818460208701611589565b9190910192915050565b60006020828403121561192457600080fd5b505191905056fea164736f6c6343000815000a00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e00000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b692
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101775760003560e01c806379ba5097116100d8578063a005d3d21161008c578063e30c397811610066578063e30c39781461036d578063f2fde38b1461038b578063ffa1ad741461039e57600080fd5b8063a005d3d214610320578063a526d83b14610333578063ab583c1b1461034657600080fd5b80638456cb59116100bd5780638456cb59146102df57806384b0196e146102e75780638da5cb5b1461030257600080fd5b806379ba5097146102a15780637ecebe00146102a957600080fd5b80635c975abb1161012f5780637140415611610114578063714041561461027e578063715018a61461029157806378e890ba1461029957600080fd5b80635c975abb1461023e57806369615a4c1461026157600080fd5b806322b1a4141161016057806322b1a414146102005780633f4ba83a146102155780634980f2881461021d57600080fd5b80630633b14a1461017c578063086b5198146101b4575b600080fd5b61019f61018a366004611453565b60026020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6101db7f00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ab565b61021361020e3660046114dc565b6103e7565b005b6102136104a7565b61023061022b366004611570565b6104b9565b6040519081526020016101ab565b60015474010000000000000000000000000000000000000000900460ff1661019f565b336000908152600560205260409020805460018101909155610230565b61021361028c366004611453565b6104cf565b61021361054b565b61023061055d565b610213610567565b6102306102b7366004611453565b73ffffffffffffffffffffffffffffffffffffffff1660009081526005602052604090205490565b610213610621565b6102ef610698565b6040516101ab97969594939291906115f7565b60005473ffffffffffffffffffffffffffffffffffffffff166101db565b61021361032e3660046116b6565b61073d565b610213610341366004611453565b6108ae565b6102307f4b433bd06b4af9895086805d78f8acbe4b07223722f4feff3ee4393feb4fd75481565b60015473ffffffffffffffffffffffffffffffffffffffff166101db565b610213610399366004611453565b61092d565b6103da6040518060400160405280600a81526020017f323032332e31312e31350000000000000000000000000000000000000000000081525081565b6040516101ab9190611791565b6103ef6109dd565b6040517f207e3d6900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e169063207e3d699061046d9033908a908a908a908a908a908a906004016117ed565b600060405180830381600087803b15801561048757600080fd5b505af115801561049b573d6000803e3d6000fd5b50505050505050505050565b6104af610a62565b6104b7610ae3565b565b60006104c482610b60565b92915050565b905090565b6104d7610a62565b73ffffffffffffffffffffffffffffffffffffffff811660008181526002602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517fbe7c7ac3248df4581c206a84aab3cb4e7d521b5398b42b681757f78a5a7d411e9190a250565b610553610a62565b6104b76000610ba8565b60006104ca610bd9565b600154339073ffffffffffffffffffffffffffffffffffffffff168114610615576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e6572000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61061e81610ba8565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331480159061065957503360009081526002602052604090205460ff16155b15610690576040517fcae1d95600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104b7610d11565b6000606080828080836106cc7f466172636173746572204b6579476174657761790000000000000000000000146003610d80565b6106f77f31000000000000000000000000000000000000000000000000000000000000016004610d80565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6107456109dd565b6107f28a8a8a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8d018190048102820181019092528b81528d935091508b908b908190840183828082843760009201919091525050604080516020601f8c018190048102820181019092528a81528c935091508a908a9081908401838280828437600092019190915250610e2c92505050565b6040517f207e3d6900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e169063207e3d6990610870908d908d908d908d908d908d908d906004016117ed565b600060405180830381600087803b15801561088a57600080fd5b505af115801561089e573d6000803e3d6000fd5b5050505050505050505050505050565b6108b6610a62565b73ffffffffffffffffffffffffffffffffffffffff811660008181526002602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f87dc5eecd6d6bdeae407c426da6bfba5b7190befc554ed5d4d62dd5cf939fbae9190a250565b610935610a62565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811790915561099860005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60015474010000000000000000000000000000000000000000900460ff16156104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a2070617573656400000000000000000000000000000000604482015260640161060c565b60005473ffffffffffffffffffffffffffffffffffffffff1633146104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161060c565b610aeb610f24565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b60006104c4610b6d610bd9565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561061e81610fa8565b60003073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000fc56947c7e7183f8ca4b62398caadf0b16148015610c3f57507f000000000000000000000000000000000000000000000000000000000000000a46145b15610c6957507ff44c21da8a87a6bc7004b59246498e3412f2bca217e65b3799c183a7da1dbb6190565b6104ca604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fbd24452010736d626a45975931a5c2852885733f5a1f80ee14f3390c0b0eaf0c918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b610d196109dd565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258610b363390565b606060ff8314610d9a57610d938361101d565b90506104c4565b818054610da690611853565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd290611853565b8015610e1f5780601f10610df457610100808354040283529160200191610e1f565b820191906000526020600020905b815481529060010190602001808311610e0257829003601f168201915b5050505050905092915050565b610f1b610f137f4b433bd06b4af9895086805d78f8acbe4b07223722f4feff3ee4393feb4fd75489898980519060200120898980519060200120610e9a8f73ffffffffffffffffffffffffffffffffffffffff16600090815260056020526040902080546001810190915590565b60408051602081019890985273ffffffffffffffffffffffffffffffffffffffff9096169587019590955263ffffffff9093166060860152608085019190915260ff1660a084015260c083015260e082015261010081018590526101200160405160208183030381529060405280519060200120610b60565b88848461105c565b50505050505050565b60015474010000000000000000000000000000000000000000900460ff166104b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f7420706175736564000000000000000000000000604482015260640161060c565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6060600061102a836110dd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b81421115611096576040517f0819bdcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110a183858361111e565b6110d7576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b600060ff8216601f8111156104c4576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080600061112d8585611199565b90925090506000816004811115611146576111466118a6565b14801561117e57508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b8061118f575061118f8686866111de565b9695505050505050565b60008082516041036111cf5760208301516040840151606085015160001a6111c38782858561133b565b945094505050506111d7565b506000905060025b9250929050565b60008060008573ffffffffffffffffffffffffffffffffffffffff16631626ba7e60e01b86866040516024016112159291906118d5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161129e91906118f6565b600060405180830381855afa9150503d80600081146112d9576040519150601f19603f3d011682016040523d82523d6000602084013e6112de565b606091505b50915091508180156112f257506020815110155b801561118f575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906113309083016020908101908401611912565b149695505050505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156113725750600090506003611421565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156113c6573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661141a57600060019250925050611421565b9150600090505b94509492505050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461144e57600080fd5b919050565b60006020828403121561146557600080fd5b61146e8261142a565b9392505050565b803563ffffffff8116811461144e57600080fd5b60008083601f84011261149b57600080fd5b50813567ffffffffffffffff8111156114b357600080fd5b6020830191508360208285010111156111d757600080fd5b803560ff8116811461144e57600080fd5b600080600080600080608087890312156114f557600080fd5b6114fe87611475565b9550602087013567ffffffffffffffff8082111561151b57600080fd5b6115278a838b01611489565b909750955085915061153b60408a016114cb565b9450606089013591508082111561155157600080fd5b5061155e89828a01611489565b979a9699509497509295939492505050565b60006020828403121561158257600080fd5b5035919050565b60005b838110156115a457818101518382015260200161158c565b50506000910152565b600081518084526115c5816020860160208601611589565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e08184015261163360e084018a6115ad565b8381036040850152611645818a6115ad565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156116a457835183529284019291840191600101611688565b50909c9b505050505050505050505050565b60008060008060008060008060008060e08b8d0312156116d557600080fd5b6116de8b61142a565b99506116ec60208c01611475565b985060408b013567ffffffffffffffff8082111561170957600080fd5b6117158e838f01611489565b909a50985088915061172960608e016114cb565b975060808d013591508082111561173f57600080fd5b61174b8e838f01611489565b909750955060a08d0135945060c08d013591508082111561176b57600080fd5b506117788d828e01611489565b915080935050809150509295989b9194979a5092959850565b60208152600061146e60208301846115ad565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8816815263ffffffff8716602082015260a06040820152600061182960a0830187896117a4565b60ff8616606084015282810360808401526118458185876117a4565b9a9950505050505050505050565b600181811c9082168061186757607f821691505b6020821081036118a0577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8281526040602082015260006118ee60408301846115ad565b949350505050565b60008251611908818460208701611589565b9190910192915050565b60006020828403121561192457600080fd5b505191905056fea164736f6c6343000815000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e00000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b692
-----Decoded View---------------
Arg [0] : _keyRegistry (address): 0x00000000Fc1237824fb747aBDE0FF18990E59b7e
Arg [1] : _initialOwner (address): 0x53c6dA835c777AD11159198FBe11f95E5eE6B692
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000fc1237824fb747abde0ff18990e59b7e
Arg [1] : 00000000000000000000000053c6da835c777ad11159198fbe11f95e5ee6b692
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.