Source Code
Overview
CELO Balance
CELO Value
$0.00Multichain Info
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SuperChainResolver
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {SchemaResolver} from "eas-contracts/resolver/SchemaResolver.sol";
import {IEAS, Attestation} from "eas-contracts/IEAS.sol";
import {SuperChainModuleUpgradeable} from "./SuperChainModuleUpgradeable.sol";
import "./SuperChainBadges.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract SuperChainResolver is SchemaResolver, Ownable {
SuperChainModuleUpgradeable public superChainModule;
SuperChainBadges public superChainBadges;
address public attestator;
constructor(
IEAS eas,
address _attestator,
SuperChainBadges _superChainBadges,
address owner
) Ownable(owner) SchemaResolver(eas) {
attestator = _attestator;
superChainBadges = _superChainBadges;
}
// This might be onlyOwner
function updateSuperChainAccountsManager(
SuperChainModuleUpgradeable _superChainModule
) public onlyOwner {
superChainModule = _superChainModule;
}
function updateAttestator(address _attestator) public onlyOwner {
attestator = _attestator;
}
function updateSuperChainBadges(
SuperChainBadges _superChainBadges
) public onlyOwner {
superChainBadges = _superChainBadges;
}
function onAttest(
Attestation calldata attestation,
uint256 /*value*/
) internal override returns (bool) {
if (attestation.attester != attestator) {
return false;
}
BadgeUpdate[] memory badgeUpdates = abi.decode(
attestation.data,
(BadgeUpdate[])
);
uint256 points = superChainBadges.updateOrMintBadges(
attestation.recipient,
badgeUpdates
);
superChainModule.incrementSuperChainPoints(
points,
attestation.recipient
);
return true;
}
function onRevoke(
Attestation calldata,
/*attestation*/ uint256 /*value*/
) internal pure override returns (bool) {
return true;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import { IEAS, Attestation } from "../IEAS.sol";
import { AccessDenied, InvalidEAS, InvalidLength, uncheckedInc } from "../Common.sol";
import { Semver } from "../Semver.sol";
import { ISchemaResolver } from "./ISchemaResolver.sol";
/// @title SchemaResolver
/// @notice The base schema resolver contract.
abstract contract SchemaResolver is ISchemaResolver, Semver {
error InsufficientValue();
error NotPayable();
// The global EAS contract.
IEAS internal immutable _eas;
/// @dev Creates a new resolver.
/// @param eas The address of the global EAS contract.
constructor(IEAS eas) Semver(1, 3, 0) {
if (address(eas) == address(0)) {
revert InvalidEAS();
}
_eas = eas;
}
/// @dev Ensures that only the EAS contract can make this call.
modifier onlyEAS() {
_onlyEAS();
_;
}
/// @inheritdoc ISchemaResolver
function isPayable() public pure virtual returns (bool) {
return false;
}
/// @dev ETH callback.
receive() external payable virtual {
if (!isPayable()) {
revert NotPayable();
}
}
/// @inheritdoc ISchemaResolver
function attest(Attestation calldata attestation) external payable onlyEAS returns (bool) {
return onAttest(attestation, msg.value);
}
/// @inheritdoc ISchemaResolver
function multiAttest(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable onlyEAS returns (bool) {
uint256 length = attestations.length;
if (length != values.length) {
revert InvalidLength();
}
// We are keeping track of the remaining ETH amount that can be sent to resolvers and will keep deducting
// from it to verify that there isn't any attempt to send too much ETH to resolvers. Please note that unless
// some ETH was stuck in the contract by accident (which shouldn't happen in normal conditions), it won't be
// possible to send too much ETH anyway.
uint256 remainingValue = msg.value;
for (uint256 i = 0; i < length; i = uncheckedInc(i)) {
// Ensure that the attester/revoker doesn't try to spend more than available.
uint256 value = values[i];
if (value > remainingValue) {
revert InsufficientValue();
}
// Forward the attestation to the underlying resolver and return false in case it isn't approved.
if (!onAttest(attestations[i], value)) {
return false;
}
unchecked {
// Subtract the ETH amount, that was provided to this attestation, from the global remaining ETH amount.
remainingValue -= value;
}
}
return true;
}
/// @inheritdoc ISchemaResolver
function revoke(Attestation calldata attestation) external payable onlyEAS returns (bool) {
return onRevoke(attestation, msg.value);
}
/// @inheritdoc ISchemaResolver
function multiRevoke(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable onlyEAS returns (bool) {
uint256 length = attestations.length;
if (length != values.length) {
revert InvalidLength();
}
// We are keeping track of the remaining ETH amount that can be sent to resolvers and will keep deducting
// from it to verify that there isn't any attempt to send too much ETH to resolvers. Please note that unless
// some ETH was stuck in the contract by accident (which shouldn't happen in normal conditions), it won't be
// possible to send too much ETH anyway.
uint256 remainingValue = msg.value;
for (uint256 i = 0; i < length; i = uncheckedInc(i)) {
// Ensure that the attester/revoker doesn't try to spend more than available.
uint256 value = values[i];
if (value > remainingValue) {
revert InsufficientValue();
}
// Forward the revocation to the underlying resolver and return false in case it isn't approved.
if (!onRevoke(attestations[i], value)) {
return false;
}
unchecked {
// Subtract the ETH amount, that was provided to this attestation, from the global remaining ETH amount.
remainingValue -= value;
}
}
return true;
}
/// @notice A resolver callback that should be implemented by child contracts.
/// @param attestation The new attestation.
/// @param value An explicit ETH amount that was sent to the resolver. Please note that this value is verified in
/// both attest() and multiAttest() callbacks EAS-only callbacks and that in case of multi attestations, it'll
/// usually hold that msg.value != value, since msg.value aggregated the sent ETH amounts for all the
/// attestations in the batch.
/// @return Whether the attestation is valid.
function onAttest(Attestation calldata attestation, uint256 value) internal virtual returns (bool);
/// @notice Processes an attestation revocation and verifies if it can be revoked.
/// @param attestation The existing attestation to be revoked.
/// @param value An explicit ETH amount that was sent to the resolver. Please note that this value is verified in
/// both revoke() and multiRevoke() callbacks EAS-only callbacks and that in case of multi attestations, it'll
/// usually hold that msg.value != value, since msg.value aggregated the sent ETH amounts for all the
/// attestations in the batch.
/// @return Whether the attestation can be revoked.
function onRevoke(Attestation calldata attestation, uint256 value) internal virtual returns (bool);
/// @dev Ensures that only the EAS contract can make this call.
function _onlyEAS() private view {
if (msg.sender != address(_eas)) {
revert AccessDenied();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ISchemaRegistry } from "./ISchemaRegistry.sol";
import { ISemver } from "./ISemver.sol";
import { Attestation, Signature } from "./Common.sol";
/// @notice A struct representing the arguments of the attestation request.
struct AttestationRequestData {
address recipient; // The recipient of the attestation.
uint64 expirationTime; // The time when the attestation expires (Unix timestamp).
bool revocable; // Whether the attestation is revocable.
bytes32 refUID; // The UID of the related attestation.
bytes data; // Custom attestation data.
uint256 value; // An explicit ETH amount to send to the resolver. This is important to prevent accidental user errors.
}
/// @notice A struct representing the full arguments of the attestation request.
struct AttestationRequest {
bytes32 schema; // The unique identifier of the schema.
AttestationRequestData data; // The arguments of the attestation request.
}
/// @notice A struct representing the full arguments of the full delegated attestation request.
struct DelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema.
AttestationRequestData data; // The arguments of the attestation request.
Signature signature; // The ECDSA signature data.
address attester; // The attesting account.
uint64 deadline; // The deadline of the signature/request.
}
/// @notice A struct representing the full arguments of the multi attestation request.
struct MultiAttestationRequest {
bytes32 schema; // The unique identifier of the schema.
AttestationRequestData[] data; // The arguments of the attestation request.
}
/// @notice A struct representing the full arguments of the delegated multi attestation request.
struct MultiDelegatedAttestationRequest {
bytes32 schema; // The unique identifier of the schema.
AttestationRequestData[] data; // The arguments of the attestation requests.
Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with increasing nonces.
address attester; // The attesting account.
uint64 deadline; // The deadline of the signature/request.
}
/// @notice A struct representing the arguments of the revocation request.
struct RevocationRequestData {
bytes32 uid; // The UID of the attestation to revoke.
uint256 value; // An explicit ETH amount to send to the resolver. This is important to prevent accidental user errors.
}
/// @notice A struct representing the full arguments of the revocation request.
struct RevocationRequest {
bytes32 schema; // The unique identifier of the schema.
RevocationRequestData data; // The arguments of the revocation request.
}
/// @notice A struct representing the arguments of the full delegated revocation request.
struct DelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema.
RevocationRequestData data; // The arguments of the revocation request.
Signature signature; // The ECDSA signature data.
address revoker; // The revoking account.
uint64 deadline; // The deadline of the signature/request.
}
/// @notice A struct representing the full arguments of the multi revocation request.
struct MultiRevocationRequest {
bytes32 schema; // The unique identifier of the schema.
RevocationRequestData[] data; // The arguments of the revocation request.
}
/// @notice A struct representing the full arguments of the delegated multi revocation request.
struct MultiDelegatedRevocationRequest {
bytes32 schema; // The unique identifier of the schema.
RevocationRequestData[] data; // The arguments of the revocation requests.
Signature[] signatures; // The ECDSA signatures data. Please note that the signatures are assumed to be signed with increasing nonces.
address revoker; // The revoking account.
uint64 deadline; // The deadline of the signature/request.
}
/// @title IEAS
/// @notice EAS - Ethereum Attestation Service interface.
interface IEAS is ISemver {
/// @notice Emitted when an attestation has been made.
/// @param recipient The recipient of the attestation.
/// @param attester The attesting account.
/// @param uid The UID the revoked attestation.
/// @param schemaUID The UID of the schema.
event Attested(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID);
/// @notice Emitted when an attestation has been revoked.
/// @param recipient The recipient of the attestation.
/// @param attester The attesting account.
/// @param schemaUID The UID of the schema.
/// @param uid The UID the revoked attestation.
event Revoked(address indexed recipient, address indexed attester, bytes32 uid, bytes32 indexed schemaUID);
/// @notice Emitted when a data has been timestamped.
/// @param data The data.
/// @param timestamp The timestamp.
event Timestamped(bytes32 indexed data, uint64 indexed timestamp);
/// @notice Emitted when a data has been revoked.
/// @param revoker The address of the revoker.
/// @param data The data.
/// @param timestamp The timestamp.
event RevokedOffchain(address indexed revoker, bytes32 indexed data, uint64 indexed timestamp);
/// @notice Returns the address of the global schema registry.
/// @return The address of the global schema registry.
function getSchemaRegistry() external view returns (ISchemaRegistry);
/// @notice Attests to a specific schema.
/// @param request The arguments of the attestation request.
/// @return The UID of the new attestation.
///
/// Example:
/// attest({
/// schema: "0facc36681cbe2456019c1b0d1e7bedd6d1d40f6f324bf3dd3a4cef2999200a0",
/// data: {
/// recipient: "0xdEADBeAFdeAdbEafdeadbeafDeAdbEAFdeadbeaf",
/// expirationTime: 0,
/// revocable: true,
/// refUID: "0x0000000000000000000000000000000000000000000000000000000000000000",
/// data: "0xF00D",
/// value: 0
/// }
/// })
function attest(AttestationRequest calldata request) external payable returns (bytes32);
/// @notice Attests to a specific schema via the provided ECDSA signature.
/// @param delegatedRequest The arguments of the delegated attestation request.
/// @return The UID of the new attestation.
///
/// Example:
/// attestByDelegation({
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: {
/// recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
/// expirationTime: 1673891048,
/// revocable: true,
/// refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
/// data: '0x1234',
/// value: 0
/// },
/// signature: {
/// v: 28,
/// r: '0x148c...b25b',
/// s: '0x5a72...be22'
/// },
/// attester: '0xc5E8740aD971409492b1A63Db8d83025e0Fc427e',
/// deadline: 1673891048
/// })
function attestByDelegation(
DelegatedAttestationRequest calldata delegatedRequest
) external payable returns (bytes32);
/// @notice Attests to multiple schemas.
/// @param multiRequests The arguments of the multi attestation requests. The requests should be grouped by distinct
/// schema ids to benefit from the best batching optimization.
/// @return The UIDs of the new attestations.
///
/// Example:
/// multiAttest([{
/// schema: '0x33e9094830a5cba5554d1954310e4fbed2ef5f859ec1404619adea4207f391fd',
/// data: [{
/// recipient: '0xdEADBeAFdeAdbEafdeadbeafDeAdbEAFdeadbeaf',
/// expirationTime: 1673891048,
/// revocable: true,
/// refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
/// data: '0x1234',
/// value: 1000
/// },
/// {
/// recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
/// expirationTime: 0,
/// revocable: false,
/// refUID: '0x480df4a039efc31b11bfdf491b383ca138b6bde160988222a2a3509c02cee174',
/// data: '0x00',
/// value: 0
/// }],
/// },
/// {
/// schema: '0x5ac273ce41e3c8bfa383efe7c03e54c5f0bff29c9f11ef6ffa930fc84ca32425',
/// data: [{
/// recipient: '0xdEADBeAFdeAdbEafdeadbeafDeAdbEAFdeadbeaf',
/// expirationTime: 0,
/// revocable: true,
/// refUID: '0x75bf2ed8dca25a8190c50c52db136664de25b2449535839008ccfdab469b214f',
/// data: '0x12345678',
/// value: 0
/// },
/// }])
function multiAttest(MultiAttestationRequest[] calldata multiRequests) external payable returns (bytes32[] memory);
/// @notice Attests to multiple schemas using via provided ECDSA signatures.
/// @param multiDelegatedRequests The arguments of the delegated multi attestation requests. The requests should be
/// grouped by distinct schema ids to benefit from the best batching optimization.
/// @return The UIDs of the new attestations.
///
/// Example:
/// multiAttestByDelegation([{
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: [{
/// recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
/// expirationTime: 1673891048,
/// revocable: true,
/// refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
/// data: '0x1234',
/// value: 0
/// },
/// {
/// recipient: '0xdEADBeAFdeAdbEafdeadbeafDeAdbEAFdeadbeaf',
/// expirationTime: 0,
/// revocable: false,
/// refUID: '0x0000000000000000000000000000000000000000000000000000000000000000',
/// data: '0x00',
/// value: 0
/// }],
/// signatures: [{
/// v: 28,
/// r: '0x148c...b25b',
/// s: '0x5a72...be22'
/// },
/// {
/// v: 28,
/// r: '0x487s...67bb',
/// s: '0x12ad...2366'
/// }],
/// attester: '0x1D86495b2A7B524D747d2839b3C645Bed32e8CF4',
/// deadline: 1673891048
/// }])
function multiAttestByDelegation(
MultiDelegatedAttestationRequest[] calldata multiDelegatedRequests
) external payable returns (bytes32[] memory);
/// @notice Revokes an existing attestation to a specific schema.
/// @param request The arguments of the revocation request.
///
/// Example:
/// revoke({
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: {
/// uid: '0x101032e487642ee04ee17049f99a70590c735b8614079fc9275f9dd57c00966d',
/// value: 0
/// }
/// })
function revoke(RevocationRequest calldata request) external payable;
/// @notice Revokes an existing attestation to a specific schema via the provided ECDSA signature.
/// @param delegatedRequest The arguments of the delegated revocation request.
///
/// Example:
/// revokeByDelegation({
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: {
/// uid: '0xcbbc12102578c642a0f7b34fe7111e41afa25683b6cd7b5a14caf90fa14d24ba',
/// value: 0
/// },
/// signature: {
/// v: 27,
/// r: '0xb593...7142',
/// s: '0x0f5b...2cce'
/// },
/// revoker: '0x244934dd3e31bE2c81f84ECf0b3E6329F5381992',
/// deadline: 1673891048
/// })
function revokeByDelegation(DelegatedRevocationRequest calldata delegatedRequest) external payable;
/// @notice Revokes existing attestations to multiple schemas.
/// @param multiRequests The arguments of the multi revocation requests. The requests should be grouped by distinct
/// schema ids to benefit from the best batching optimization.
///
/// Example:
/// multiRevoke([{
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: [{
/// uid: '0x211296a1ca0d7f9f2cfebf0daaa575bea9b20e968d81aef4e743d699c6ac4b25',
/// value: 1000
/// },
/// {
/// uid: '0xe160ac1bd3606a287b4d53d5d1d6da5895f65b4b4bab6d93aaf5046e48167ade',
/// value: 0
/// }],
/// },
/// {
/// schema: '0x5ac273ce41e3c8bfa383efe7c03e54c5f0bff29c9f11ef6ffa930fc84ca32425',
/// data: [{
/// uid: '0x053d42abce1fd7c8fcddfae21845ad34dae287b2c326220b03ba241bc5a8f019',
/// value: 0
/// },
/// }])
function multiRevoke(MultiRevocationRequest[] calldata multiRequests) external payable;
/// @notice Revokes existing attestations to multiple schemas via provided ECDSA signatures.
/// @param multiDelegatedRequests The arguments of the delegated multi revocation attestation requests. The requests
/// should be grouped by distinct schema ids to benefit from the best batching optimization.
///
/// Example:
/// multiRevokeByDelegation([{
/// schema: '0x8e72f5bc0a8d4be6aa98360baa889040c50a0e51f32dbf0baa5199bd93472ebc',
/// data: [{
/// uid: '0x211296a1ca0d7f9f2cfebf0daaa575bea9b20e968d81aef4e743d699c6ac4b25',
/// value: 1000
/// },
/// {
/// uid: '0xe160ac1bd3606a287b4d53d5d1d6da5895f65b4b4bab6d93aaf5046e48167ade',
/// value: 0
/// }],
/// signatures: [{
/// v: 28,
/// r: '0x148c...b25b',
/// s: '0x5a72...be22'
/// },
/// {
/// v: 28,
/// r: '0x487s...67bb',
/// s: '0x12ad...2366'
/// }],
/// revoker: '0x244934dd3e31bE2c81f84ECf0b3E6329F5381992',
/// deadline: 1673891048
/// }])
function multiRevokeByDelegation(
MultiDelegatedRevocationRequest[] calldata multiDelegatedRequests
) external payable;
/// @notice Timestamps the specified bytes32 data.
/// @param data The data to timestamp.
/// @return The timestamp the data was timestamped with.
function timestamp(bytes32 data) external returns (uint64);
/// @notice Timestamps the specified multiple bytes32 data.
/// @param data The data to timestamp.
/// @return The timestamp the data was timestamped with.
function multiTimestamp(bytes32[] calldata data) external returns (uint64);
/// @notice Revokes the specified bytes32 data.
/// @param data The data to timestamp.
/// @return The timestamp the data was revoked with.
function revokeOffchain(bytes32 data) external returns (uint64);
/// @notice Revokes the specified multiple bytes32 data.
/// @param data The data to timestamp.
/// @return The timestamp the data was revoked with.
function multiRevokeOffchain(bytes32[] calldata data) external returns (uint64);
/// @notice Returns an existing attestation by UID.
/// @param uid The UID of the attestation to retrieve.
/// @return The attestation data members.
function getAttestation(bytes32 uid) external view returns (Attestation memory);
/// @notice Checks whether an attestation exists.
/// @param uid The UID of the attestation to retrieve.
/// @return Whether an attestation exists.
function isAttestationValid(bytes32 uid) external view returns (bool);
/// @notice Returns the timestamp that the specified data was timestamped with.
/// @param data The data to query.
/// @return The timestamp the data was timestamped with.
function getTimestamp(bytes32 data) external view returns (uint64);
/// @notice Returns the timestamp that the specified data was timestamped with.
/// @param data The data to query.
/// @return The timestamp the data was timestamped with.
function getRevokeOffchain(address revoker, bytes32 data) external view returns (uint64);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {ISafe} from "../interfaces/ISafe.sol";
import {Enum} from "../libraries/Enum.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../interfaces/ISuperChainModule.sol";
contract SuperChainModuleUpgradeable is
Initializable,
ISuperChainModule,
OwnableUpgradeable,
UUPSUpgradeable
{
/// @custom:storage-location erc7201:openzeppelin.storage.superchain_module
struct SuperChainStorage {
mapping(address => mapping(address => bool)) _isPopulatedAddOwnerWithThreshold;
mapping(address => address[]) populatedAddOwnersWithTreshold;
mapping(address => Account) superChainAccount;
mapping(address => address) userSuperChainAccount;
mapping(address => bool) hasFirstOwnerYet;
mapping(string => bool) superChainIDRegistered;
address _resolver;
uint256[] _tierTreshold;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.superchain_module")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant SUPERCHAIN_MODULE_STORAGE_LOCATION =
0x0b2be64e6582d1593e5ce87fbed66eec9268226484384723dab2b56b70de0600;
function superChainStorage()
private
pure
returns (SuperChainStorage storage $)
{
assembly {
$.slot := SUPERCHAIN_MODULE_STORAGE_LOCATION
}
}
function initialize(address resolver, address owner) public initializer {
__Ownable_init(owner);
__UUPSUpgradeable_init();
SuperChainStorage storage s = superChainStorage();
s._resolver = resolver;
}
modifier firstOwnerSet(address _safe) {
SuperChainStorage storage s = superChainStorage();
require(s.hasFirstOwnerYet[_safe], "Initial owner not set yet");
_;
}
function addOwnerWithThreshold(
address _safe,
address _newOwner
) public firstOwnerSet(_safe) {
SuperChainStorage storage s = superChainStorage();
require(msg.sender == _newOwner, "Caller is not the new owner");
require(
s.userSuperChainAccount[_newOwner] == address(0),
"Owner already has a SuperChainAccount"
);
require(
s._isPopulatedAddOwnerWithThreshold[_newOwner][_safe],
"Owner not populated"
);
for (
uint i = 0;
i < s.populatedAddOwnersWithTreshold[_safe].length;
i++
) {
if (s.populatedAddOwnersWithTreshold[_safe][i] == _newOwner) {
s.populatedAddOwnersWithTreshold[_safe][i] = s
.populatedAddOwnersWithTreshold[_safe][
s.populatedAddOwnersWithTreshold[_safe].length - 1
];
s.populatedAddOwnersWithTreshold[_safe].pop();
break;
}
}
bytes memory data = abi.encodeWithSignature(
"addOwnerWithThreshold(address,uint256)",
_newOwner,
1
);
bool success = ISafe(_safe).execTransactionFromModule(
_safe,
0,
data,
Enum.Operation.Call
);
require(success, "Failed to add owner");
s.userSuperChainAccount[_newOwner] = _safe;
emit OwnerAdded(
_safe,
_newOwner,
s.superChainAccount[_safe].superChainID
);
}
function removePopulateRequest(address _safe, address user) public {
SuperChainStorage storage s = superChainStorage();
require(
s._isPopulatedAddOwnerWithThreshold[user][_safe],
"Owner not populated"
);
require(
ISafe(_safe).isOwner(msg.sender) ||
s._isPopulatedAddOwnerWithThreshold[msg.sender][_safe] ||
msg.sender == _safe,
"The address is not an owner or the populated user"
);
for (
uint i = 0;
i < s.populatedAddOwnersWithTreshold[_safe].length;
i++
) {
if (s.populatedAddOwnersWithTreshold[_safe][i] == user) {
Account memory _account = s.superChainAccount[_safe];
s.populatedAddOwnersWithTreshold[_safe][i] = s
.populatedAddOwnersWithTreshold[_safe][
s.populatedAddOwnersWithTreshold[_safe].length - 1
];
s.populatedAddOwnersWithTreshold[_safe].pop();
s._isPopulatedAddOwnerWithThreshold[user][_safe] = false;
emit OwnerPopulationRemoved(_safe, user, _account.superChainID);
break;
}
}
}
function setInitialOwner(
address _safe,
address _owner,
NounMetadata calldata _noun,
string calldata superChainID
) public {
SuperChainStorage storage s = superChainStorage();
require(
s.userSuperChainAccount[_owner] == address(0),
"Owner already has a SuperChainSmartAccount"
);
require(ISafe(_safe).isOwner(_owner), "The address is not an owner");
require(
msg.sender == _safe,
"Caller is not the SuperChainSmartAccount"
);
require(
!s.hasFirstOwnerYet[_safe],
"SuperChainSmartAccount already has owners"
);
require(
ISafe(_safe).getOwners().length == 1,
"SuperChainSmartAccount already has owners"
);
require(
!_isInvalidSuperChainId(superChainID),
"The last 11 characters cannot be '.superchain'"
);
require(
!s.superChainIDRegistered[superChainID],
"The superchain ID was registered yet."
);
s.superChainAccount[_safe].smartAccount = _safe;
s.userSuperChainAccount[_owner] = _safe;
s.superChainAccount[_safe].superChainID = string.concat(
superChainID,
".superchain"
);
s.superChainIDRegistered[superChainID] = true;
s.hasFirstOwnerYet[_safe] = true;
s.superChainAccount[_safe].noun = _noun;
emit OwnerAdded(_safe, _owner, s.superChainAccount[_safe].superChainID);
emit SuperChainSmartAccountCreated(
_safe,
_owner,
s.superChainAccount[_safe].superChainID,
_noun
);
}
function populateAddOwner(
address _safe,
address _newOwner
) public firstOwnerSet(_safe) {
SuperChainStorage storage s = superChainStorage();
require(
msg.sender == _safe,
"Caller is not the SuperChainSmartAccount"
);
require(!ISafe(_safe).isOwner(_newOwner), "Owner already exists");
require(
!s._isPopulatedAddOwnerWithThreshold[_newOwner][_safe],
"Owner already populated"
);
require(
s.userSuperChainAccount[_newOwner] == address(0),
"Owner already has a SuperChainSmartAccount"
);
require(
s.populatedAddOwnersWithTreshold[_safe].length <= 2,
"Max owners populated"
);
s.populatedAddOwnersWithTreshold[_safe].push(_newOwner);
s._isPopulatedAddOwnerWithThreshold[_newOwner][_safe] = true;
string memory _superChainId = s.superChainAccount[_safe].superChainID;
emit OwnerPopulated(_safe, _newOwner, _superChainId);
}
function incrementSuperChainPoints(
uint256 _points,
address recipent
) public returns (bool levelUp) {
SuperChainStorage storage s = superChainStorage();
Account storage _account = s.superChainAccount[recipent];
require(
msg.sender == s._resolver,
"Only the resolver can increment the points"
);
require(_account.smartAccount != address(0), "Account not found");
_account.points += _points;
for (uint16 i = uint16(s._tierTreshold.length); i > 0; i--) {
uint16 index = i - 1;
if (s._tierTreshold[index] <= _account.points) {
if (_account.level == index + 1) {
break;
}
_account.level = index + 1;
levelUp = true;
break;
}
}
emit PointsIncremented(recipent, _points, levelUp);
return levelUp;
}
function simulateIncrementSuperChainPoints(
uint256 _points,
address recipent
) public view returns (bool levelUp) {
SuperChainStorage storage s = superChainStorage();
Account memory _account = s.superChainAccount[recipent];
require(_account.smartAccount != address(0), "Account not found");
_account.points += _points;
for (uint16 i = uint16(s._tierTreshold.length); i > 0; i--) {
uint16 index = i - 1;
if (s._tierTreshold[index] <= _account.points) {
if (_account.level == index + 1) {
break;
}
_account.level = index + 1;
levelUp = true;
break;
}
}
return levelUp;
}
function _changeResolver(address resolver) public onlyOwner {
SuperChainStorage storage s = superChainStorage();
s._resolver = resolver;
}
function addTiersTreshold(uint256[] memory _tresholds) external onlyOwner{
for (uint256 i = 0; i < _tresholds.length; i++) {
_addTierTreshold(_tresholds[i]);
}
}
function _addTierTreshold(uint256 _treshold) internal {
SuperChainStorage storage s = superChainStorage();
if (s._tierTreshold.length > 0) {
require(
s._tierTreshold[s._tierTreshold.length - 1] < _treshold,
"The treshold must be higher than the last one"
);
}
s._tierTreshold.push(_treshold);
emit TierTresholdAdded(_treshold);
}
function updateTierThreshold(
uint256 index,
uint256 newThreshold
) public onlyOwner {
SuperChainStorage storage s = superChainStorage();
require(index < s._tierTreshold.length, "Index out of bounds");
require(
(index == 0 || s._tierTreshold[index - 1] < newThreshold) &&
(index == s._tierTreshold.length - 1 ||
newThreshold < s._tierTreshold[index + 1]),
"Invalid threshold update"
);
s._tierTreshold[index] = newThreshold;
emit TierTresholdUpdated(index, newThreshold);
}
function getNextLevelPoints(address _safe) public view returns (uint256) {
SuperChainStorage storage s = superChainStorage();
if (s.superChainAccount[_safe].level == s._tierTreshold.length) {
revert MaxLvlReached();
}
return s._tierTreshold[s.superChainAccount[_safe].level];
}
function _isInvalidSuperChainId(
string memory str
) internal pure returns (bool) {
bytes memory strBytes = bytes(str);
bytes memory suffixBytes = bytes(".superchain");
if (strBytes.length < suffixBytes.length) {
return false;
}
for (uint i = 0; i < suffixBytes.length; i++) {
if (
strBytes[strBytes.length - suffixBytes.length + i] !=
suffixBytes[i]
) {
return false;
}
}
return true;
}
function getSuperChainAccount(
address _safe
) public view returns (Account memory) {
SuperChainStorage storage s = superChainStorage();
return s.superChainAccount[_safe];
}
function getUserSuperChainAccount(
address _owner
) public view returns (Account memory) {
SuperChainStorage storage s = superChainStorage();
return s.superChainAccount[s.userSuperChainAccount[_owner]];
}
function UpdateNounAvatar(address _safe, NounMetadata calldata _noun) public {
SuperChainStorage storage s = superChainStorage();
require(
msg.sender == _safe,
"Only the SuperChainSmartAccount can update the noun"
);
s.superChainAccount[_safe].noun = _noun;
emit NounUpdated(_safe, _noun);
}
function populatedAddOwnersWithTreshold(
address $
) public view returns (address[] memory) {
SuperChainStorage storage s = superChainStorage();
return s.populatedAddOwnersWithTreshold[$];
}
function superChainAccount(address $) public view returns (Account memory) {
SuperChainStorage storage s = superChainStorage();
return s.superChainAccount[$];
}
function userSuperChainAccount(address $) public view returns (address) {
SuperChainStorage storage s = superChainStorage();
return s.userSuperChainAccount[$];
}
function hasFirstOwnerYet(address $) public view returns (bool) {
SuperChainStorage storage s = superChainStorage();
return s.hasFirstOwnerYet[$];
}
function superChainIDRegistered(
string memory $
) public view returns (bool) {
SuperChainStorage storage s = superChainStorage();
return s.superChainIDRegistered[$];
}
function _authorizeUpgrade(address) internal override onlyOwner {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import {ERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
struct BadgeUpdate {
uint256 badgeId;
uint256 tier;
}
struct BadgeMetadata {
uint256 badgeId;
string generalURI;
}
struct BadgeTierMetadata {
uint256 badgeId;
uint256 tier;
string newURI;
uint256 points;
}
contract SuperChainBadges is
Initializable,
ERC1155Upgradeable,
OwnableUpgradeable,
UUPSUpgradeable
{
uint256 constant LEVEL_MASK = uint256(type(uint128).max);
uint256 constant LEVEL_SHIFT = 128;
/// @custom:storage-location erc7201:openzeppelin.storage.superchain_badges
struct BadgesStorage {
address resolver;
mapping(uint256 => Badge) _badges;
mapping(address => mapping(uint256 => uint256)) _userBadgeTiers;
}
struct BadgeTier {
string uri;
uint256 points;
}
struct Badge {
string generalURI;
mapping(uint256 => BadgeTier) tiers;
uint256 highestTier;
}
event BadgeTierSet(
uint256 indexed badgeId,
uint256 tier,
string uri,
uint256 points
);
event BadgeMinted(
address indexed user,
uint256 indexed badgeId,
uint256 initialTier,
uint256 points,
string uri
);
event BadgeMetadataSettled(uint256 indexed badgeId, string generalURI);
event BadgeTierMetadataUpdated(
uint256 indexed badgeId,
uint256 tier,
string newURI
);
event BadgeTierUpdated(
address indexed user,
uint256 indexed badgeId,
uint256 tier,
uint256 points,
string uri
);
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.superchain_badges")) - 1)) & ~bytes32(uint256(0xff));
bytes32 private constant SUPERCHAIN_BADGES_STORAGE_LOCATION =
0xb2b7b32472936fec942d11d364b3fb7baeea6584fbe4aa7e3432289df3426200;
function badgesStorage() private pure returns (BadgesStorage storage $) {
assembly {
$.slot := SUPERCHAIN_BADGES_STORAGE_LOCATION
}
}
function initialize(address owner) public initializer {
__ERC1155_init("");
__Ownable_init(owner);
__UUPSUpgradeable_init();
}
function setBadgesAndTiers(
BadgeMetadata[] memory badges,
BadgeTierMetadata[] memory badgeTiers
) public onlyOwner {
for (uint256 i = 0; i < badges.length; i++) {
setBadgeMetadata(badges[i].badgeId, badges[i].generalURI);
}
for (uint256 i = 0; i < badgeTiers.length; i++) {
setBadgeTier(
badgeTiers[i].badgeId,
badgeTiers[i].tier,
badgeTiers[i].newURI,
badgeTiers[i].points
);
}
}
function setBadgeMetadata(
uint256 badgeId,
string memory generalURI
) public onlyOwner {
BadgesStorage storage s = badgesStorage();
s._badges[badgeId].generalURI = generalURI;
emit BadgeMetadataSettled(badgeId, generalURI);
}
function updateBadgeTierMetadata(
uint256 badgeId,
uint256 tier,
string memory newURI
) public onlyOwner {
BadgesStorage storage s = badgesStorage();
require(
bytes(s._badges[badgeId].generalURI).length != 0,
"Badge does not exist"
);
require(
bytes(s._badges[badgeId].tiers[tier].uri).length != 0,
"URI for initial tier not set"
);
s._badges[badgeId].tiers[tier].uri = newURI;
emit BadgeTierMetadataUpdated(badgeId, tier, newURI);
}
function setBadgeTier(
uint256 badgeId,
uint256 tier,
string memory newURI,
uint256 points
) public onlyOwner {
BadgesStorage storage s = badgesStorage();
require(
bytes(s._badges[badgeId].generalURI).length != 0,
"Badge does not exist"
);
require(tier > 0, "Tier must be greater than 0");
require(
tier == s._badges[badgeId].highestTier + 1,
"Tiers must be added sequentially"
);
if (tier > 1) {
require(
points > s._badges[badgeId].tiers[tier - 1].points,
"Points must be greater than the previous tier"
);
}
s._badges[badgeId].tiers[tier] = BadgeTier(newURI, points);
s._badges[badgeId].highestTier = tier;
emit BadgeTierSet(badgeId, tier, newURI, points);
}
function mintBadge(
address to,
uint256 badgeId,
uint256 initialTier
) internal returns (uint256 totalPoints) {
BadgesStorage storage s = badgesStorage();
require(
bytes(s._badges[badgeId].tiers[initialTier].uri).length != 0,
"URI for initial tier not set"
);
uint256 tokenId = _encodeTokenId(badgeId, initialTier);
require(balanceOf(to, tokenId) == 0, "Badge already minted");
_mint(to, tokenId, 1, "");
s._userBadgeTiers[to][badgeId] = initialTier;
for (uint256 tier = 1; tier <= initialTier; tier++) {
totalPoints += s._badges[badgeId].tiers[tier].points;
}
emit BadgeMinted(
to,
badgeId,
initialTier,
totalPoints,
s._badges[badgeId].tiers[initialTier].uri
);
}
function updateBadgeTier(
address user,
uint256 badgeId,
uint256 newTier
) internal returns (uint256 totalPoints) {
BadgesStorage storage s = badgesStorage();
require(
bytes(s._badges[badgeId].tiers[newTier].uri).length != 0,
"URI for new tier not set"
);
uint256 oldTier = s._userBadgeTiers[user][badgeId];
uint256 oldTokenId = _encodeTokenId(badgeId, oldTier);
uint256 newTokenId = _encodeTokenId(badgeId, newTier);
require(balanceOf(user, newTokenId) == 0, "Badge already minted");
_burn(user, oldTokenId, 1);
_mint(user, newTokenId, 1, "");
s._userBadgeTiers[user][badgeId] = newTier;
for (uint256 tier = oldTier + 1; tier <= newTier; tier++) {
totalPoints += s._badges[badgeId].tiers[tier].points;
}
emit BadgeTierUpdated(
user,
badgeId,
newTier,
totalPoints,
s._badges[badgeId].tiers[newTier].uri
);
}
function getBadgeURIForUser(
address user,
uint256 badgeId
) public view returns (string memory generalURI, string memory tierUri) {
BadgesStorage storage s = badgesStorage();
uint256 userTier = s._userBadgeTiers[user][badgeId];
generalURI = s._badges[badgeId].generalURI;
tierUri = s._badges[badgeId].tiers[userTier].uri;
}
function getGeneralBadgeURI(
uint256 badgeId
) public view returns (string memory) {
BadgesStorage storage s = badgesStorage();
return s._badges[badgeId].generalURI;
}
function getUserBadgeTier(
address user,
uint256 badgeId
) public view returns (uint256) {
BadgesStorage storage s = badgesStorage();
return s._userBadgeTiers[user][badgeId];
}
function updateOrMintBadges(
address user,
BadgeUpdate[] memory updates
) public returns (uint256 points) {
BadgesStorage storage s = badgesStorage();
require(
msg.sender == s.resolver,
"Only resolver can call this function"
);
for (uint256 i = 0; i < updates.length; i++) {
uint256 badgeId = updates[i].badgeId;
uint256 tier = updates[i].tier;
if (s._userBadgeTiers[user][badgeId] > 0) {
points += updateBadgeTier(user, badgeId, tier);
} else {
points += mintBadge(user, badgeId, tier);
}
}
}
function setResolver(address _resolver) public onlyOwner {
BadgesStorage storage s = badgesStorage();
s.resolver = _resolver;
}
function getHighestBadgeTier(
uint256 badgeId
) public view returns (uint256) {
BadgesStorage storage s = badgesStorage();
return s._badges[badgeId].highestTier;
}
function uri(uint256 tokenId) public view override returns (string memory) {
BadgesStorage storage s = badgesStorage();
(uint256 badgeId, uint256 tier) = _decodeTokenId(tokenId);
string memory baseURI = s._badges[badgeId].generalURI;
string memory tierURI = s._badges[badgeId].tiers[tier].uri;
return
string(
abi.encodePacked(
"{",
'"generalURI": "',
baseURI,
'",',
'"tierURI": "',
tierURI,
'"',
"}"
)
);
}
function safeTransferFrom(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override {
revert("BadgeNFT: Transfers are disabled");
}
function safeBatchTransferFrom(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override {
revert("BadgeNFT: Transfers are disabled");
}
function _encodeTokenId(
uint256 badgeId,
uint256 tier
) internal pure returns (uint256) {
return (badgeId << LEVEL_SHIFT) | (tier & LEVEL_MASK);
}
function _decodeTokenId(
uint256 tokenId
) internal pure returns (uint256 badgeId, uint256 tier) {
badgeId = tokenId >> LEVEL_SHIFT;
tier = tokenId & LEVEL_MASK;
}
function resolver() public view returns (address) {
BadgesStorage storage s = badgesStorage();
return s.resolver;
}
function _authorizeUpgrade(address) internal override onlyOwner {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// A representation of an empty/uninitialized UID.
bytes32 constant EMPTY_UID = 0;
// A zero expiration represents an non-expiring attestation.
uint64 constant NO_EXPIRATION_TIME = 0;
error AccessDenied();
error DeadlineExpired();
error InvalidEAS();
error InvalidLength();
error InvalidSignature();
error NotFound();
/// @notice A struct representing ECDSA signature data.
struct Signature {
uint8 v; // The recovery ID.
bytes32 r; // The x-coordinate of the nonce R.
bytes32 s; // The signature data.
}
/// @notice A struct representing a single attestation.
struct Attestation {
bytes32 uid; // A unique identifier of the attestation.
bytes32 schema; // The unique identifier of the schema.
uint64 time; // The time when the attestation was created (Unix timestamp).
uint64 expirationTime; // The time when the attestation expires (Unix timestamp).
uint64 revocationTime; // The time when the attestation was revoked (Unix timestamp).
bytes32 refUID; // The UID of the related attestation.
address recipient; // The recipient of the attestation.
address attester; // The attester/sender of the attestation.
bool revocable; // Whether the attestation is revocable.
bytes data; // Custom attestation data.
}
/// @notice A helper function to work with unchecked iterators in loops.
function uncheckedInc(uint256 i) pure returns (uint256 j) {
unchecked {
j = i + 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ISemver } from "./ISemver.sol";
/// @title Semver
/// @notice A simple contract for managing contract versions.
contract Semver is ISemver {
// Contract's major version number.
uint256 private immutable _major;
// Contract's minor version number.
uint256 private immutable _minor;
// Contract's patch version number.
uint256 private immutable _patch;
/// @dev Create a new Semver instance.
/// @param major Major version number.
/// @param minor Minor version number.
/// @param patch Patch version number.
constructor(uint256 major, uint256 minor, uint256 patch) {
_major = major;
_minor = minor;
_patch = patch;
}
/// @notice Returns the full semver contract version.
/// @return Semver contract version as a string.
function version() external view returns (string memory) {
return
string(
abi.encodePacked(Strings.toString(_major), ".", Strings.toString(_minor), ".", Strings.toString(_patch))
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ISemver } from "../ISemver.sol";
import { Attestation } from "../Common.sol";
/// @title ISchemaResolver
/// @notice The interface of an optional schema resolver.
interface ISchemaResolver is ISemver {
/// @notice Checks if the resolver can be sent ETH.
/// @return Whether the resolver supports ETH transfers.
function isPayable() external pure returns (bool);
/// @notice Processes an attestation and verifies whether it's valid.
/// @param attestation The new attestation.
/// @return Whether the attestation is valid.
function attest(Attestation calldata attestation) external payable returns (bool);
/// @notice Processes multiple attestations and verifies whether they are valid.
/// @param attestations The new attestations.
/// @param values Explicit ETH amounts which were sent with each attestation.
/// @return Whether all the attestations are valid.
function multiAttest(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable returns (bool);
/// @notice Processes an attestation revocation and verifies if it can be revoked.
/// @param attestation The existing attestation to be revoked.
/// @return Whether the attestation can be revoked.
function revoke(Attestation calldata attestation) external payable returns (bool);
/// @notice Processes revocation of multiple attestation and verifies they can be revoked.
/// @param attestations The existing attestations to be revoked.
/// @param values Explicit ETH amounts which were sent with each revocation.
/// @return Whether the attestations can be revoked.
function multiRevoke(
Attestation[] calldata attestations,
uint256[] calldata values
) external payable returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ISemver } from "./ISemver.sol";
import { ISchemaResolver } from "./resolver/ISchemaResolver.sol";
/// @notice A struct representing a record for a submitted schema.
struct SchemaRecord {
bytes32 uid; // The unique identifier of the schema.
ISchemaResolver resolver; // Optional schema resolver.
bool revocable; // Whether the schema allows revocations explicitly.
string schema; // Custom specification of the schema (e.g., an ABI).
}
/// @title ISchemaRegistry
/// @notice The interface of global attestation schemas for the Ethereum Attestation Service protocol.
interface ISchemaRegistry is ISemver {
/// @notice Emitted when a new schema has been registered
/// @param uid The schema UID.
/// @param registerer The address of the account used to register the schema.
/// @param schema The schema data.
event Registered(bytes32 indexed uid, address indexed registerer, SchemaRecord schema);
/// @notice Submits and reserves a new schema
/// @param schema The schema data schema.
/// @param resolver An optional schema resolver.
/// @param revocable Whether the schema allows revocations explicitly.
/// @return The UID of the new schema.
function register(string calldata schema, ISchemaResolver resolver, bool revocable) external returns (bytes32);
/// @notice Returns an existing schema by UID
/// @param uid The UID of the schema to retrieve.
/// @return The schema data members.
function getSchema(bytes32 uid) external view returns (SchemaRecord memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ISemver
/// @notice A semver interface.
interface ISemver {
/// @notice Returns the full semver contract version.
/// @return Semver contract version as a string.
function version() external view returns (string memory);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {Enum} from "../libraries/Enum.sol";
import {IModuleManager} from "./IModuleManager.sol";
import {IOwnerManager} from "./IOwnerManager.sol";
import {IFallbackManager} from "./IFallbackManager.sol";
import {IGuardManager} from "./IGuardManager.sol";
/**
* @title ISafe - A multisignature wallet interface with support for confirmations using signed messages based on EIP-712.
* @author @safe-global/safe-protocol
*/
interface ISafe is
IModuleManager,
IGuardManager,
IOwnerManager,
IFallbackManager
{
event SafeSetup(
address indexed initiator,
address[] owners,
uint256 threshold,
address initializer,
address fallbackHandler
);
event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
event SignMsg(bytes32 indexed msgHash);
event ExecutionFailure(bytes32 indexed txHash, uint256 payment);
event ExecutionSuccess(bytes32 indexed txHash, uint256 payment);
/**
* @notice Sets an initial storage of the Safe contract.
* @dev This method can only be called once.
* If a proxy was created without setting up, anyone can call setup and claim the proxy.
* @param _owners List of Safe owners.
* @param _threshold Number of required confirmations for a Safe transaction.
* @param to Contract address for optional delegate call.
* @param data Data payload for optional delegate call.
* @param fallbackHandler Handler for fallback calls to this contract
* @param paymentToken Token that should be used for the payment (0 is ETH)
* @param payment Value that should be paid
* @param paymentReceiver Address that should receive the payment (or 0 if tx.origin)
*/
function setup(
address[] calldata _owners,
uint256 _threshold,
address to,
bytes calldata data,
address fallbackHandler,
address paymentToken,
uint256 payment,
address payable paymentReceiver
) external;
/** @notice Executes a `operation` {0: Call, 1: DelegateCall}} transaction to `to` with `value` (Native Currency)
* and pays `gasPrice` * `gasLimit` in `gasToken` token to `refundReceiver`.
* @dev The fees are always transferred, even if the user transaction fails.
* This method doesn't perform any sanity check of the transaction, such as:
* - if the contract at `to` address has code or not
* - if the `gasToken` is a contract or not
* It is the responsibility of the caller to perform such checks.
* @param to Destination address of Safe transaction.
* @param value Ether value of Safe transaction.
* @param data Data payload of Safe transaction.
* @param operation Operation type of Safe transaction.
* @param safeTxGas Gas that should be used for the Safe transaction.
* @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
* @param gasPrice Gas price that should be used for the payment calculation.
* @param gasToken Token address (or 0 if ETH) that is used for the payment.
* @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
* @return success Boolean indicating transaction's success.
*/
function execTransaction(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address payable refundReceiver,
bytes memory signatures
) external payable returns (bool success);
/**
* @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
*/
function checkSignatures(
bytes32 dataHash,
bytes memory signatures
) external view;
/**
* @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
* @dev This function makes it compatible with previous versions.
*/
function checkSignatures(
bytes32 dataHash,
bytes memory /* IGNORED */,
bytes memory signatures
) external view;
/**
* @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise.
* @dev Since the EIP-1271 does an external call, be mindful of reentrancy attacks.
* @param executor Address that executing the transaction.
* ⚠️⚠️⚠️ Make sure that the executor address is a legitmate executor.
* Incorrectly passed the executor might reduce the threshold by 1 signature. ⚠️⚠️⚠️
* @param dataHash Hash of the data (could be either a message hash or transaction hash)
* @param signatures Signature data that should be verified.
* Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash.
* @param requiredSignatures Amount of required valid signatures.
*/
function checkNSignatures(
address executor,
bytes32 dataHash,
bytes memory signatures,
uint256 requiredSignatures
) external view;
/**
* @notice Marks hash `hashToApprove` as approved.
* @dev This can be used with a pre-approved hash transaction signature.
* IMPORTANT: The approved hash stays approved forever. There's no revocation mechanism, so it behaves similarly to ECDSA signatures
* @param hashToApprove The hash to mark as approved for signatures that are verified by this contract.
*/
function approveHash(bytes32 hashToApprove) external;
/**
* @dev Returns the domain separator for this contract, as defined in the EIP-712 standard.
* @return bytes32 The domain separator hash.
*/
function domainSeparator() external view returns (bytes32);
/**
* @notice Returns transaction hash to be signed by owners.
* @param to Destination address.
* @param value Ether value.
* @param data Data payload.
* @param operation Operation type.
* @param safeTxGas Gas that should be used for the safe transaction.
* @param baseGas Gas costs for data used to trigger the safe transaction.
* @param gasPrice Maximum gas price that should be used for this transaction.
* @param gasToken Token address (or 0 if ETH) that is used for the payment.
* @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
* @param _nonce Transaction nonce.
* @return Transaction hash.
*/
function getTransactionHash(
address to,
uint256 value,
bytes calldata data,
Enum.Operation operation,
uint256 safeTxGas,
uint256 baseGas,
uint256 gasPrice,
address gasToken,
address refundReceiver,
uint256 _nonce
) external view returns (bytes32);
/**
* External getter function for state variables.
*/
/**
* @notice Returns the version of the Safe contract.
* @return Version string.
*/
// solhint-disable-next-line
function VERSION() external view returns (string memory);
/**
* @notice Returns the nonce of the Safe contract.
* @return Nonce.
*/
function nonce() external view returns (uint256);
/**
* @notice Returns a uint if the messageHash is signed by the owner.
* @param messageHash Hash of message that should be checked.
* @return Number denoting if an owner signed the hash.
*/
function signedMessages(
bytes32 messageHash
) external view returns (uint256);
/**
* @notice Returns a uint if the messageHash is approved by the owner.
* @param owner Owner address that should be checked.
* @param messageHash Hash of message that should be checked.
* @return Number denoting if an owner approved the hash.
*/
function approvedHashes(
address owner,
bytes32 messageHash
) external view returns (uint256);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Enum - Collection of enums used in Safe Smart Account contracts.
* @author @safe-global/safe-protocol
*/
library Enum {
enum Operation {
Call,
DelegateCall
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.20;
import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol";
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
import {Initializable} from "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address private immutable __self = address(this);
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)`
* and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev The call is from an unauthorized context.
*/
error UUPSUnauthorizedCallContext();
/**
* @dev The storage `slot` is unsupported as a UUID.
*/
error UUPSUnsupportedProxiableUUID(bytes32 slot);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
_checkProxy();
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
_checkNotDelegated();
_;
}
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual notDelegated returns (bytes32) {
return ERC1967Utils.IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data);
}
/**
* @dev Reverts if the execution is not performed via delegatecall or the execution
* context is not of a proxy with an ERC1967-compliant implementation pointing to self.
* See {_onlyProxy}.
*/
function _checkProxy() internal view virtual {
if (
address(this) == __self || // Must be called through delegatecall
ERC1967Utils.getImplementation() != __self // Must be called through an active proxy
) {
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Reverts if the execution is performed via delegatecall.
* See {notDelegated}.
*/
function _checkNotDelegated() internal view virtual {
if (address(this) != __self) {
// Must not be called through delegatecall
revert UUPSUnauthorizedCallContext();
}
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call.
*
* As a security check, {proxiableUUID} is invoked in the new implementation, and the return value
* is expected to be the implementation slot in ERC1967.
*
* Emits an {IERC1967-Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) {
revert UUPSUnsupportedProxiableUUID(slot);
}
ERC1967Utils.upgradeToAndCall(newImplementation, data);
} catch {
// The implementation is not UUPS
revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
struct NounMetadata {
uint48 background;
uint48 body;
uint48 accessory;
uint48 head;
uint48 glasses;
}
interface ISuperChainModule {
error MaxLvlReached();
event SuperChainSmartAccountCreated(
address indexed safe,
address indexed initialOwner,
string superChainId,
NounMetadata noun
);
event OwnerPopulationRemoved(
address indexed safe,
address indexed owner,
string superChainId
);
event OwnerPopulated(
address indexed safe,
address indexed newOwner,
string superChainId
);
event OwnerAdded(
address indexed safe,
address indexed newOwner,
string superChainId
);
event PointsIncremented(address indexed recipient, uint256 points, bool levelUp);
event TierTresholdAdded(uint256 treshold);
event TierTresholdUpdated(uint256 index, uint256 newThreshold);
event NounUpdated(address indexed safe, NounMetadata noun);
// Functions
function addOwnerWithThreshold(address _safe, address _newOwner) external;
function removePopulateRequest(address _safe, address user) external;
function setInitialOwner(
address _safe,
address _owner,
NounMetadata calldata _noun,
string calldata superChainID
) external;
function populateAddOwner(address _safe, address _newOwner) external;
function incrementSuperChainPoints(uint256 _points, address recipient) external returns (bool levelUp);
function simulateIncrementSuperChainPoints(uint256 _points, address recipient) external view returns (bool levelUp);
function addTiersTreshold(uint256[] memory tresholds) external;
function _changeResolver(address resolver) external;
function getNextLevelPoints(address _safe) external view returns (uint256);
function getSuperChainAccount(address _safe) external view returns (Account memory);
function getUserSuperChainAccount(address _owner) external view returns (Account memory);
struct AddOwnerRequest {
address superChainAccount;
address newOwner;
}
struct Account {
address smartAccount;
string superChainID;
uint256 points;
uint16 level;
NounMetadata noun;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {ERC165Upgradeable} from "../../utils/introspection/ERC165Upgradeable.sol";
import {Arrays} from "@openzeppelin/contracts/utils/Arrays.sol";
import {IERC1155Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the basic standard multi-token.
* See https://eips.ethereum.org/EIPS/eip-1155
* Originally based on code by Enjin: https://github.com/enjin/erc-1155
*/
abstract contract ERC1155Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC1155, IERC1155MetadataURI, IERC1155Errors {
using Arrays for uint256[];
using Arrays for address[];
/// @custom:storage-location erc7201:openzeppelin.storage.ERC1155
struct ERC1155Storage {
mapping(uint256 id => mapping(address account => uint256)) _balances;
mapping(address account => mapping(address operator => bool)) _operatorApprovals;
// Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
string _uri;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC1155")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ERC1155StorageLocation = 0x88be536d5240c274a3b1d3a1be54482fd9caa294f08c62a7cde569f49a3c4500;
function _getERC1155Storage() private pure returns (ERC1155Storage storage $) {
assembly {
$.slot := ERC1155StorageLocation
}
}
/**
* @dev See {_setURI}.
*/
function __ERC1155_init(string memory uri_) internal onlyInitializing {
__ERC1155_init_unchained(uri_);
}
function __ERC1155_init_unchained(string memory uri_) internal onlyInitializing {
_setURI(uri_);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165) returns (bool) {
return
interfaceId == type(IERC1155).interfaceId ||
interfaceId == type(IERC1155MetadataURI).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC1155MetadataURI-uri}.
*
* This implementation returns the same URI for *all* token types. It relies
* on the token type ID substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* Clients calling this function must replace the `\{id\}` substring with the
* actual token type ID.
*/
function uri(uint256 /* id */) public view virtual returns (string memory) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._uri;
}
/**
* @dev See {IERC1155-balanceOf}.
*/
function balanceOf(address account, uint256 id) public view virtual returns (uint256) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._balances[id][account];
}
/**
* @dev See {IERC1155-balanceOfBatch}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] memory accounts,
uint256[] memory ids
) public view virtual returns (uint256[] memory) {
if (accounts.length != ids.length) {
revert ERC1155InvalidArrayLength(ids.length, accounts.length);
}
uint256[] memory batchBalances = new uint256[](accounts.length);
for (uint256 i = 0; i < accounts.length; ++i) {
batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i));
}
return batchBalances;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view virtual returns (bool) {
ERC1155Storage storage $ = _getERC1155Storage();
return $._operatorApprovals[account][operator];
}
/**
* @dev See {IERC1155-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeTransferFrom(from, to, id, value, data);
}
/**
* @dev See {IERC1155-safeBatchTransferFrom}.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) public virtual {
address sender = _msgSender();
if (from != sender && !isApprovedForAll(from, sender)) {
revert ERC1155MissingApprovalForAll(sender, from);
}
_safeBatchTransferFrom(from, to, ids, values, data);
}
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from`
* (or `to`) is the zero address.
*
* Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received}
* or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value.
* - `ids` and `values` must have the same length.
*
* NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead.
*/
function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
if (ids.length != values.length) {
revert ERC1155InvalidArrayLength(ids.length, values.length);
}
address operator = _msgSender();
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids.unsafeMemoryAccess(i);
uint256 value = values.unsafeMemoryAccess(i);
if (from != address(0)) {
uint256 fromBalance = $._balances[id][from];
if (fromBalance < value) {
revert ERC1155InsufficientBalance(from, fromBalance, value, id);
}
unchecked {
// Overflow not possible: value <= fromBalance
$._balances[id][from] = fromBalance - value;
}
}
if (to != address(0)) {
$._balances[id][to] += value;
}
}
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
emit TransferSingle(operator, from, to, id, value);
} else {
emit TransferBatch(operator, from, to, ids, values);
}
}
/**
* @dev Version of {_update} that performs the token acceptance check by calling
* {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it
* contains code (eg. is a smart contract at the moment of execution).
*
* IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any
* update to the contract state after this function would break the check-effect-interaction pattern. Consider
* overriding {_update} instead.
*/
function _updateWithAcceptanceCheck(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal virtual {
_update(from, to, ids, values);
if (to != address(0)) {
address operator = _msgSender();
if (ids.length == 1) {
uint256 id = ids.unsafeMemoryAccess(0);
uint256 value = values.unsafeMemoryAccess(0);
_doSafeTransferAcceptanceCheck(operator, from, to, id, value, data);
} else {
_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data);
}
}
}
/**
* @dev Transfers a `value` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
* - `ids` and `values` must have the same length.
*/
function _safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, to, ids, values, data);
}
/**
* @dev Sets a new URI for all token types, by relying on the token type ID
* substitution mechanism
* https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
*
* By this mechanism, any occurrence of the `\{id\}` substring in either the
* URI or any of the values in the JSON file at said URI will be replaced by
* clients with the token type ID.
*
* For example, the `https://token-cdn-domain/\{id\}.json` URI would be
* interpreted by clients as
* `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
* for token type ID 0x4cce0.
*
* See {uri}.
*
* Because these URIs cannot be meaningfully represented by the {URI} event,
* this function emits no events.
*/
function _setURI(string memory newuri) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
$._uri = newuri;
}
/**
* @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function _mint(address to, uint256 id, uint256 value, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - `to` cannot be the zero address.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
if (to == address(0)) {
revert ERC1155InvalidReceiver(address(0));
}
_updateWithAcceptanceCheck(address(0), to, ids, values, data);
}
/**
* @dev Destroys a `value` amount of tokens of type `id` from `from`
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
*/
function _burn(address from, uint256 id, uint256 value) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
(uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value);
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `from` must have at least `value` amount of tokens of type `id`.
* - `ids` and `values` must have the same length.
*/
function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal {
if (from == address(0)) {
revert ERC1155InvalidSender(address(0));
}
_updateWithAcceptanceCheck(from, address(0), ids, values, "");
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the zero address.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
ERC1155Storage storage $ = _getERC1155Storage();
if (operator == address(0)) {
revert ERC1155InvalidOperator(address(0));
}
$._operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256 id,
uint256 value,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) {
if (response != IERC1155Receiver.onERC1155Received.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address
* if it contains code at the moment of execution.
*/
function _doSafeBatchTransferAcceptanceCheck(
address operator,
address from,
address to,
uint256[] memory ids,
uint256[] memory values,
bytes memory data
) private {
if (to.code.length > 0) {
try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (
bytes4 response
) {
if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
// Tokens rejected
revert ERC1155InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
// non-ERC1155Receiver implementer
revert ERC1155InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
/**
* @dev Creates an array in memory with only one value for each of the elements provided.
*/
function _asSingletonArrays(
uint256 element1,
uint256 element2
) private pure returns (uint256[] memory array1, uint256[] memory array2) {
/// @solidity memory-safe-assembly
assembly {
// Load the free memory pointer
array1 := mload(0x40)
// Set array length to 1
mstore(array1, 1)
// Store the single element at the next word after the length (where content starts)
mstore(add(array1, 0x20), element1)
// Repeat for next array locating it right after the first array
array2 := add(array1, 0x40)
mstore(array2, 1)
mstore(add(array2, 0x20), element2)
// Update the free memory pointer by pointing after the second array
mstore(0x40, add(array2, 0x40))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @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), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {Enum} from "../libraries/Enum.sol";
/**
* @title IModuleManager - An interface of contract managing Safe modules
* @notice Modules are extensions with unlimited access to a Safe that can be added to a Safe by its owners.
⚠️ WARNING: Modules are a security risk since they can execute arbitrary transactions,
so only trusted and audited modules should be added to a Safe. A malicious module can
completely takeover a Safe.
* @author @safe-global/safe-protocol
*/
interface IModuleManager {
event EnabledModule(address indexed module);
event DisabledModule(address indexed module);
event ExecutionFromModuleSuccess(address indexed module);
event ExecutionFromModuleFailure(address indexed module);
event ChangedModuleGuard(address indexed moduleGuard);
/**
* @notice Enables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param module Module to be whitelisted.
*/
function enableModule(address module) external;
/**
* @notice Disables the module `module` for the Safe.
* @dev This can only be done via a Safe transaction.
* @param prevModule Previous module in the modules linked list.
* @param module Module to be removed.
*/
function disableModule(address prevModule, address module) external;
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token)
* @dev Function is virtual to allow overriding for L2 singleton to emit an event for indexing.
* @param to Destination address of module transaction.
* @param value Ether value of module transaction.
* @param data Data payload of module transaction.
* @param operation Operation type of module transaction.
* @return success Boolean flag indicating if the call succeeded.
*/
function execTransactionFromModule(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success);
/**
* @notice Execute `operation` (0: Call, 1: DelegateCall) to `to` with `value` (Native Token) and return data
* @param to Destination address of module transaction.
* @param value Ether value of module transaction.
* @param data Data payload of module transaction.
* @param operation Operation type of module transaction.
* @return success Boolean flag indicating if the call succeeded.
* @return returnData Data returned by the call.
*/
function execTransactionFromModuleReturnData(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation
) external returns (bool success, bytes memory returnData);
/**
* @notice Returns if an module is enabled
* @return True if the module is enabled
*/
function isModuleEnabled(address module) external view returns (bool);
/**
* @notice Returns an array of modules.
* If all entries fit into a single page, the next pointer will be 0x1.
* If another page is present, next will be the last element of the returned array.
* @param start Start of the page. Has to be a module or start pointer (0x1 address)
* @param pageSize Maximum number of modules that should be returned. Has to be > 0
* @return array Array of modules.
* @return next Start of the next page.
*/
function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next);
/**
* @dev Set a module guard that checks transactions initiated by the module before execution
* This can only be done via a Safe transaction.
* ⚠️ IMPORTANT: Since a module guard has full power to block Safe transaction execution initiatied via a module,
* a broken module guard can cause a denial of service for the Safe modules. Make sure to carefully
* audit the module guard code and design recovery mechanisms.
* @notice Set Module Guard `moduleGuard` for the Safe. Make sure you trust the module guard.
* @param moduleGuard The address of the module guard to be used or the zero address to disable the module guard.
*/
function setModuleGuard(address moduleGuard) external;
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title IOwnerManager - Interface for contract which manages Safe owners and a threshold to authorize transactions.
* @author @safe-global/safe-protocol
*/
interface IOwnerManager {
event AddedOwner(address indexed owner);
event RemovedOwner(address indexed owner);
event ChangedThreshold(uint256 threshold);
/**
* @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param owner New owner address.
* @param _threshold New threshold.
*/
function addOwnerWithThreshold(address owner, uint256 _threshold) external;
/**
* @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param prevOwner Owner that pointed to the owner to be removed in the linked list
* @param owner Owner address to be removed.
* @param _threshold New threshold.
*/
function removeOwner(address prevOwner, address owner, uint256 _threshold) external;
/**
* @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
* @dev This can only be done via a Safe transaction.
* @param prevOwner Owner that pointed to the owner to be replaced in the linked list
* @param oldOwner Owner address to be replaced.
* @param newOwner New owner address.
*/
function swapOwner(address prevOwner, address oldOwner, address newOwner) external;
/**
* @notice Changes the threshold of the Safe to `_threshold`.
* @dev This can only be done via a Safe transaction.
* @param _threshold New threshold.
*/
function changeThreshold(uint256 _threshold) external;
/**
* @notice Returns the number of required confirmations for a Safe transaction aka the threshold.
* @return Threshold number.
*/
function getThreshold() external view returns (uint256);
/**
* @notice Returns if `owner` is an owner of the Safe.
* @return Boolean if owner is an owner of the Safe.
*/
function isOwner(address owner) external view returns (bool);
/**
* @notice Returns a list of Safe owners.
* @return Array of Safe owners.
*/
function getOwners() external view returns (address[] memory);
}// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
/**
* @title IFallbackManager - A contract interface managing fallback calls made to this contract.
* @author @safe-global/safe-protocol
*/
interface IFallbackManager {
event ChangedFallbackHandler(address indexed handler);
/**
* @notice Set Fallback Handler to `handler` for the Safe.
* @dev Only fallback calls without value and with data will be forwarded.
* This can only be done via a Safe transaction.
* Cannot be set to the Safe itself.
* @param handler contract to handle fallback calls.
*/
function setFallbackHandler(address handler) external;
}// SPDX-License-Identifier: LGPL-3.0-only
/* solhint-disable one-contract-per-file */
pragma solidity >=0.7.0 <0.9.0;
/**
* @title IGuardManager - A contract interface managing transaction guards which perform pre and post-checks on Safe transactions.
* @author @safe-global/safe-protocol
*/
interface IGuardManager {
event ChangedGuard(address indexed guard);
/**
* @dev Set a guard that checks transactions before execution
* This can only be done via a Safe transaction.
* ⚠️ IMPORTANT: Since a guard has full power to block Safe transaction execution,
* a broken guard can cause a denial of service for the Safe. Make sure to carefully
* audit the guard code and design recovery mechanisms.
* @notice Set Transaction Guard `guard` for the Safe. Make sure you trust the guard.
* @param guard The address of the guard to be used or the 0 address to disable the guard
*/
function setGuard(address guard) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @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 ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the value of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155Received} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `value` amount.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* WARNING: This function can potentially allow a reentrancy attack when transferring tokens
* to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver.
* Ensure to follow the checks-effects-interactions pattern and consider employing
* reentrancy guards when interacting with untrusted contracts.
*
* Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments.
*
* Requirements:
*
* - `ids` and `values` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol)
pragma solidity ^0.8.20;
import {IERC1155} from "../IERC1155.sol";
/**
* @dev Interface of the optional ERC1155MetadataExtension interface, as defined
* in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
*/
interface IERC1155MetadataURI is IERC1155 {
/**
* @dev Returns the URI for token type `id`.
*
* If the `\{id\}` substring is present in the URI, it must be replaced by
* clients with the actual token type ID.
*/
function uri(uint256 id) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {Initializable} from "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165Upgradeable is Initializable, IERC165 {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.sol";
import {Math} from "./math/Math.sol";
/**
* @dev Collection of functions related to array types.
*/
library Arrays {
using StorageSlot for bytes32;
/**
* @dev Searches a sorted `array` and returns the first index that contains
* a value greater or equal to `element`. If no such index exists (i.e. all
* values in the array are strictly less than `element`), the array length is
* returned. Time complexity O(log n).
*
* `array` is expected to be sorted in ascending order, and to contain no
* repeated elements.
*/
function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) {
uint256 low = 0;
uint256 high = array.length;
if (high == 0) {
return 0;
}
while (low < high) {
uint256 mid = Math.average(low, high);
// Note that mid will always be strictly less than high (i.e. it will be a valid array index)
// because Math.average rounds towards zero (it does integer division with truncation).
if (unsafeAccess(array, mid).value > element) {
high = mid;
} else {
low = mid + 1;
}
}
// At this point `low` is the exclusive upper bound. We will return the inclusive upper bound.
if (low > 0 && unsafeAccess(array, low - 1).value == element) {
return low - 1;
} else {
return low;
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getAddressSlot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getBytes32Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) {
bytes32 slot;
// We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr`
// following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays.
/// @solidity memory-safe-assembly
assembly {
mstore(0, arr.slot)
slot := add(keccak256(0, 0x20), pos)
}
return slot.getUint256Slot();
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
/**
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
*
* WARNING: Only use if you are certain `pos` is lower than the array length.
*/
function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) {
assembly {
res := mload(add(add(arr, 0x20), mul(pos, 0x20)))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
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.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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 (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @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);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @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(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
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
}
}
}{
"remappings": [
"eas-contracts/=lib/eas-contracts/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IEAS","name":"eas","type":"address"},{"internalType":"address","name":"_attestator","type":"address"},{"internalType":"contract SuperChainBadges","name":"_superChainBadges","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessDenied","type":"error"},{"inputs":[],"name":"InsufficientValue","type":"error"},{"inputs":[],"name":"InvalidEAS","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"NotPayable","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"components":[{"internalType":"bytes32","name":"uid","type":"bytes32"},{"internalType":"bytes32","name":"schema","type":"bytes32"},{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"uint64","name":"revocationTime","type":"uint64"},{"internalType":"bytes32","name":"refUID","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"attester","type":"address"},{"internalType":"bool","name":"revocable","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Attestation","name":"attestation","type":"tuple"}],"name":"attest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"attestator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPayable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"uid","type":"bytes32"},{"internalType":"bytes32","name":"schema","type":"bytes32"},{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"uint64","name":"revocationTime","type":"uint64"},{"internalType":"bytes32","name":"refUID","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"attester","type":"address"},{"internalType":"bool","name":"revocable","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Attestation[]","name":"attestations","type":"tuple[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"multiAttest","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"uid","type":"bytes32"},{"internalType":"bytes32","name":"schema","type":"bytes32"},{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"uint64","name":"revocationTime","type":"uint64"},{"internalType":"bytes32","name":"refUID","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"attester","type":"address"},{"internalType":"bool","name":"revocable","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Attestation[]","name":"attestations","type":"tuple[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"multiRevoke","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"uid","type":"bytes32"},{"internalType":"bytes32","name":"schema","type":"bytes32"},{"internalType":"uint64","name":"time","type":"uint64"},{"internalType":"uint64","name":"expirationTime","type":"uint64"},{"internalType":"uint64","name":"revocationTime","type":"uint64"},{"internalType":"bytes32","name":"refUID","type":"bytes32"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"attester","type":"address"},{"internalType":"bool","name":"revocable","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Attestation","name":"attestation","type":"tuple"}],"name":"revoke","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"superChainBadges","outputs":[{"internalType":"contract SuperChainBadges","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superChainModule","outputs":[{"internalType":"contract SuperChainModuleUpgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_attestator","type":"address"}],"name":"updateAttestator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract SuperChainModuleUpgradeable","name":"_superChainModule","type":"address"}],"name":"updateSuperChainAccountsManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract SuperChainBadges","name":"_superChainBadges","type":"address"}],"name":"updateSuperChainBadges","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6101006040523480156200001257600080fd5b50604051620010053803806200100583398101604081905262000035916200014c565b6001608052600360a052600060c05280846001600160a01b0381166200006e576040516341bc07ff60e11b815260040160405180910390fd5b6001600160a01b0390811660e0528116620000a357604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000ae81620000e3565b5050600380546001600160a01b039384166001600160a01b0319918216179091556002805492909316911617905550620001b4565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200014957600080fd5b50565b600080600080608085870312156200016357600080fd5b8451620001708162000133565b6020860151909450620001838162000133565b6040860151909350620001968162000133565b6060860151909250620001a98162000133565b939692955090935050565b60805160a05160c05160e051610e17620001ee600039600061071b01526000610380015260006103570152600061032e0152610e176000f3fe6080604052600436106100ec5760003560e01c80638da5cb5b1161008a578063e49617e111610059578063e49617e11461026d578063e60c350514610280578063efa2669e14610293578063f2fde38b146102b357600080fd5b80638da5cb5b1461020857806391db0b7e14610226578063a8829a9514610239578063ce46e0461461025957600080fd5b806353e9aa0a116100c657806353e9aa0a1461018e57806354fd4d50146101ae578063715018a6146101d057806388e5b2d9146101e557600080fd5b80632132e424146101115780634554cb621461014e578063484bcfac1461016e57600080fd5b3661010c57604051631574f9f360e01b815260040160405180910390fd5b005b600080fd5b34801561011d57600080fd5b50600254610131906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015a57600080fd5b5061010a6101693660046109c2565b6102d3565b34801561017a57600080fd5b50600154610131906001600160a01b031681565b34801561019a57600080fd5b5061010a6101a93660046109c2565b6102fd565b3480156101ba57600080fd5b506101c3610327565b6040516101459190610a0a565b3480156101dc57600080fd5b5061010a6103ca565b6101f86101f3366004610a89565b6103de565b6040519015158152602001610145565b34801561021457600080fd5b506000546001600160a01b0316610131565b6101f8610234366004610a89565b6104ad565b34801561024557600080fd5b50600354610131906001600160a01b031681565b34801561026557600080fd5b5060006101f8565b6101f861027b366004610af5565b61056c565b6101f861028e366004610af5565b61057f565b34801561029f57600080fd5b5061010a6102ae3660046109c2565b610593565b3480156102bf57600080fd5b5061010a6102ce3660046109c2565b6105bd565b6102db610600565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b610305610600565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60606103527f000000000000000000000000000000000000000000000000000000000000000061062d565b61037b7f000000000000000000000000000000000000000000000000000000000000000061062d565b6103a47f000000000000000000000000000000000000000000000000000000000000000061062d565b6040516020016103b693929190610b31565b604051602081830303815290604052905090565b6103d2610600565b6103dc60006106c0565b565b60006103e8610710565b838281146104095760405163251f56a160e21b815260040160405180910390fd5b3460005b8281101561049d57600086868381811061042957610429610b8b565b905060200201359050828111156104535760405163044044a560e21b815260040160405180910390fd5b61048089898481811061046857610468610b8b565b905060200281019061047a9190610ba1565b50600190565b6104915760009450505050506104a5565b9091039060010161040d565b506001925050505b949350505050565b60006104b7610710565b838281146104d85760405163251f56a160e21b815260040160405180910390fd5b3460005b8281101561049d5760008686838181106104f8576104f8610b8b565b905060200201359050828111156105225760405163044044a560e21b815260040160405180910390fd5b61054f89898481811061053757610537610b8b565b90506020028101906105499190610ba1565b82610759565b6105605760009450505050506104a5565b909103906001016104dc565b6000610576610710565b60015b92915050565b6000610589610710565b6105798234610759565b61059b610600565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6105c5610600565b6001600160a01b0381166105f457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6105fd816106c0565b50565b6000546001600160a01b031633146103dc5760405163118cdaa760e01b81523360048201526024016105eb565b6060600061063a836108d5565b600101905060008167ffffffffffffffff81111561065a5761065a610bc2565b6040519080825280601f01601f191660200182016040528015610684576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461068e57509392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103dc57604051634ca8886760e01b815260040160405180910390fd5b6003546000906001600160a01b0316610779610100850160e086016109c2565b6001600160a01b03161461078f57506000610579565b600061079f610120850185610bd8565b8101906107ac9190610c79565b6002549091506000906001600160a01b03166397240eaa6107d360e0880160c089016109c2565b846040518363ffffffff1660e01b81526004016107f1929190610d46565b6020604051808303816000875af1158015610810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108349190610da6565b6001549091506001600160a01b03166347ac32bc8261085960e0890160c08a016109c2565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044016020604051808303816000875af11580156108a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c99190610dbf565b50600195945050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106109145772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610940576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061095e57662386f26fc10000830492506010015b6305f5e1008310610976576305f5e100830492506008015b612710831061098a57612710830492506004015b6064831061099c576064830492506002015b600a83106105795760010192915050565b6001600160a01b03811681146105fd57600080fd5b6000602082840312156109d457600080fd5b81356109df816109ad565b9392505050565b60005b83811015610a015781810151838201526020016109e9565b50506000910152565b6020815260008251806020840152610a298160408501602087016109e6565b601f01601f19169190910160400192915050565b60008083601f840112610a4f57600080fd5b50813567ffffffffffffffff811115610a6757600080fd5b6020830191508360208260051b8501011115610a8257600080fd5b9250929050565b60008060008060408587031215610a9f57600080fd5b843567ffffffffffffffff80821115610ab757600080fd5b610ac388838901610a3d565b90965094506020870135915080821115610adc57600080fd5b50610ae987828801610a3d565b95989497509550505050565b600060208284031215610b0757600080fd5b813567ffffffffffffffff811115610b1e57600080fd5b820161014081850312156109df57600080fd5b60008451610b438184602089016109e6565b8083019050601760f91b8082528551610b63816001850160208a016109e6565b60019201918201528351610b7e8160028401602088016109e6565b0160020195945050505050565b634e487b7160e01b600052603260045260246000fd5b6000823561013e19833603018112610bb857600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b6000808335601e19843603018112610bef57600080fd5b83018035915067ffffffffffffffff821115610c0a57600080fd5b602001915036819003821315610a8257600080fd5b6040805190810167ffffffffffffffff81118282101715610c4257610c42610bc2565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610c7157610c71610bc2565b604052919050565b60006020808385031215610c8c57600080fd5b823567ffffffffffffffff80821115610ca457600080fd5b818501915085601f830112610cb857600080fd5b813581811115610cca57610cca610bc2565b610cd8848260051b01610c48565b818152848101925060069190911b830184019087821115610cf857600080fd5b928401925b81841015610d3b5760408489031215610d165760008081fd5b610d1e610c1f565b843581528585013586820152835260409093019291840191610cfd565b979650505050505050565b6001600160a01b038316815260406020808301829052835183830181905260009291858101916060860190855b81811015610d9857845180518452840151848401529383019391850191600101610d73565b509098975050505050505050565b600060208284031215610db857600080fd5b5051919050565b600060208284031215610dd157600080fd5b815180151581146109df57600080fdfea2646970667358221220b93cdcb8e1d808b562731c9b5443f39eb4bd29aa362941470afc7607088f789f64736f6c6343000817003300000000000000000000000072e1d8ccf5299fb36fefd8cc4394b8ef7e98af920000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5000000000000000000000000d47c56513e640e394024facbbe5032cf604bb6990000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5
Deployed Bytecode
0x6080604052600436106100ec5760003560e01c80638da5cb5b1161008a578063e49617e111610059578063e49617e11461026d578063e60c350514610280578063efa2669e14610293578063f2fde38b146102b357600080fd5b80638da5cb5b1461020857806391db0b7e14610226578063a8829a9514610239578063ce46e0461461025957600080fd5b806353e9aa0a116100c657806353e9aa0a1461018e57806354fd4d50146101ae578063715018a6146101d057806388e5b2d9146101e557600080fd5b80632132e424146101115780634554cb621461014e578063484bcfac1461016e57600080fd5b3661010c57604051631574f9f360e01b815260040160405180910390fd5b005b600080fd5b34801561011d57600080fd5b50600254610131906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561015a57600080fd5b5061010a6101693660046109c2565b6102d3565b34801561017a57600080fd5b50600154610131906001600160a01b031681565b34801561019a57600080fd5b5061010a6101a93660046109c2565b6102fd565b3480156101ba57600080fd5b506101c3610327565b6040516101459190610a0a565b3480156101dc57600080fd5b5061010a6103ca565b6101f86101f3366004610a89565b6103de565b6040519015158152602001610145565b34801561021457600080fd5b506000546001600160a01b0316610131565b6101f8610234366004610a89565b6104ad565b34801561024557600080fd5b50600354610131906001600160a01b031681565b34801561026557600080fd5b5060006101f8565b6101f861027b366004610af5565b61056c565b6101f861028e366004610af5565b61057f565b34801561029f57600080fd5b5061010a6102ae3660046109c2565b610593565b3480156102bf57600080fd5b5061010a6102ce3660046109c2565b6105bd565b6102db610600565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b610305610600565b600380546001600160a01b0319166001600160a01b0392909216919091179055565b60606103527f000000000000000000000000000000000000000000000000000000000000000161062d565b61037b7f000000000000000000000000000000000000000000000000000000000000000361062d565b6103a47f000000000000000000000000000000000000000000000000000000000000000061062d565b6040516020016103b693929190610b31565b604051602081830303815290604052905090565b6103d2610600565b6103dc60006106c0565b565b60006103e8610710565b838281146104095760405163251f56a160e21b815260040160405180910390fd5b3460005b8281101561049d57600086868381811061042957610429610b8b565b905060200201359050828111156104535760405163044044a560e21b815260040160405180910390fd5b61048089898481811061046857610468610b8b565b905060200281019061047a9190610ba1565b50600190565b6104915760009450505050506104a5565b9091039060010161040d565b506001925050505b949350505050565b60006104b7610710565b838281146104d85760405163251f56a160e21b815260040160405180910390fd5b3460005b8281101561049d5760008686838181106104f8576104f8610b8b565b905060200201359050828111156105225760405163044044a560e21b815260040160405180910390fd5b61054f89898481811061053757610537610b8b565b90506020028101906105499190610ba1565b82610759565b6105605760009450505050506104a5565b909103906001016104dc565b6000610576610710565b60015b92915050565b6000610589610710565b6105798234610759565b61059b610600565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6105c5610600565b6001600160a01b0381166105f457604051631e4fbdf760e01b8152600060048201526024015b60405180910390fd5b6105fd816106c0565b50565b6000546001600160a01b031633146103dc5760405163118cdaa760e01b81523360048201526024016105eb565b6060600061063a836108d5565b600101905060008167ffffffffffffffff81111561065a5761065a610bc2565b6040519080825280601f01601f191660200182016040528015610684576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a850494508461068e57509392505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b336001600160a01b037f00000000000000000000000072e1d8ccf5299fb36fefd8cc4394b8ef7e98af9216146103dc57604051634ca8886760e01b815260040160405180910390fd5b6003546000906001600160a01b0316610779610100850160e086016109c2565b6001600160a01b03161461078f57506000610579565b600061079f610120850185610bd8565b8101906107ac9190610c79565b6002549091506000906001600160a01b03166397240eaa6107d360e0880160c089016109c2565b846040518363ffffffff1660e01b81526004016107f1929190610d46565b6020604051808303816000875af1158015610810573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108349190610da6565b6001549091506001600160a01b03166347ac32bc8261085960e0890160c08a016109c2565b6040516001600160e01b031960e085901b16815260048101929092526001600160a01b031660248201526044016020604051808303816000875af11580156108a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c99190610dbf565b50600195945050505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b83106109145772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610940576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061095e57662386f26fc10000830492506010015b6305f5e1008310610976576305f5e100830492506008015b612710831061098a57612710830492506004015b6064831061099c576064830492506002015b600a83106105795760010192915050565b6001600160a01b03811681146105fd57600080fd5b6000602082840312156109d457600080fd5b81356109df816109ad565b9392505050565b60005b83811015610a015781810151838201526020016109e9565b50506000910152565b6020815260008251806020840152610a298160408501602087016109e6565b601f01601f19169190910160400192915050565b60008083601f840112610a4f57600080fd5b50813567ffffffffffffffff811115610a6757600080fd5b6020830191508360208260051b8501011115610a8257600080fd5b9250929050565b60008060008060408587031215610a9f57600080fd5b843567ffffffffffffffff80821115610ab757600080fd5b610ac388838901610a3d565b90965094506020870135915080821115610adc57600080fd5b50610ae987828801610a3d565b95989497509550505050565b600060208284031215610b0757600080fd5b813567ffffffffffffffff811115610b1e57600080fd5b820161014081850312156109df57600080fd5b60008451610b438184602089016109e6565b8083019050601760f91b8082528551610b63816001850160208a016109e6565b60019201918201528351610b7e8160028401602088016109e6565b0160020195945050505050565b634e487b7160e01b600052603260045260246000fd5b6000823561013e19833603018112610bb857600080fd5b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b6000808335601e19843603018112610bef57600080fd5b83018035915067ffffffffffffffff821115610c0a57600080fd5b602001915036819003821315610a8257600080fd5b6040805190810167ffffffffffffffff81118282101715610c4257610c42610bc2565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715610c7157610c71610bc2565b604052919050565b60006020808385031215610c8c57600080fd5b823567ffffffffffffffff80821115610ca457600080fd5b818501915085601f830112610cb857600080fd5b813581811115610cca57610cca610bc2565b610cd8848260051b01610c48565b818152848101925060069190911b830184019087821115610cf857600080fd5b928401925b81841015610d3b5760408489031215610d165760008081fd5b610d1e610c1f565b843581528585013586820152835260409093019291840191610cfd565b979650505050505050565b6001600160a01b038316815260406020808301829052835183830181905260009291858101916060860190855b81811015610d9857845180518452840151848401529383019391850191600101610d73565b509098975050505050505050565b600060208284031215610db857600080fd5b5051919050565b600060208284031215610dd157600080fd5b815180151581146109df57600080fdfea2646970667358221220b93cdcb8e1d808b562731c9b5443f39eb4bd29aa362941470afc7607088f789f64736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000072e1d8ccf5299fb36fefd8cc4394b8ef7e98af920000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5000000000000000000000000d47c56513e640e394024facbbe5032cf604bb6990000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5
-----Decoded View---------------
Arg [0] : eas (address): 0x72E1d8ccf5299fb36fEfD8CC4394B8ef7e98Af92
Arg [1] : _attestator (address): 0x8835669696Fb92839aB198cD80ce9f0d35F45aD5
Arg [2] : _superChainBadges (address): 0xd47C56513E640E394024FaCBBe5032cf604Bb699
Arg [3] : owner (address): 0x8835669696Fb92839aB198cD80ce9f0d35F45aD5
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000072e1d8ccf5299fb36fefd8cc4394b8ef7e98af92
Arg [1] : 0000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5
Arg [2] : 000000000000000000000000d47c56513e640e394024facbbe5032cf604bb699
Arg [3] : 0000000000000000000000008835669696fb92839ab198cd80ce9f0d35f45ad5
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.