Contract

0x52CEba41Da235Af367bFC0b0cCd3314cb901bB5F

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-
Transaction Hash
Method
Block
From
To
Close Delegation5995972024-12-18 18:08:0517 hrs ago1734545285IN
0x52CEba41...cb901bB5F
0.94999999 S0.000751973.3
Delegate5988022024-12-18 18:03:0717 hrs ago1734544987IN
0x52CEba41...cb901bB5F
1 S0.000966143.3

Latest 2 internal transactions

Parent Transaction Hash Block From To
5995972024-12-18 18:08:0517 hrs ago1734545285
0x52CEba41...cb901bB5F
0.94999999 S
5988022024-12-18 18:03:0717 hrs ago1734544987
0x52CEba41...cb901bB5F
1 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SacraRelay

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 50 runs

Other Settings:
istanbul EvmVersion
File 1 of 4 : SacraRelay.sol
// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.23;

import "../openzeppelin/EnumerableSet.sol";
import "../openzeppelin/ECDSA.sol";
import "../interfaces/IAppErrors.sol";

/// @title Sacra relay contract
contract SacraRelay {
  using EnumerableSet for EnumerableSet.AddressSet;

  //region ------------------------ Data types
  /// @notice Relay call with user signature verification for ERC 2771 compliance
  struct CallWithERC2771 {
    uint chainId;
    address target;
    bytes data;
    address user;
    uint userNonce;
    uint userDeadline;
  }
  //endregion ------------------------ Data types

  //region ------------------------ Constants

  string public constant NAME = "SacraRelay";
  string public constant VERSION = "1.0.1";
  uint public immutable DELEGATION_DEADLINE = 1 weeks;
  bytes32 public immutable DOMAIN_SEPARATOR;
  bytes32 public constant CALL_ERC2771_TYPEHASH =
  keccak256(
    bytes(
      "CallERC2771(uint256 chainId,address target,bytes data,address user,uint256 userNonce,uint256 userDeadline)"
    )
  );

  //endregion ------------------------ Constants

  //region ------------------------ Variables

  /// @dev Suppose to be the game governance
  address public owner;
  /// @dev Allowed EOAs to call game contract on behalf of users
  EnumerableSet.AddressSet private _operators;
  /// @dev Allowance is a sequence of numbers where any non zero value means that operator is allowed to call game contract on behalf of user
  mapping(address => bool) public allowance;
  /// @dev Nonce for each user to prevent tx duplication
  mapping(address => uint) public userTxNonce;
  /// @dev User => Delegator. A user can allow another EOA to call any game action on behalf of him
  mapping(address => address) public delegatedCallers;
  /// @dev Delegator => Deadline for delegation
  mapping(address => uint) public delegatedDeadline;

  //endregion ------------------------ Variables

  //region ------------------------ Events
  event CalledFromOperator(CallWithERC2771 callData);
  event CalledFromDelegator(CallWithERC2771 callData);
  //endregion ------------------------ Events

  //region ------------------------ Constructor

  constructor(address owner_) {
    owner = owner_;

    DOMAIN_SEPARATOR = keccak256(
      abi.encode(
        keccak256(
          bytes(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
          )
        ),
        keccak256(bytes(NAME)),
        keccak256(bytes(VERSION)),
        block.chainid,
        address(this)
      )
    );
  }

  //endregion ------------------------ Constructor

  //region ------------------------ Views

  /// @dev Get all operators
  function operatorsList() external view returns (address[] memory) {
    return _operators.values();
  }

  /// @dev Get user info
  function userInfo(address user) external view returns (uint nonce, bool allowed, address delegator, uint delegatorDeadline) {
    delegator = delegatedCallers[user];
    return (userTxNonce[user], allowance[user], delegator, delegatedDeadline[delegator]);
  }

  //endregion ------------------------ Views

  //region ------------------------ Owner actions

  /// @dev Change owner of this contract
  function changeOwner(address newOwner) external {
    if (msg.sender != owner) revert IAppErrors.SacraRelayNotOwner();
    owner = newOwner;
  }

  /// @dev Add or remove operator
  function changeOperator(address operator, bool add) external {
    if (msg.sender != owner) revert IAppErrors.SacraRelayNotOwner();
    if (add) {
      _operators.add(operator);
    } else {
      _operators.remove(operator);
    }
  }
  //endregion ------------------------ Owner actions

  //region ------------------------ Main logic
  /// @dev Approve or disapprove operator to call game contract on behalf of users
  function approve(bool status) external {
    allowance[msg.sender] = status;
  }

  /// @dev Allow to call game contract on behalf of user for given EOA.
  ///      Zero delegator address means that user revoke permission for this EOA.
  ///      A user can refuel his delegator by sending some ether with this call.
  function delegate(address delegator) external payable {
    address oldDelegator = delegatedCallers[msg.sender];
    delegatedCallers[msg.sender] = delegator;

    delete delegatedDeadline[oldDelegator];
    delegatedDeadline[delegator] = block.timestamp + DELEGATION_DEADLINE;

    if (msg.value > 0) {
      payable(delegator).transfer(msg.value);
    }
  }

  /// @dev Close delegation for user.
  ///      Delegator can send back ether to user with this call.
  function closeDelegation(address user) external payable {
    if (delegatedCallers[user] != msg.sender) revert IAppErrors.SacraRelayNotDelegator();
    delete delegatedCallers[user];
    delete delegatedDeadline[msg.sender];

    if (msg.value > 0) {
      payable(user).transfer(msg.value);
    }
  }

  /// @dev Call from delegator. No user signature required.
  ///      We assume delegator is under control of user.
  function callFromDelegator(CallWithERC2771 calldata callInfo) external {
    if (delegatedCallers[callInfo.user] != msg.sender) revert IAppErrors.SacraRelayNotDelegator();
    if (callInfo.chainId != block.chainid) revert IAppErrors.SacraRelayInvalidChainId(callInfo.chainId, block.chainid);

    uint _userTxNonce = userTxNonce[callInfo.user];
    if (callInfo.userNonce != _userTxNonce) revert IAppErrors.SacraRelayInvalidNonce(callInfo.userNonce, _userTxNonce);
    if (callInfo.userDeadline != 0 && callInfo.userDeadline < block.timestamp) revert IAppErrors.SacraRelayDeadline();
    if (delegatedDeadline[msg.sender] < block.timestamp) revert IAppErrors.SacraRelayDelegationExpired();

    userTxNonce[callInfo.user] = _userTxNonce + 1;

    _revertingContractCall(callInfo.target, _encodeERC2771Context(callInfo.data, callInfo.user), "SacraRelay.DelegatedCall");

    emit CalledFromDelegator(callInfo);
  }

  /// @dev Call game contract on behalf of user. Require user signature for every call.
  function callFromOperator(CallWithERC2771 calldata callInfo, bytes calldata userSignature_) external {
    if (!_operators.contains(msg.sender)) revert IAppErrors.SacraRelayNotOperator();
    if (callInfo.chainId != block.chainid) revert IAppErrors.SacraRelayInvalidChainId(callInfo.chainId, block.chainid);

    // a user should allow this contract to call game contracts on behalf of him
    if (!allowance[callInfo.user]) revert IAppErrors.SacraRelayNotAllowed();

    uint _userTxNonce = userTxNonce[callInfo.user];
    if (callInfo.userNonce != _userTxNonce) revert IAppErrors.SacraRelayInvalidNonce(callInfo.userNonce, _userTxNonce);
    if (callInfo.userDeadline != 0 && callInfo.userDeadline < block.timestamp) revert IAppErrors.SacraRelayDeadline();

    // Verify user's signature
    _requireCallERC2771Signature(callInfo, userSignature_);

    userTxNonce[callInfo.user] = _userTxNonce + 1;

    _revertingContractCall(callInfo.target, _encodeERC2771Context(callInfo.data, callInfo.user), "SacraRelay.CallERC2771");

    emit CalledFromOperator(callInfo);
  }
  //endregion ------------------------ Main logic

  //region ------------------------ Internal logic
  /// @dev from GelatoCallUtils
  function _revertingContractCall(
    address _contract,
    bytes memory _data,
    string memory _errorMsg
  ) internal returns (bytes memory returnData) {
    bool success;
    (success, returnData) = _contract.call(_data);

    // solhint-disable-next-line max-line-length
    // https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/f9b6fc3fdab7aca33a9cfa8837c5cd7f67e176be/contracts/utils/AddressUpgradeable.sol#L177
    if (success) {
      if (returnData.length == 0) {
        // only check isContract if the call was successful and the return data is empty
        // otherwise we already know that it was a contract
        if (!_isContract(_contract)) revert IAppErrors.SacraRelayCallToNotContract(_contract, _errorMsg);
      }
    } else {
      _revertWithError(returnData, _errorMsg);
    }
  }

  /// @dev NOT SECURE CHECK! Just for more clear error messages
  function _isContract(address account) internal view returns (bool) {
    return account.code.length > 0;
  }

  function _revertWithError(bytes memory _bytes, string memory _tracingInfo) internal pure {
    // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err
    if (_bytes.length % 32 == 4) {
      bytes4 selector;
      assembly {
        selector := mload(add(0x20, _bytes))
      }
      if (selector == 0x08c379a0) {
        // Function selector for Error(string)
        assembly {
          _bytes := add(_bytes, 68)
        }
        revert(string(abi.encodePacked(_tracingInfo, string(_bytes))));
      } else {
        revert IAppErrors.SacraRelayNoErrorSelector(selector, _tracingInfo);
      }
    } else {
      revert IAppErrors.SacraRelayUnexpectedReturnData(_bytes, _tracingInfo);
    }
  }

  /// @dev vanilla ERC2771 context encoding
  function _encodeERC2771Context(bytes calldata _data, address _msgSender) pure internal returns (bytes memory){
    return abi.encodePacked(_data, _msgSender);
  }

  function _requireCallERC2771Signature(CallWithERC2771 calldata callInfo, bytes calldata signature_) internal view returns (bytes32 digest) {
    digest = keccak256(
      abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        keccak256(_abiEncodeCallERC2771(callInfo))
      )
    );

    (address recovered, ECDSA.RecoverError error,) = ECDSA.tryRecover(digest, signature_);
    if (error != ECDSA.RecoverError.NoError || recovered != callInfo.user) revert IAppErrors.SacraRelayInvalidSignature();
  }

  function _abiEncodeCallERC2771(CallWithERC2771 calldata callInfo) internal pure returns (bytes memory){
    return abi.encode(
      CALL_ERC2771_TYPEHASH,
      callInfo.chainId,
      callInfo.target,
      keccak256(callInfo.data),
      callInfo.user,
      callInfo.userNonce,
      callInfo.userDeadline
    );
  }
  //endregion ------------------------ Internal logic

  receive() external payable {}
}

File 2 of 4 : IAppErrors.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.23;

/// @notice All errors of the app
interface IAppErrors {

  //region ERC20Errors
  /**
     * @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);

  //endregion ERC20Errors

  //region ERC721Errors

  /**
  * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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);

  //endregion ERC721Errors

  error ZeroAddress();
  error ZeroValueNotAllowed();
  error ZeroToken();
  error LengthsMismatch();
  error NotEnoughBalance();
  error NotEnoughAllowance();
  error EmptyNameNotAllowed();
  error NotInitialized();
  error AlreadyInitialized();
  error ReentrancyGuardReentrantCall();
  error TooLongString();
  error AlreadyDeployed(address deployed);

  //region Restrictions
  error ErrorNotDeployer(address sender);
  error ErrorNotGoc();
  error NotGovernance(address sender);
  error ErrorOnlyEoa();
  error NotEOA(address sender);
  error ErrorForbidden(address sender);
  error AdminOnly();
  error ErrorNotItemController(address sender);
  error ErrorNotHeroController(address sender);
  error ErrorNotDungeonFactory(address sender);
  error ErrorNotObjectController(address sender);
  error ErrorNotStoryController();
  error ErrorNotAllowedSender();
  error MintNotAllowed();
  //endregion Restrictions

  //region PackingLib
  error TooHighValue(uint value);
  error IntValueOutOfRange(int value);
  error OutOfBounds(uint index, uint length);
  error UnexpectedValue(uint expected, uint actual);
  error WrongValue(uint newValue, uint actual);
  error IntOutOfRange(int value);
  error ZeroValue();
  /// @notice packCustomDataChange requires an input string with two zero bytes at the beginning
  ///         0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0000
  /// This error happens if these bytes are not zero
  error IncompatibleInputString();
  error IncorrectOtherItemTypeKind(uint8 kind);
  //endregion PackingLib

  //region Hero
  error ErrorHeroIsNotRegistered(address heroToken);
  error ErrorHeroIsDead(address heroToken, uint heroTokenId);
  error ErrorHeroNotInDungeon();
  error HeroInDungeon();
  error ErrorNotOwner(address token, uint tokenId);
  error Staked(address heroToken, uint heroId);
  error NameTaken();
  error TooBigName();
  error WrongSymbolsInTheName();
  error NoPayToken(address token, uint payTokenAmount);
  error AlreadyHaveReinforcement();
  /// @notice SIP-001 - Reinforcement requires 3 skills
  error ErrorReinforcementRequiresThreeSkills();
  error WrongTier(uint tier);
  error NotEnoughNgLevel(uint8 ngLevel);
  error NgpNotActive(address hero);
  error RebornNotAllowed();
  error AlreadyPrePaidHero();
  //endregion Hero

  //region Dungeon
  error ErrorDungeonIsFreeAlready();
  error ErrorNoEligibleDungeons();
  error ErrorDungeonBusy();
  error ErrorNoDungeonsForBiome(uint8 heroBiome);
  error ErrorDungeonCompleted();
  error ErrorAlreadyInDungeon();
  error NotEnoughTokens(uint balance, uint expectedBalance);
  error DungeonAlreadySpecific(uint16 dungNum);
  error DungeonAlreadySpecific2(uint16 dungNum);
  error WrongSpecificDungeon();
  //endregion Dungeon

  //region Items
  error ErrorItemNotEligibleForTheSlot(uint itemType, uint8 itemSlot);
  error ErrorItemSlotBusyHand(uint8 slot);
  error ErrorItemSlotBusy();
  error ErrorItemNotInSlot();
  error ErrorConsumableItemIsUsed(address item);
  error ErrorCannotRemoveItemFromMap();
  error ErrorCannotRemoveDataFromMap();
  error EquippedItemsExist();
  error ItemEquipped(address item, uint itemId);
  error ZeroItemMetaType();
  error NotZeroOtherItemMetaType();
  error ZeroLevel();
  error ItemTypeChanged();
  error ItemMetaTypeChanged();
  error UnknownItem(address item);
  error ErrorEquipForbidden();
  error EquipForbiddenInDungeon();
  error TakeOffForbiddenInDungeon();
  error Consumable(address item);
  error NotConsumable(address item);
  error Broken(address item);
  error ZeroLife();
  error RequirementsToItemAttributes();
  error NotEquipped(address item);
  error ZeroDurability();
  error ZeroAugmentation();
  error TooHighAgLevel(uint8 augmentationLevel);
  error UseForbiddenZeroPayToken();
  error IncorrectMinMaxAttributeRange(int32 min, int32 max);
  error SameIdsNotAllowed();
  error ZeroFragility();
  error OtherTypeItemNotRepairable();
  error NotOther();
  error DoubleItemUsageForbidden(uint itemIndex, address[] items);
  error ItemAlreadyUsedInSlot(address item, uint8 equippedSlot);
  error WrongWayToRegisterItem();
  error UnionItemNotFound(address item);
  error WrongListUnionItemTokens(address item, uint countTokens, uint requiredCountTokens);
  error UnknownUnionConfig(uint unionConfigId);
  error UserHasNoKeyPass(address user, address keyPassItem);
  error MaxValue(uint value);
  error UnexpectedOtherItem(address item);
  error NotExist();
  //endregion Items

  //region Stages
  error ErrorWrongStage(uint stage);
  error ErrorNotStages();
  //endregion Stages

  //region Level
  error ErrorWrongLevel(uint heroLevel);
  error ErrorLevelTooLow(uint heroLevel);
  error ErrorHeroLevelStartFrom1();
  error ErrorWrongLevelUpSum();
  error ErrorMaxLevel();
  //endregion Level

  //region Treasure
  error ErrorNotValidTreasureToken(address treasureToken);
  //endregion Treasure

  //region State
  error ErrorPaused();
  error ErrorNotReady();
  error ErrorNotObject1();
  error ErrorNotObject2();
  error ErrorNotCompleted();
  //endregion State

  //region Biome
  error ErrorNotBiome();
  error ErrorIncorrectBiome(uint biome);
  error TooHighBiome(uint biome);
  //endregion Biome

  //region Misc
  error ErrorWrongMultiplier(uint multiplier);
  error ErrorNotEnoughMana(uint32 mana, uint requiredMana);
  error ErrorExperienceMustNotDecrease();
  error ErrorNotEnoughExperience();
  error ErrorNotChances();
  error ErrorNotEligible(address heroToken, uint16 dungNum);
  error ErrorZeroKarmaNotAllowed();
  //endregion Misc

  //region GOC
  error GenObjectIdBiomeOverflow(uint8 biome);
  error GenObjectIdSubTypeOverflow(uint subType);
  error GenObjectIdIdOverflow(uint id);
  error UnknownObjectTypeGoc1(uint8 objectType);
  error UnknownObjectTypeGoc2(uint8 objectType);
  error UnknownObjectTypeGocLib1(uint8 objectType);
  error UnknownObjectTypeGocLib2(uint8 objectType);
  error UnknownObjectTypeForSubtype(uint8 objectSubType);
  error FightDelay();
  error ZeroChance();
  error TooHighChance(uint32 chance);
  error TooHighRandom(uint random);
  error EmptyObjects();
  error ObjectNotFound();
  error WrongGetObjectTypeInput();
  error WrongChances(uint32 chances, uint32 maxChances);
  //endregion GOC

  //region Story
  error PageNotRemovedError(uint pageId);
  error NotItem1();
  error NotItem2();
  error NotRandom(uint32 random);
  error NotHeroData();
  error NotGlobalData();
  error ZeroStoryIdRemoveStory();
  error ZeroStoryIdStoryAction();
  error ZeroStoryIdAction();
  error NotEnoughAmount(uint balance, uint requiredAmount);
  error NotAnswer();
  error AnswerStoryIdMismatch(uint16 storyId, uint16 storyIdFromAnswerHash);
  error AnswerPageIdMismatch(uint16 pageId, uint16 pageIdFromAnswerHash);
  //endregion Story

  //region FightLib
  error NotMagic();
  error NotAType(uint atype);
  //endregion FightLib

  //region MonsterLib
  error NotYourDebuffItem();
  error UnknownAttackType(uint attackType);
  error NotYourAttackItem();
  /// @notice The skill item cannot be used because it doesn't belong either to the hero or to the hero's helper
  error NotYourBuffItem();
  //endregion MonsterLib

  //region GameToken
  error ApproveToZeroAddress();
  error MintToZeroAddress();
  error TransferToZeroAddress();
  error TransferAmountExceedsBalance(uint balance, uint value);
  error InsufficientAllowance();
  error BurnAmountExceedsBalance();
  error NotMinter(address sender);
  //endregion GameToken

  //region NFT
  error TokenTransferNotAllowed();
  error IdOverflow(uint id);
  error NotExistToken(uint tokenId);
  error EquippedItemIsNotAllowedToTransfer(uint tokenId);
  //endregion NFT

  //region CalcLib
  error TooLowX(uint x);
  //endregion CalcLib

  //region Controller
  error NotFutureGovernance(address sender);
  //endregion Controller

  //region Oracle
  error OracleWrongInput();
  //endregion Oracle

  //region ReinforcementController
  error AlreadyStaked();
  error MaxFee(uint8 fee);
  error MinFee(uint8 fee);
  error StakeHeroNotStats();
  error NotStaked();
  error NoStakedHeroes();
  error GuildHelperNotAvailable(uint guildId, address helper, uint helperId);
  error HelperNotAvailableInGivenBiome();
  //endregion ReinforcementController

  //region SponsoredHero
  error InvalidHeroClass();
  error ZeroAmount();
  error InvalidProof();
  error NoHeroesAvailable();
  error AlreadyRegistered();
  //endregion SponsoredHero

  //region SacraRelay
  error SacraRelayNotOwner();
  error SacraRelayNotDelegator();
  error SacraRelayNotOperator();
  error SacraRelayInvalidChainId(uint callChainId, uint blockChainId);
  error SacraRelayInvalidNonce(uint callNonce, uint txNonce);
  error SacraRelayDeadline();
  error SacraRelayDelegationExpired();
  error SacraRelayNotAllowed();
  error SacraRelayInvalidSignature();
  /// @notice This error is generated when custom error is caught
  /// There is no info about custom error in SacraRelay
  /// but you can decode custom error by selector, see tests
  error SacraRelayNoErrorSelector(bytes4 selector, string tracingInfo);
  /// @notice This error is generated when custom error is caught
  /// There is no info about custom error in SacraRelay
  /// but you can decode custom error manually from {errorBytes} as following:
  /// if (keccak256(abi.encodeWithSignature("MyError()")) == keccak256(errorBytes)) { ... }
  error SacraRelayUnexpectedReturnData(bytes errorBytes, string tracingInfo);
  error SacraRelayCallToNotContract(address notContract, string tracingInfo);
  //endregion SacraRelay

  //region Misc
  error UnknownHeroClass(uint heroClass);
  error AbsDiff(int32 a, int32 b);
  //region Misc

  //region ------------------------ UserController
  error NoAvailableLootBox(address msgSender, uint lootBoxKind);
  error FameHallHeroAlreadyRegistered(uint8 openedNgLevel);

  //endregion ------------------------ UserController

  //region ------------------------ Guilds
  error AlreadyGuildMember();
  error NotGuildMember();
  error WrongGuild();
  error GuildActionForbidden(uint right);
  error GuildHasMaxSize(uint guildSize);
  error GuildHasMaxLevel(uint level);
  error TooLongUrl();
  error TooLongDescription();
  error CannotRemoveGuildOwnerFromNotEmptyGuild();
  error GuildControllerOnly();
  error GuildAlreadyHasShelter();
  error ShelterIsBusy();
  error ShelterIsNotRegistered();
  error ShelterIsNotOwnedByTheGuild();
  error ShelterIsInUse();
  error GuildHasNoShelter();
  error ShelterBidIsNotAllowedToBeUsed();
  error ShelterHasHeroesInside();
  error SecondGuildAdminIsNotAllowed();
  error NotEnoughGuildBankBalance(uint guildId);

  error GuildReinforcementCooldownPeriod();
  error NoStakedGuildHeroes();
  error NotStakedInGuild();
  error ShelterHasNotEnoughLevelForReinforcement();
  error NotBusyGuildHelper();

  error GuildRequestNotActive();
  error GuildRequestNotAvailable();
  error NotAdminCannotAddMemberWithNotZeroRights();
  //endregion ------------------------ Guilds

  //region ------------------------ Shelters
  error ErrorNotShelterController();
  error ErrorNotGuildController();
  error ShelterHasNotItem(uint shelterId, address item);
  error MaxNumberItemsSoldToday(uint numSoldItems, uint limit);
  error GuildHasNotEnoughPvpPoints(uint64 pointsAvailable, uint pointRequired);
  error FreeShelterItemsAreNotAllowed(uint shelterId, address item);
  error TooLowShelterLevel(uint8 shelterLevel, uint8 allowedShelterLevel);
  error NotEnoughPvpPointsCapacity(address user, uint usedPoints, uint pricePvpPoints, uint64 capactiy);
  error IncorrectShelterLevel(uint8 shelterLevel);
  //endregion ------------------------ Shelters

  //region ------------------------ Auction
  error WrongAuctionPosition();
  error AuctionPositionClosed();
  error AuctionBidOpened(uint positionId);
  error TooLowAmountToBid();
  error AuctionEnded();
  error TooLowAmountForNewBid();
  error AuctionSellerOnly();
  error AuctionBuyerOnly();
  error AuctionBidNotFound();
  error AuctionBidClosed();
  error OnlyShelterAuction();
  error CannotCloseLastBid();
  error AuctionNotEnded();
  error NotShelterAuction();
  error AuctionPositionOpened(uint positionId);
  error AuctionSellerCannotBid();
  error AuctionGuildWithShelterCannotBid();
  error AuctionBidExists();
  //endregion ------------------------ Auction

  //region ------------------------ Pawnshop
  error AuctionPositionNotSupported(uint positionId);
  error PositionNotSupported(uint positionId);
  error NotNftPositionNotSupported(uint positionId);
  error CallFailed(bytes callResultData);

  error PawnShopZeroOwner();
  error PawnShopZeroFeeRecipient();
  error PawnShopNotOwner();
  error PawnShopAlreadyAnnounced();
  error PawnShopTimeLock();
  error PawnShopWrongAddressValue();
  error PawnShopWrongUintValue();
  error PawnShopZeroAddress();
  error PawnShopTooHighValue();
  error PawnShopZeroAToken();
  error PawnShopZeroCToken();
  error PawnShopWrongAmounts();
  error PawnShopPosFeeForInstantDealForbidden();
  error PawnShopPosFeeAbsurdlyHigh();
  error PawnShopIncorrect();
  error PawnShopWrongId();
  error PawnShopNotBorrower();
  error PawnShopPositionClosed();
  error PawnShopPositionExecuted();
  error PawnShopWrongBidAmount();
  error PawnShopTooLowBid();
  error PawnShopNewBidTooLow();
  error PawnShopBidAlreadyExists();
  error PawnShopAuctionEnded();
  error PawnShopNotLender();
  error PawnShopTooEarlyToClaim();
  error PawnShopPositionNotExecuted();
  error PawnShopAlreadyClaimed();
  error PawnShopAuctionNotEnded();
  error PawnShopBidClosed();
  error PawnShopNoBids();
  error PawnShopAuctionBidNotFound();
  error PawnShopWrongBid();
  error PawnShopBidNotFound();

  //endregion ------------------------ Pawnshop
}

File 3 of 4 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
  enum RecoverError {
    NoError,
    InvalidSignature,
    InvalidSignatureLength,
    InvalidSignatureS
  }

  /**
   * @dev The signature derives the `address(0)`.
     */
  error ECDSAInvalidSignature();

  /**
   * @dev The signature has an invalid length.
     */
  error ECDSAInvalidSignatureLength(uint256 length);

  /**
   * @dev The signature has an S value that is in the upper half order.
     */
  error ECDSAInvalidSignatureS(bytes32 s);

  /**
   * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
  function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
    if (signature.length == 65) {
      bytes32 r;
      bytes32 s;
      uint8 v;
      // ecrecover takes the signature parameters, and the only way to get them
      // currently is to use assembly.
      /// @solidity memory-safe-assembly
      assembly {
        r := mload(add(signature, 0x20))
        s := mload(add(signature, 0x40))
        v := byte(0, mload(add(signature, 0x60)))
      }
      return tryRecover(hash, v, r, s);
    } else {
      return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
    }
  }

  /**
   * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
  function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
    _throwError(error, errorArg);
    return recovered;
  }

  /**
   * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
     */
  function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
    unchecked {
      bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
    // We do not check for an overflow here since the shift operation results in 0 or 1.
      uint8 v = uint8((uint256(vs) >> 255) + 27);
      return tryRecover(hash, v, r, s);
    }
  }

  /**
   * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
  function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
    _throwError(error, errorArg);
    return recovered;
  }

  /**
   * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
  function tryRecover(
    bytes32 hash,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) internal pure returns (address, RecoverError, bytes32) {
    // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
    // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
    // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
    // signatures from current libraries generate a unique signature with an s-value in the lower half order.
    //
    // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
    // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
    // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
    // these malleable signatures as well.
    if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
      return (address(0), RecoverError.InvalidSignatureS, s);
    }

    // If the signature is valid (and not malleable), return the signer address
    address signer = ecrecover(hash, v, r, s);
    if (signer == address(0)) {
      return (address(0), RecoverError.InvalidSignature, bytes32(0));
    }

    return (signer, RecoverError.NoError, bytes32(0));
  }

  /**
   * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
  function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
    (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
    _throwError(error, errorArg);
    return recovered;
  }

  /**
   * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
  function _throwError(RecoverError error, bytes32 errorArg) private pure {
    if (error == RecoverError.NoError) {
      return; // no error: do nothing
    } else if (error == RecoverError.InvalidSignature) {
      revert ECDSAInvalidSignature();
    } else if (error == RecoverError.InvalidSignatureLength) {
      revert ECDSAInvalidSignatureLength(uint256(errorArg));
    } else if (error == RecoverError.InvalidSignatureS) {
      revert ECDSAInvalidSignatureS(errorArg);
    }
  }
}

File 4 of 4 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
  // To implement this library for multiple types with as little code
  // repetition as possible, we write it in terms of a generic Set type with
  // bytes32 values.
  // The Set implementation uses private functions, and user-facing
  // implementations (such as AddressSet) are just wrappers around the
  // underlying Set.
  // This means that we can only create new EnumerableSets for types that fit
  // in bytes32.

  struct Set {
    // Storage of set values
    bytes32[] _values;
    // Position is the index of the value in the `values` array plus 1.
    // Position 0 is used to mean a value is not in the set.
    mapping(bytes32 value => uint256) _positions;
  }

  /**
   * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
  function _add(Set storage set, bytes32 value) private returns (bool) {
    if (!_contains(set, value)) {
      set._values.push(value);
      // The value is stored at length-1, but we add 1 to all indexes
      // and use 0 as a sentinel value
      set._positions[value] = set._values.length;
      return true;
    } else {
      return false;
    }
  }

  /**
   * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
  function _remove(Set storage set, bytes32 value) private returns (bool) {
    // We cache the value's position to prevent multiple reads from the same storage slot
    uint256 position = set._positions[value];

    if (position != 0) {
      // Equivalent to contains(set, value)
      // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
      // the array, and then remove the last element (sometimes called as 'swap and pop').
      // This modifies the order of the array, as noted in {at}.

      uint256 valueIndex = position - 1;
      uint256 lastIndex = set._values.length - 1;

      if (valueIndex != lastIndex) {
        bytes32 lastValue = set._values[lastIndex];

        // Move the lastValue to the index where the value to delete is
        set._values[valueIndex] = lastValue;
        // Update the tracked position of the lastValue (that was just moved)
        set._positions[lastValue] = position;
      }

      // Delete the slot where the moved value was stored
      set._values.pop();

      // Delete the tracked position for the deleted slot
      delete set._positions[value];

      return true;
    } else {
      return false;
    }
  }

  /**
   * @dev Returns true if the value is in the set. O(1).
     */
  function _contains(Set storage set, bytes32 value) private view returns (bool) {
    return set._positions[value] != 0;
  }

  /**
   * @dev Returns the number of values on the set. O(1).
     */
  function _length(Set storage set) private view returns (uint256) {
    return set._values.length;
  }

  /**
   * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
  function _at(Set storage set, uint256 index) private view returns (bytes32) {
    return set._values[index];
  }

  /**
   * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
  function _values(Set storage set) private view returns (bytes32[] memory) {
    return set._values;
  }

  // Bytes32Set

  struct Bytes32Set {
    Set _inner;
  }

  /**
   * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
  function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
    return _add(set._inner, value);
  }

  /**
   * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
  function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
    return _remove(set._inner, value);
  }

  /**
   * @dev Returns true if the value is in the set. O(1).
     */
  function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
    return _contains(set._inner, value);
  }

  /**
   * @dev Returns the number of values in the set. O(1).
     */
  function length(Bytes32Set storage set) internal view returns (uint256) {
    return _length(set._inner);
  }

  /**
   * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
  function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
    return _at(set._inner, index);
  }

  /**
   * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
  function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
    bytes32[] memory store = _values(set._inner);
    bytes32[] memory result;

    /// @solidity memory-safe-assembly
    assembly {
      result := store
    }

    return result;
  }

  // AddressSet

  struct AddressSet {
    Set _inner;
  }

  /**
   * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
  function add(AddressSet storage set, address value) internal returns (bool) {
    return _add(set._inner, bytes32(uint256(uint160(value))));
  }

  /**
   * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
  function remove(AddressSet storage set, address value) internal returns (bool) {
    return _remove(set._inner, bytes32(uint256(uint160(value))));
  }

  /**
   * @dev Returns true if the value is in the set. O(1).
     */
  function contains(AddressSet storage set, address value) internal view returns (bool) {
    return _contains(set._inner, bytes32(uint256(uint160(value))));
  }

  /**
   * @dev Returns the number of values in the set. O(1).
     */
  function length(AddressSet storage set) internal view returns (uint256) {
    return _length(set._inner);
  }

  /**
   * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
  function at(AddressSet storage set, uint256 index) internal view returns (address) {
    return address(uint160(uint256(_at(set._inner, index))));
  }

  /**
   * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
  function values(AddressSet storage set) internal view returns (address[] memory) {
    bytes32[] memory store = _values(set._inner);
    address[] memory result;

    /// @solidity memory-safe-assembly
    assembly {
      result := store
    }

    return result;
  }

  // UintSet

  struct UintSet {
    Set _inner;
  }

  /**
   * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
  function add(UintSet storage set, uint256 value) internal returns (bool) {
    return _add(set._inner, bytes32(value));
  }

  /**
   * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
  function remove(UintSet storage set, uint256 value) internal returns (bool) {
    return _remove(set._inner, bytes32(value));
  }

  /**
   * @dev Returns true if the value is in the set. O(1).
     */
  function contains(UintSet storage set, uint256 value) internal view returns (bool) {
    return _contains(set._inner, bytes32(value));
  }

  /**
   * @dev Returns the number of values in the set. O(1).
     */
  function length(UintSet storage set) internal view returns (uint256) {
    return _length(set._inner);
  }

  /**
   * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
  function at(UintSet storage set, uint256 index) internal view returns (uint256) {
    return uint256(_at(set._inner, index));
  }

  /**
   * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
  function values(UintSet storage set) internal view returns (uint256[] memory) {
    bytes32[] memory store = _values(set._inner);
    uint256[] memory result;

    /// @solidity memory-safe-assembly
    assembly {
      result := store
    }

    return result;
  }
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 50
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"notContract","type":"address"},{"internalType":"string","name":"tracingInfo","type":"string"}],"name":"SacraRelayCallToNotContract","type":"error"},{"inputs":[],"name":"SacraRelayDeadline","type":"error"},{"inputs":[],"name":"SacraRelayDelegationExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"callChainId","type":"uint256"},{"internalType":"uint256","name":"blockChainId","type":"uint256"}],"name":"SacraRelayInvalidChainId","type":"error"},{"inputs":[{"internalType":"uint256","name":"callNonce","type":"uint256"},{"internalType":"uint256","name":"txNonce","type":"uint256"}],"name":"SacraRelayInvalidNonce","type":"error"},{"inputs":[],"name":"SacraRelayInvalidSignature","type":"error"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"string","name":"tracingInfo","type":"string"}],"name":"SacraRelayNoErrorSelector","type":"error"},{"inputs":[],"name":"SacraRelayNotAllowed","type":"error"},{"inputs":[],"name":"SacraRelayNotDelegator","type":"error"},{"inputs":[],"name":"SacraRelayNotOperator","type":"error"},{"inputs":[],"name":"SacraRelayNotOwner","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorBytes","type":"bytes"},{"internalType":"string","name":"tracingInfo","type":"string"}],"name":"SacraRelayUnexpectedReturnData","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"userNonce","type":"uint256"},{"internalType":"uint256","name":"userDeadline","type":"uint256"}],"indexed":false,"internalType":"struct SacraRelay.CallWithERC2771","name":"callData","type":"tuple"}],"name":"CalledFromDelegator","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"userNonce","type":"uint256"},{"internalType":"uint256","name":"userDeadline","type":"uint256"}],"indexed":false,"internalType":"struct SacraRelay.CallWithERC2771","name":"callData","type":"tuple"}],"name":"CalledFromOperator","type":"event"},{"inputs":[],"name":"CALL_ERC2771_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATION_DEADLINE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"userNonce","type":"uint256"},{"internalType":"uint256","name":"userDeadline","type":"uint256"}],"internalType":"struct SacraRelay.CallWithERC2771","name":"callInfo","type":"tuple"}],"name":"callFromDelegator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"userNonce","type":"uint256"},{"internalType":"uint256","name":"userDeadline","type":"uint256"}],"internalType":"struct SacraRelay.CallWithERC2771","name":"callInfo","type":"tuple"},{"internalType":"bytes","name":"userSignature_","type":"bytes"}],"name":"callFromOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"add","type":"bool"}],"name":"changeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"closeDelegation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatedCallers","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegatedDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorsList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"address","name":"delegator","type":"address"},{"internalType":"uint256","name":"delegatorDeadline","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userTxNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c060405262093a8060805234801561001757600080fd5b506040516119583803806119588339810160408190526100369161012c565b600080546001600160a01b0319166001600160a01b0383161790556040805160808101909152605280825261190660208301398051602091820120604080518082018252600a815269536163726152656c617960b01b90840152805180820182526005815264312e302e3160d81b908401528051928301919091527f32a92115be7e065b55c8b7fc04acb48f2699673871fc189c5de626fae92d0c99908201527ffc7f6d936935ae6385924f29da7af79e941070dafe46831a51595892abc1b97a60608201524660808201523060a082015260c00160408051601f19818403018152919052805160209091012060a0525061015c565b60006020828403121561013e57600080fd5b81516001600160a01b038116811461015557600080fd5b9392505050565b60805160a05161177761018f600039600081816102570152610c8f01526000818161045301526107d201526117776000f3fe6080604052600436106100f85760003560e01c8063748e002411610090578063748e0024146102f95780637c9227a614610347578063860639ec1461035c5780638da5cb5b1461037c578063a3f4df7e1461039c578063a6f9dae1146103df578063ad96569a146103ff578063c54191061461041f578063f7b13b4114610441578063ffa1ad741461047557600080fd5b806309b67f8e14610104578063112710a914610141578063158731ce146101815780631959a002146101a15780632b3d167e146102325780633644e515146102455780633e5beab9146102795780635c19a95c146102b95780635da2fd42146102cc57600080fd5b366100ff57005b600080fd5b34801561011057600080fd5b5061013f61011f3660046111fc565b336000908152600360205260409020805460ff1916911515919091179055565b005b34801561014d57600080fd5b5061016e61015c36600461122e565b60066020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561018d57600080fd5b5061013f61019c366004611261565b6104a6565b3480156101ad57600080fd5b506102036101bc36600461122e565b6001600160a01b038082166000908152600560209081526040808320546004835281842054600384528285205491909516808552600690935292205460ff90921693509193565b604051610178949392919093845291151560208401526001600160a01b03166040830152606082015260800190565b61013f61024036600461122e565b6106e2565b34801561025157600080fd5b5061016e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561028557600080fd5b506102a961029436600461122e565b60036020526000908152604090205460ff1681565b6040519015158152602001610178565b61013f6102c736600461122e565b610790565b3480156102d857600080fd5b5061016e6102e736600461122e565b60046020526000908152604090205481565b34801561030557600080fd5b5061032f61031436600461122e565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610178565b34801561035357600080fd5b5061016e610850565b34801561036857600080fd5b5061013f61037736600461129d565b610873565b34801561038857600080fd5b5060005461032f906001600160a01b031681565b3480156103a857600080fd5b506103d26040518060400160405280600a815260200169536163726152656c617960b01b81525081565b6040516101789190611320565b3480156103eb57600080fd5b5061013f6103fa36600461122e565b6108c0565b34801561040b57600080fd5b5061013f61041a366004611333565b61090d565b34801561042b57600080fd5b50610434610b41565b60405161017891906113c9565b34801561044d57600080fd5b5061016e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561048157600080fd5b506103d260405180604001604052806005815260200164312e302e3160d81b81525081565b33600560006104bb608085016060860161122e565b6001600160a01b03908116825260208201929092526040016000205416146104f657604051630660dde160e01b815260040160405180910390fd5b8035461461052557604051633312c4bd60e11b8152813560048201524660248201526044015b60405180910390fd5b600060048161053a608085016060860161122e565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508082608001351461058e576040516308e7900f60e01b8152608083013560048201526024810182905260440161051c565b60a0820135158015906105a45750428260a00135105b156105c2576040516335a217b160e11b815260040160405180910390fd5b336000908152600660205260409020544211156105f257604051631e660ce760e21b815260040160405180910390fd5b6105fd81600161142c565b60046000610611608086016060870161122e565b6001600160a01b03166001600160a01b03168152602001908152602001600020819055506106a682602001602081019061064b919061122e565b61067061065b604086018661143f565b61066b608088016060890161122e565b610b52565b6040518060400160405280601881526020017714d858dc9854995b185e4b91195b1959d85d195910d85b1b60421b815250610b81565b507f8a35d03c38d83318b06a44c1b0010ba96f7ba3a2295032f534593ed4fd7618f9826040516106d691906114b5565b60405180910390a15050565b6001600160a01b0381811660009081526005602052604090205416331461071c57604051630660dde160e01b815260040160405180910390fd5b6001600160a01b038116600090815260056020908152604080832080546001600160a01b03191690553383526006909152812055341561078d576040516001600160a01b038216903480156108fc02916000818181858888f1935050505015801561078b573d6000803e3d6000fd5b505b50565b33600090815260056020908152604080832080546001600160a01b038681166001600160a01b03198316179092551680845260069092528220919091556107f77f00000000000000000000000000000000000000000000000000000000000000004261142c565b6001600160a01b038316600090815260066020526040902055341561078b576040516001600160a01b038316903480156108fc02916000818181858888f1935050505015801561084b573d6000803e3d6000fd5b505050565b6040518060a00160405280606a81526020016116d8606a91398051906020012081565b6000546001600160a01b0316331461089e5760405163321294a560e21b815260040160405180910390fd5b80156108b5576108af600183610c36565b5061078b565b61084b600183610c54565b6000546001600160a01b031633146108eb5760405163321294a560e21b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b610918600133610c69565b61093557604051630245d56b60e21b815260040160405180910390fd5b8235461461095f57604051633312c4bd60e11b81528335600482015246602482015260440161051c565b60036000610973608086016060870161122e565b6001600160a01b0316815260208101919091526040016000205460ff166109ad5760405163b2140b1960e01b815260040160405180910390fd5b60006004816109c2608087016060880161122e565b6001600160a01b03166001600160a01b0316815260200190815260200160002054905080846080013514610a16576040516308e7900f60e01b8152608085013560048201526024810182905260440161051c565b60a084013515801590610a2c5750428460a00135105b15610a4a576040516335a217b160e11b815260040160405180910390fd5b610a55848484610c8b565b50610a6181600161142c565b60046000610a75608088016060890161122e565b6001600160a01b03166001600160a01b0316815260200190815260200160002081905550610b03846020016020810190610aaf919061122e565b610acf610abf604088018861143f565b61066b60808a0160608b0161122e565b60405180604001604052806016815260200175536163726152656c61792e43616c6c4552433237373160501b815250610b81565b507f2624002b70e935afe786f89aca9bbbcfda114b4eed5cae7cb2f9394631822db984604051610b3391906114b5565b60405180910390a150505050565b6060610b4d6001610dad565b905090565b6060838383604051602001610b6993929190611570565b60405160208183030381529060405290509392505050565b60606000846001600160a01b031684604051610b9d9190611591565b6000604051808303816000865af19150503d8060008114610bda576040519150601f19603f3d011682016040523d82523d6000602084013e610bdf565b606091505b50925090508015610c24578151600003610c1f576001600160a01b0385163b610c1f5784836040516349aacb2160e11b815260040161051c9291906115ad565b610c2e565b610c2e8284610dc1565b509392505050565b6000610c4b836001600160a01b038416610e6b565b90505b92915050565b6000610c4b836001600160a01b038416610eba565b6001600160a01b03811660009081526001830160205260408120541515610c4b565b60007f0000000000000000000000000000000000000000000000000000000000000000610cb785610fad565b8051602091820120604051610ce393920161190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050600080610d3e8386868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b5090925090506000816003811115610d5857610d586115d1565b141580610d865750610d70608087016060880161122e565b6001600160a01b0316826001600160a01b031614155b15610da4576040516318eb9ab160e01b815260040160405180910390fd5b50509392505050565b60606000610dba836110c6565b9392505050565b60208251610dcf91906115e7565b600403610e4e5760208201516001600160e01b0319811662461bcd60e51b03610e31576044830192508183604051602001610e0b929190611609565b60408051601f198184030181529082905262461bcd60e51b825261051c91600401611320565b8082604051631c9f0c9160e31b815260040161051c929190611638565b8181604051634aea63e960e01b815260040161051c92919061165a565b6000818152600183016020526040812054610eb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c4e565b506000610c4e565b60008181526001830160205260408120548015610fa3576000610ede600183611688565b8554909150600090610ef290600190611688565b9050808214610f57576000866000018281548110610f1257610f1261169b565b9060005260206000200154905080876000018481548110610f3557610f3561169b565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f6857610f686116b1565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c4e565b6000915050610c4e565b60606040518060a00160405280606a81526020016116d8606a9139805160209182012090833590610fe4906040860190860161122e565b610ff1604086018661143f565b604051610fff9291906116c7565b604051908190039020611018608087016060880161122e565b6040805160208101969096528501939093526001600160a01b039182166060850152608084810191909152911660a0838101919091529084013560c083015283013560e0820152610100016040516020818303038152906040529050919050565b600080600083516041036110b35760208401516040850151606086015160001a6110a588828585611122565b9550955095505050506110bf565b50508151600091506002905b9250925092565b60608160000180548060200260200160405190810160405280929190818152602001828054801561111657602002820191906000526020600020905b815481526020019060010190808311611102575b50505050509050919050565b600080806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0384111561115357506000915060039050826111dd565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156111a7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111d3575060009250600191508290506111dd565b9250600091508190505b9450945094915050565b803580151581146111f757600080fd5b919050565b60006020828403121561120e57600080fd5b610c4b826111e7565b80356001600160a01b03811681146111f757600080fd5b60006020828403121561124057600080fd5b610c4b82611217565b600060c0828403121561125b57600080fd5b50919050565b60006020828403121561127357600080fd5b81356001600160401b0381111561128957600080fd5b61129584828501611249565b949350505050565b600080604083850312156112b057600080fd5b6112b983611217565b91506112c7602084016111e7565b90509250929050565b60005b838110156112eb5781810151838201526020016112d3565b50506000910152565b6000815180845261130c8160208601602086016112d0565b601f01601f19169290920160200192915050565b602081526000610c4b60208301846112f4565b60008060006040848603121561134857600080fd5b83356001600160401b038082111561135f57600080fd5b61136b87838801611249565b9450602086013591508082111561138157600080fd5b818601915086601f83011261139557600080fd5b8135818111156113a457600080fd5b8760208285010111156113b657600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561140a5783516001600160a01b0316835292840192918401916001016113e5565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c4e57610c4e611416565b6000808335601e1984360301811261145657600080fd5b8301803591506001600160401b0382111561147057600080fd5b60200191503681900382131561148557600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208082528235828201526001600160a01b03906114d4908401611217565b16604082015260006040830135601e198436030181126114f357600080fd5b83016020810190356001600160401b0381111561150f57600080fd5b80360382131561151e57600080fd5b60c0606085015261153360e08501828461148c565b91505061154260608501611217565b6001600160a01b038116608085015250608084013560a084015260a084013560c08401528091505092915050565b8284823760609190911b6001600160601b0319169101908152601401919050565b600082516115a38184602087016112d0565b9190910192915050565b6001600160a01b0383168152604060208201819052600090611295908301846112f4565b634e487b7160e01b600052602160045260246000fd5b60008261160457634e487b7160e01b600052601260045260246000fd5b500690565b6000835161161b8184602088016112d0565b83519083019061162f8183602088016112d0565b01949350505050565b63ffffffff60e01b8316815260406020820152600061129560408301846112f4565b60408152600061166d60408301856112f4565b828103602084015261167f81856112f4565b95945050505050565b81810381811115610c4e57610c4e611416565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b818382376000910190815291905056fe43616c6c455243323737312875696e7432353620636861696e49642c61646472657373207461726765742c627974657320646174612c6164647265737320757365722c75696e7432353620757365724e6f6e63652c75696e743235362075736572446561646c696e6529a2646970667358221220687b2bade5f00e72a8410e9c92268a9d628669844d27e8d79ab438d21cc9a9ed64736f6c63430008170033454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429000000000000000000000000a88fdfbdcd728903c2f85f973f7defedcd517530

Deployed Bytecode

0x6080604052600436106100f85760003560e01c8063748e002411610090578063748e0024146102f95780637c9227a614610347578063860639ec1461035c5780638da5cb5b1461037c578063a3f4df7e1461039c578063a6f9dae1146103df578063ad96569a146103ff578063c54191061461041f578063f7b13b4114610441578063ffa1ad741461047557600080fd5b806309b67f8e14610104578063112710a914610141578063158731ce146101815780631959a002146101a15780632b3d167e146102325780633644e515146102455780633e5beab9146102795780635c19a95c146102b95780635da2fd42146102cc57600080fd5b366100ff57005b600080fd5b34801561011057600080fd5b5061013f61011f3660046111fc565b336000908152600360205260409020805460ff1916911515919091179055565b005b34801561014d57600080fd5b5061016e61015c36600461122e565b60066020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561018d57600080fd5b5061013f61019c366004611261565b6104a6565b3480156101ad57600080fd5b506102036101bc36600461122e565b6001600160a01b038082166000908152600560209081526040808320546004835281842054600384528285205491909516808552600690935292205460ff90921693509193565b604051610178949392919093845291151560208401526001600160a01b03166040830152606082015260800190565b61013f61024036600461122e565b6106e2565b34801561025157600080fd5b5061016e7fdad96cc137db9e7642852be44d11d71b9a4d0a1567829c53eec1c95d6e509eb781565b34801561028557600080fd5b506102a961029436600461122e565b60036020526000908152604090205460ff1681565b6040519015158152602001610178565b61013f6102c736600461122e565b610790565b3480156102d857600080fd5b5061016e6102e736600461122e565b60046020526000908152604090205481565b34801561030557600080fd5b5061032f61031436600461122e565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610178565b34801561035357600080fd5b5061016e610850565b34801561036857600080fd5b5061013f61037736600461129d565b610873565b34801561038857600080fd5b5060005461032f906001600160a01b031681565b3480156103a857600080fd5b506103d26040518060400160405280600a815260200169536163726152656c617960b01b81525081565b6040516101789190611320565b3480156103eb57600080fd5b5061013f6103fa36600461122e565b6108c0565b34801561040b57600080fd5b5061013f61041a366004611333565b61090d565b34801561042b57600080fd5b50610434610b41565b60405161017891906113c9565b34801561044d57600080fd5b5061016e7f0000000000000000000000000000000000000000000000000000000000093a8081565b34801561048157600080fd5b506103d260405180604001604052806005815260200164312e302e3160d81b81525081565b33600560006104bb608085016060860161122e565b6001600160a01b03908116825260208201929092526040016000205416146104f657604051630660dde160e01b815260040160405180910390fd5b8035461461052557604051633312c4bd60e11b8152813560048201524660248201526044015b60405180910390fd5b600060048161053a608085016060860161122e565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508082608001351461058e576040516308e7900f60e01b8152608083013560048201526024810182905260440161051c565b60a0820135158015906105a45750428260a00135105b156105c2576040516335a217b160e11b815260040160405180910390fd5b336000908152600660205260409020544211156105f257604051631e660ce760e21b815260040160405180910390fd5b6105fd81600161142c565b60046000610611608086016060870161122e565b6001600160a01b03166001600160a01b03168152602001908152602001600020819055506106a682602001602081019061064b919061122e565b61067061065b604086018661143f565b61066b608088016060890161122e565b610b52565b6040518060400160405280601881526020017714d858dc9854995b185e4b91195b1959d85d195910d85b1b60421b815250610b81565b507f8a35d03c38d83318b06a44c1b0010ba96f7ba3a2295032f534593ed4fd7618f9826040516106d691906114b5565b60405180910390a15050565b6001600160a01b0381811660009081526005602052604090205416331461071c57604051630660dde160e01b815260040160405180910390fd5b6001600160a01b038116600090815260056020908152604080832080546001600160a01b03191690553383526006909152812055341561078d576040516001600160a01b038216903480156108fc02916000818181858888f1935050505015801561078b573d6000803e3d6000fd5b505b50565b33600090815260056020908152604080832080546001600160a01b038681166001600160a01b03198316179092551680845260069092528220919091556107f77f0000000000000000000000000000000000000000000000000000000000093a804261142c565b6001600160a01b038316600090815260066020526040902055341561078b576040516001600160a01b038316903480156108fc02916000818181858888f1935050505015801561084b573d6000803e3d6000fd5b505050565b6040518060a00160405280606a81526020016116d8606a91398051906020012081565b6000546001600160a01b0316331461089e5760405163321294a560e21b815260040160405180910390fd5b80156108b5576108af600183610c36565b5061078b565b61084b600183610c54565b6000546001600160a01b031633146108eb5760405163321294a560e21b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b610918600133610c69565b61093557604051630245d56b60e21b815260040160405180910390fd5b8235461461095f57604051633312c4bd60e11b81528335600482015246602482015260440161051c565b60036000610973608086016060870161122e565b6001600160a01b0316815260208101919091526040016000205460ff166109ad5760405163b2140b1960e01b815260040160405180910390fd5b60006004816109c2608087016060880161122e565b6001600160a01b03166001600160a01b0316815260200190815260200160002054905080846080013514610a16576040516308e7900f60e01b8152608085013560048201526024810182905260440161051c565b60a084013515801590610a2c5750428460a00135105b15610a4a576040516335a217b160e11b815260040160405180910390fd5b610a55848484610c8b565b50610a6181600161142c565b60046000610a75608088016060890161122e565b6001600160a01b03166001600160a01b0316815260200190815260200160002081905550610b03846020016020810190610aaf919061122e565b610acf610abf604088018861143f565b61066b60808a0160608b0161122e565b60405180604001604052806016815260200175536163726152656c61792e43616c6c4552433237373160501b815250610b81565b507f2624002b70e935afe786f89aca9bbbcfda114b4eed5cae7cb2f9394631822db984604051610b3391906114b5565b60405180910390a150505050565b6060610b4d6001610dad565b905090565b6060838383604051602001610b6993929190611570565b60405160208183030381529060405290509392505050565b60606000846001600160a01b031684604051610b9d9190611591565b6000604051808303816000865af19150503d8060008114610bda576040519150601f19603f3d011682016040523d82523d6000602084013e610bdf565b606091505b50925090508015610c24578151600003610c1f576001600160a01b0385163b610c1f5784836040516349aacb2160e11b815260040161051c9291906115ad565b610c2e565b610c2e8284610dc1565b509392505050565b6000610c4b836001600160a01b038416610e6b565b90505b92915050565b6000610c4b836001600160a01b038416610eba565b6001600160a01b03811660009081526001830160205260408120541515610c4b565b60007fdad96cc137db9e7642852be44d11d71b9a4d0a1567829c53eec1c95d6e509eb7610cb785610fad565b8051602091820120604051610ce393920161190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050600080610d3e8386868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061107992505050565b5090925090506000816003811115610d5857610d586115d1565b141580610d865750610d70608087016060880161122e565b6001600160a01b0316826001600160a01b031614155b15610da4576040516318eb9ab160e01b815260040160405180910390fd5b50509392505050565b60606000610dba836110c6565b9392505050565b60208251610dcf91906115e7565b600403610e4e5760208201516001600160e01b0319811662461bcd60e51b03610e31576044830192508183604051602001610e0b929190611609565b60408051601f198184030181529082905262461bcd60e51b825261051c91600401611320565b8082604051631c9f0c9160e31b815260040161051c929190611638565b8181604051634aea63e960e01b815260040161051c92919061165a565b6000818152600183016020526040812054610eb257508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610c4e565b506000610c4e565b60008181526001830160205260408120548015610fa3576000610ede600183611688565b8554909150600090610ef290600190611688565b9050808214610f57576000866000018281548110610f1257610f1261169b565b9060005260206000200154905080876000018481548110610f3557610f3561169b565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f6857610f686116b1565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610c4e565b6000915050610c4e565b60606040518060a00160405280606a81526020016116d8606a9139805160209182012090833590610fe4906040860190860161122e565b610ff1604086018661143f565b604051610fff9291906116c7565b604051908190039020611018608087016060880161122e565b6040805160208101969096528501939093526001600160a01b039182166060850152608084810191909152911660a0838101919091529084013560c083015283013560e0820152610100016040516020818303038152906040529050919050565b600080600083516041036110b35760208401516040850151606086015160001a6110a588828585611122565b9550955095505050506110bf565b50508151600091506002905b9250925092565b60608160000180548060200260200160405190810160405280929190818152602001828054801561111657602002820191906000526020600020905b815481526020019060010190808311611102575b50505050509050919050565b600080806fa2a8918ca85bafe22016d0b997e4df60600160ff1b0384111561115357506000915060039050826111dd565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156111a7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111d3575060009250600191508290506111dd565b9250600091508190505b9450945094915050565b803580151581146111f757600080fd5b919050565b60006020828403121561120e57600080fd5b610c4b826111e7565b80356001600160a01b03811681146111f757600080fd5b60006020828403121561124057600080fd5b610c4b82611217565b600060c0828403121561125b57600080fd5b50919050565b60006020828403121561127357600080fd5b81356001600160401b0381111561128957600080fd5b61129584828501611249565b949350505050565b600080604083850312156112b057600080fd5b6112b983611217565b91506112c7602084016111e7565b90509250929050565b60005b838110156112eb5781810151838201526020016112d3565b50506000910152565b6000815180845261130c8160208601602086016112d0565b601f01601f19169290920160200192915050565b602081526000610c4b60208301846112f4565b60008060006040848603121561134857600080fd5b83356001600160401b038082111561135f57600080fd5b61136b87838801611249565b9450602086013591508082111561138157600080fd5b818601915086601f83011261139557600080fd5b8135818111156113a457600080fd5b8760208285010111156113b657600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b8181101561140a5783516001600160a01b0316835292840192918401916001016113e5565b50909695505050505050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610c4e57610c4e611416565b6000808335601e1984360301811261145657600080fd5b8301803591506001600160401b0382111561147057600080fd5b60200191503681900382131561148557600080fd5b9250929050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208082528235828201526001600160a01b03906114d4908401611217565b16604082015260006040830135601e198436030181126114f357600080fd5b83016020810190356001600160401b0381111561150f57600080fd5b80360382131561151e57600080fd5b60c0606085015261153360e08501828461148c565b91505061154260608501611217565b6001600160a01b038116608085015250608084013560a084015260a084013560c08401528091505092915050565b8284823760609190911b6001600160601b0319169101908152601401919050565b600082516115a38184602087016112d0565b9190910192915050565b6001600160a01b0383168152604060208201819052600090611295908301846112f4565b634e487b7160e01b600052602160045260246000fd5b60008261160457634e487b7160e01b600052601260045260246000fd5b500690565b6000835161161b8184602088016112d0565b83519083019061162f8183602088016112d0565b01949350505050565b63ffffffff60e01b8316815260406020820152600061129560408301846112f4565b60408152600061166d60408301856112f4565b828103602084015261167f81856112f4565b95945050505050565b81810381811115610c4e57610c4e611416565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b818382376000910190815291905056fe43616c6c455243323737312875696e7432353620636861696e49642c61646472657373207461726765742c627974657320646174612c6164647265737320757365722c75696e7432353620757365724e6f6e63652c75696e743235362075736572446561646c696e6529a2646970667358221220687b2bade5f00e72a8410e9c92268a9d628669844d27e8d79ab438d21cc9a9ed64736f6c63430008170033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000a88fdfbdcd728903c2f85f973f7defedcd517530

-----Decoded View---------------
Arg [0] : owner_ (address): 0xA88FDfbdcD728903C2f85F973F7deFEdcD517530

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a88fdfbdcd728903c2f85f973f7defedcd517530


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.