ETH Price: $2,951.74 (-0.14%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
0x60a06040220656052025-03-17 9:06:11313 days ago1742202371  Contract Creation0 ETH
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
VotingStrategy

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 200 runs

Other Settings:
shanghai EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {BaseVotingStrategy, IBaseVotingStrategy} from '../BaseVotingStrategy.sol';
import {StateProofVerifier} from './libs/StateProofVerifier.sol';
import {IVotingStrategy, IDataWarehouse} from './interfaces/IVotingStrategy.sol';
import {Errors} from '../libraries/Errors.sol';
import {SlotUtils} from '../libraries/SlotUtils.sol';

enum DelegationMode {
  NO_DELEGATION,
  VOTING_DELEGATED,
  PROPOSITION_DELEGATED,
  FULL_POWER_DELEGATED
}

/**
 * @title VotingStrategy
 * @author BGD Labs
 * @notice This contracts overrides the base voting strategy to return specific assets used on the strategy.
 * @dev These tokens will be used to get the voting power for proposal voting
 */
contract VotingStrategy is BaseVotingStrategy, IVotingStrategy {
  /// @inheritdoc IVotingStrategy
  IDataWarehouse public immutable DATA_WAREHOUSE;

  /// @inheritdoc IVotingStrategy
  uint256 public constant STK_AAVE_SLASHING_EXCHANGE_RATE_PRECISION = 1e18;

  /// @inheritdoc IVotingStrategy
  uint256 public constant STK_AAVE_SLASHING_EXCHANGE_RATE_SLOT = 81;

  /// @inheritdoc IVotingStrategy
  uint256 public constant POWER_SCALE_FACTOR = 1e10;

  /**
   * @param dataWarehouse address of the DataWarehouse contract used to store roots
   */
  constructor(address dataWarehouse) BaseVotingStrategy() {
    require(dataWarehouse != address(0), Errors.INVALID_DATA_WAREHOUSE);
    DATA_WAREHOUSE = IDataWarehouse(dataWarehouse);
  }

  /// @inheritdoc IVotingStrategy
  function getVotingPower(
    address asset,
    uint128 storageSlot,
    uint256 power,
    bytes32 blockHash
  ) public view returns (uint256) {
    uint256 votingPower;

    if (asset == STK_AAVE()) {
      if (storageSlot == BASE_BALANCE_SLOT) {
        uint256 slashingExchangeRateSlotValue = DATA_WAREHOUSE
          .getRegisteredSlot(
            blockHash,
            asset,
            bytes32(STK_AAVE_SLASHING_EXCHANGE_RATE_SLOT)
          );

        // casting to uint216 as exchange rate is saved in first 27 bytes of slot
        uint256 slashingExchangeRate = uint256(
          uint216(slashingExchangeRateSlotValue)
        );

        // Shifting to take into account how stk aave token balances is structured
        votingPower = uint72(power >> (104 + 72)) * POWER_SCALE_FACTOR; // stored delegated voting power was scaled down by POWER_SCALE_FACTOR

        DelegationMode delegationMode = DelegationMode(
          uint8(power >> (104 + 72 + 72))
        );

        if (
          delegationMode != DelegationMode.VOTING_DELEGATED &&
          delegationMode != DelegationMode.FULL_POWER_DELEGATED
        ) {
          // adding user token balance if is not delegating his voting power
          votingPower += uint104(power);
        }
        // applying slashing exchange rate
        votingPower =
          (votingPower * STK_AAVE_SLASHING_EXCHANGE_RATE_PRECISION) /
          slashingExchangeRate;
      }
    } else if (asset == AAVE()) {
      if (storageSlot == BASE_BALANCE_SLOT) {
        // Shifting to take into account how aave token v3 balances is structured
        votingPower = uint72(power >> (104 + 72)) * POWER_SCALE_FACTOR; // stored delegated voting power was scaled down by POWER_SCALE_FACTOR

        DelegationMode delegationMode = DelegationMode(
          uint8(power >> (104 + 72 + 72))
        );

        if (
          delegationMode != DelegationMode.VOTING_DELEGATED &&
          delegationMode != DelegationMode.FULL_POWER_DELEGATED
        ) {
          votingPower += uint104(power); // adding user token balance if is not delegating his voting power
        }
      }
    } else if (asset == A_AAVE()) {
      if (storageSlot == A_AAVE_DELEGATED_STATE_SLOT) {
        // Shifting to take into account how aave a token delegation balances is structured
        votingPower = uint72(power >> 72) * POWER_SCALE_FACTOR; // stored delegated voting power was scaled down by POWER_SCALE_FACTOR
      } else if (storageSlot == A_AAVE_BASE_BALANCE_SLOT) {
        // need to get first 120 as its where balance is stored
        uint256 powerBalance = uint256(uint120(power));

        // next uint8 is for delegationMode
        DelegationMode delegationMode = DelegationMode(uint8(power >> (120)));
        if (
          delegationMode != DelegationMode.VOTING_DELEGATED &&
          delegationMode != DelegationMode.FULL_POWER_DELEGATED
        ) {
          votingPower += powerBalance; // adding user token balance if is not delegating his voting power
        }
      }
    }

    return votingPower;
  }

  // @inheritdoc IVotingStrategy
  function hasRequiredRoots(bytes32 blockHash) external view {
    require(
      DATA_WAREHOUSE.getStorageRoots(AAVE(), blockHash) != bytes32(0),
      Errors.MISSING_AAVE_ROOTS
    );
    require(
      DATA_WAREHOUSE.getStorageRoots(STK_AAVE(), blockHash) != bytes32(0),
      Errors.MISSING_STK_AAVE_ROOTS
    );
    require(
      DATA_WAREHOUSE.getStorageRoots(A_AAVE(), blockHash) != bytes32(0),
      Errors.MISSING_A_AAVE_ROOTS
    );
    require(
      DATA_WAREHOUSE.getRegisteredSlot(
        blockHash,
        STK_AAVE(),
        bytes32(STK_AAVE_SLASHING_EXCHANGE_RATE_SLOT)
      ) > 0,
      Errors.MISSING_STK_AAVE_SLASHING_EXCHANGE_RATE
    );
  }
}

// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {IBaseVotingStrategy} from '../interfaces/IBaseVotingStrategy.sol';
import {Errors} from './libraries/Errors.sol';

//import {AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol';

/**
 * @title BaseVotingStrategy
 * @author BGD Labs
 * @notice This contract contains the base logic of a voting strategy, being on governance chain or voting machine chain.
 */
abstract contract BaseVotingStrategy is IBaseVotingStrategy {
  function AAVE() public pure virtual returns (address) {
    return 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9;
  }

  function STK_AAVE() public pure virtual returns (address) {
    return 0x4da27a545c0c5B758a6BA100e3a049001de870f5;
  }

  function A_AAVE() public pure virtual returns (address) {
    return 0xA700b4eB416Be35b2911fd5Dee80678ff64fF6C9;
  }

  uint128 public constant BASE_BALANCE_SLOT = 0;
  uint128 public constant A_AAVE_BASE_BALANCE_SLOT = 52;
  uint128 public constant A_AAVE_DELEGATED_STATE_SLOT = 64;

  /// @dev on the constructor we get all the voting assets and emit the different asset configurations
  constructor() {
    address[] memory votingAssetList = getVotingAssetList();

    // Check that voting strategy at least has one asset
    require(votingAssetList.length != 0, Errors.NO_VOTING_ASSETS);

    for (uint256 i = 0; i < votingAssetList.length; i++) {
      for (uint256 j = i + 1; j < votingAssetList.length; j++) {
        require(
          votingAssetList[i] != votingAssetList[j],
          Errors.REPEATED_STRATEGY_ASSET
        );
      }
      VotingAssetConfig memory votingAssetConfig = getVotingAssetConfig(
        votingAssetList[i]
      );

      require(
        votingAssetConfig.storageSlots.length > 0,
        Errors.EMPTY_ASSET_STORAGE_SLOTS
      );

      for (uint256 k = 0; k < votingAssetConfig.storageSlots.length; k++) {
        for (
          uint256 l = k + 1;
          l < votingAssetConfig.storageSlots.length;
          l++
        ) {
          require(
            votingAssetConfig.storageSlots[k] !=
              votingAssetConfig.storageSlots[l],
            Errors.REPEATED_STRATEGY_ASSET_SLOT
          );
        }
      }

      emit VotingAssetAdd(votingAssetList[i], votingAssetConfig.storageSlots);
    }
  }

  /// @inheritdoc IBaseVotingStrategy
  function getVotingAssetList() public pure returns (address[] memory) {
    address[] memory votingAssets = new address[](3);

    votingAssets[0] = AAVE();
    votingAssets[1] = STK_AAVE();
    votingAssets[2] = A_AAVE();

    return votingAssets;
  }

  /// @inheritdoc IBaseVotingStrategy
  function getVotingAssetConfig(
    address asset
  ) public pure returns (VotingAssetConfig memory) {
    VotingAssetConfig memory votingAssetConfig;

    if (asset == AAVE() || asset == STK_AAVE()) {
      votingAssetConfig.storageSlots = new uint128[](1);
      votingAssetConfig.storageSlots[0] = BASE_BALANCE_SLOT;
    } else if (asset == A_AAVE()) {
      votingAssetConfig.storageSlots = new uint128[](2);
      votingAssetConfig.storageSlots[0] = A_AAVE_BASE_BALANCE_SLOT;
      votingAssetConfig.storageSlots[1] = A_AAVE_DELEGATED_STATE_SLOT;
    } else {
      return votingAssetConfig;
    }

    return votingAssetConfig;
  }

  /// @inheritdoc IBaseVotingStrategy
  function isTokenSlotAccepted(
    address token,
    uint128 slot
  ) external pure returns (bool) {
    VotingAssetConfig memory votingAssetConfig = getVotingAssetConfig(token);
    for (uint256 i = 0; i < votingAssetConfig.storageSlots.length; i++) {
      if (slot == votingAssetConfig.storageSlots[i]) {
        return true;
      }
    }
    return false;
  }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {RLPReader} from './RLPReader.sol';
import {MerklePatriciaProofVerifier} from './MerklePatriciaProofVerifier.sol';

/**
 * @title A helper library for verification of Merkle Patricia account and state proofs.
 */
library StateProofVerifier {
  using RLPReader for RLPReader.RLPItem;
  using RLPReader for bytes;

  uint256 constant HEADER_STATE_ROOT_INDEX = 3;
  uint256 constant HEADER_NUMBER_INDEX = 8;
  uint256 constant HEADER_TIMESTAMP_INDEX = 11;

  struct BlockHeader {
    bytes32 hash;
    bytes32 stateRootHash;
    uint256 number;
    uint256 timestamp;
  }

  struct Account {
    bool exists;
    uint256 nonce;
    uint256 balance;
    bytes32 storageRoot;
    bytes32 codeHash;
  }

  struct SlotValue {
    bool exists;
    uint256 value;
  }

  /**
   * @notice Parses block header and verifies its presence onchain within the latest 256 blocks.
   * @param _headerRlpBytes RLP-encoded block header.
   */
  function verifyBlockHeader(
    bytes memory _headerRlpBytes,
    bytes32 _blockHash
  ) internal pure returns (BlockHeader memory) {
    BlockHeader memory header = parseBlockHeader(_headerRlpBytes);
    require(header.hash == _blockHash, 'blockhash mismatch');
    return header;
  }

  /**
   * @notice Parses RLP-encoded block header.
   * @param _headerRlpBytes RLP-encoded block header.
   */
  function parseBlockHeader(
    bytes memory _headerRlpBytes
  ) internal pure returns (BlockHeader memory) {
    BlockHeader memory result;
    RLPReader.RLPItem[] memory headerFields = _headerRlpBytes
      .toRlpItem()
      .toList();

    require(headerFields.length > HEADER_TIMESTAMP_INDEX);

    result.stateRootHash = bytes32(
      headerFields[HEADER_STATE_ROOT_INDEX].toUint()
    );
    result.number = headerFields[HEADER_NUMBER_INDEX].toUint();
    result.timestamp = headerFields[HEADER_TIMESTAMP_INDEX].toUint();
    result.hash = keccak256(_headerRlpBytes);

    return result;
  }

  /**
   * @notice Verifies Merkle Patricia proof of an account and extracts the account fields.
   *
   * @param _addressHash Keccak256 hash of the address corresponding to the account.
   * @param _stateRootHash MPT root hash of the Ethereum state trie.
   */
  function extractAccountFromProof(
    bytes32 _addressHash, // keccak256(abi.encodePacked(address))
    bytes32 _stateRootHash,
    RLPReader.RLPItem[] memory _proof
  ) internal pure returns (Account memory) {
    bytes memory acctRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
      _stateRootHash,
      abi.encodePacked(_addressHash),
      _proof
    );
    Account memory account;

    if (acctRlpBytes.length == 0) {
      return account;
    }

    RLPReader.RLPItem[] memory acctFields = acctRlpBytes.toRlpItem().toList();
    require(acctFields.length == 4);

    account.exists = true;
    account.nonce = acctFields[0].toUint();
    account.balance = acctFields[1].toUint();
    account.storageRoot = bytes32(acctFields[2].toUint());
    account.codeHash = bytes32(acctFields[3].toUint());

    return account;
  }

  /**
   * @notice Verifies Merkle Patricia proof of a slot and extracts the slot's value.
   *
   * @param _slotHash Keccak256 hash of the slot position.
   * @param _storageRootHash MPT root hash of the account's storage trie.
   */
  function extractSlotValueFromProof(
    bytes32 _slotHash,
    bytes32 _storageRootHash,
    RLPReader.RLPItem[] memory _proof
  ) internal pure returns (SlotValue memory) {
    bytes memory valueRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
      _storageRootHash,
      abi.encodePacked(_slotHash),
      _proof
    );

    SlotValue memory value;

    if (valueRlpBytes.length != 0) {
      value.exists = true;
      value.value = valueRlpBytes.toRlpItem().toUint();
    }

    return value;
  }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IDataWarehouse} from './IDataWarehouse.sol';

/**
 * @title IVotingStrategy
 * @author BGD Labs
 * @notice interface containing the methods definitions of the VotingStrategy contract
 */
interface IVotingStrategy {
  /**
   * @notice method to get the DataWarehouse contract
   * @return DataWarehouse contract
   */
  function DATA_WAREHOUSE() external view returns (IDataWarehouse);

  /**
   * @notice method to get the exchange rate precision. Taken from stkTokenV3 contract
   * @return exchange rate precission
   */
  function STK_AAVE_SLASHING_EXCHANGE_RATE_PRECISION()
    external
    view
    returns (uint256);

  /**
   * @notice method to get the slot of the stkAave exchange rate in the stkAave contract
   * @return stkAave exchange rate slot
   */
  function STK_AAVE_SLASHING_EXCHANGE_RATE_SLOT()
    external
    view
    returns (uint256);

  /**
   * @notice method to get the power scale factor of the delegated balances
   * @return power scale factor
   */
  function POWER_SCALE_FACTOR() external view returns (uint256);

  /**
   * @notice method to get the power of an asset
   * @param asset address of the token to get the power
   * @param storageSlot storage position of the balance mapping
   * @param power balance of a determined asset to be used for the vote
   * @param blockHash block hash of when we want to get the power. Optional parameter
   * @return voting power of the specified asset
   */
  function getVotingPower(
    address asset,
    uint128 storageSlot,
    uint256 power,
    bytes32 blockHash
  ) external view returns (uint256);

  /**
   * @notice method to check that the roots for all the tokens in the voting strategy have been registered. Including
             the registry of the stkAave exchange rate slot
   * @param blockHash hash of the block from where the roots have been registered.
   */
  function hasRequiredRoots(bytes32 blockHash) external view;
}

File 5 of 10 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Errors library
 * @author BGD Labs
 * @notice Defines the error messages emitted by the different contracts of the Aave Governance V3
 */
library Errors {
  string public constant VOTING_PORTALS_COUNT_NOT_0 = '1'; // to be able to rescue voting portals count must be 0
  string public constant AT_LEAST_ONE_PAYLOAD = '2'; // to create a proposal, it must have at least one payload
  string public constant VOTING_PORTAL_NOT_APPROVED = '3'; // the voting portal used to vote on proposal must be approved
  string public constant PROPOSITION_POWER_IS_TOO_LOW = '4'; // proposition power of proposal creator must be equal or higher than the specified threshold for the access level
  string public constant PROPOSAL_NOT_IN_CREATED_STATE = '5'; // proposal should be in the CREATED state
  string public constant PROPOSAL_NOT_IN_ACTIVE_STATE = '6'; // proposal must be in an ACTIVE state
  string public constant PROPOSAL_NOT_IN_QUEUED_STATE = '7'; // proposal must be in a QUEUED state
  string public constant VOTING_START_COOLDOWN_PERIOD_NOT_PASSED = '8'; // to activate a proposal vote, the cool down delay must pass
  string public constant CALLER_NOT_A_VALID_VOTING_PORTAL = '9'; // only an allowed voting portal can queue a proposal
  string public constant QUEUE_COOLDOWN_PERIOD_NOT_PASSED = '10'; // to execute a proposal a cooldown delay must pass
  string public constant PROPOSAL_NOT_IN_THE_CORRECT_STATE = '11'; // proposal must be created but not executed yet to be able to be canceled
  string public constant CALLER_NOT_GOVERNANCE = '12'; // caller must be governance
  string public constant VOTER_ALREADY_VOTED_ON_PROPOSAL = '13'; // voter can only vote once per proposal using voting portal
  string public constant WRONG_MESSAGE_ORIGIN = '14'; // received message must come from registered source address, chain id, CrossChainController
  string public constant NO_VOTING_ASSETS = '15'; // Strategy must have voting assets
  string public constant PROPOSAL_VOTE_ALREADY_CREATED = '16'; // vote on proposal can only be created once
  string public constant INVALID_SIGNATURE = '17'; // submitted signature is not valid
  string public constant PROPOSAL_VOTE_NOT_FINISHED = '18'; // proposal vote must be finished
  string public constant PROPOSAL_VOTE_NOT_IN_ACTIVE_STATE = '19'; // proposal vote must be in active state
  string public constant PROPOSAL_VOTE_ALREADY_EXISTS = '20'; // proposal vote already exists
  string public constant VOTE_ONCE_FOR_ASSET = '21'; // an asset can only be used once per vote
  string public constant USER_BALANCE_DOES_NOT_EXISTS = '22'; // to vote an user must have balance in the token the user is voting with
  string public constant USER_VOTING_BALANCE_IS_ZERO = '23'; // to vote an user must have some balance between all the tokens selected for voting
  string public constant MISSING_AAVE_ROOTS = '24'; // must have AAVE roots registered to use strategy
  string public constant MISSING_STK_AAVE_ROOTS = '25'; // must have stkAAVE roots registered to use strategy
  string public constant MISSING_STK_AAVE_SLASHING_EXCHANGE_RATE = '26'; // must have stkAAVE slashing exchange rate registered to use strategy
  string public constant UNPROCESSED_STORAGE_ROOT = '27'; // root must be registered beforehand
  string public constant NOT_ENOUGH_MSG_VALUE = '28'; // method was not called with enough value to execute the call
  string public constant FAILED_ACTION_EXECUTION = '29'; // action failed to execute
  string public constant SHOULD_BE_AT_LEAST_ONE_EXECUTOR = '30'; // at least one executor is needed
  string public constant INVALID_EMPTY_TARGETS = '31'; // target of the payload execution must not be empty
  string public constant EXECUTOR_WAS_NOT_SPECIFIED_FOR_REQUESTED_ACCESS_LEVEL =
    '32'; // payload executor must be registered for the specified payload access level
  string public constant PAYLOAD_NOT_IN_QUEUED_STATE = '33'; // payload must be en the queued state
  string public constant TIMELOCK_NOT_FINISHED = '34'; // delay has not passed before execution can be called
  string public constant PAYLOAD_NOT_IN_THE_CORRECT_STATE = '35'; // payload must be created but not executed yet to be able to be canceled
  string public constant PAYLOAD_NOT_IN_CREATED_STATE = '36'; // payload must be in the created state
  string public constant MISSING_A_AAVE_ROOTS = '37'; // must have aAAVE roots registered to use strategy
  string public constant MISSING_PROPOSAL_BLOCK_HASH = '38'; // block hash for this proposal was not bridged before
  string public constant PROPOSAL_VOTE_CONFIGURATION_ALREADY_BRIDGED = '39'; // configuration for this proposal bridged already
  string public constant INVALID_VOTING_PORTAL_ADDRESS = '40'; // voting portal address can't be 0x0
  string public constant INVALID_POWER_STRATEGY = '41'; // 0x0 is not valid as the power strategy
  string public constant INVALID_EXECUTOR_ADDRESS = '42'; // executor address can't be 0x0
  string public constant EXECUTOR_ALREADY_SET_IN_DIFFERENT_LEVEL = '43'; // executor address already being used as executor of a different level
  string public constant INVALID_VOTING_DURATION = '44'; // voting duration can not be bigger than the time it takes to execute a proposal
  string public constant VOTING_DURATION_NOT_PASSED = '45'; // at least votingDuration should have passed since voting started for a proposal to be queued
  string public constant INVALID_PROPOSAL_ACCESS_LEVEL = '46'; // the bridged proposal access level does not correspond with the maximum access level required by the payload
  string public constant PAYLOAD_NOT_CREATED_BEFORE_PROPOSAL = '47'; // payload must be created before proposal
  string public constant INVALID_CROSS_CHAIN_CONTROLLER_ADDRESS = '48';
  string public constant INVALID_MESSAGE_ORIGINATOR_ADDRESS = '49';
  string public constant INVALID_ORIGIN_CHAIN_ID = '50';
  string public constant INVALID_ACTION_TARGET = '51';
  string public constant INVALID_ACTION_ACCESS_LEVEL = '52';
  string public constant INVALID_EXECUTOR_ACCESS_LEVEL = '53';
  string public constant INVALID_VOTING_PORTAL_CROSS_CHAIN_CONTROLLER = '54';
  string public constant INVALID_VOTING_PORTAL_VOTING_MACHINE = '55';
  string public constant INVALID_VOTING_PORTAL_GOVERNANCE = '56';
  string public constant INVALID_VOTING_MACHINE_CHAIN_ID = '57';
  string public constant G_INVALID_CROSS_CHAIN_CONTROLLER_ADDRESS = '58';
  string public constant G_INVALID_IPFS_HASH = '59';
  string public constant G_INVALID_PAYLOAD_ACCESS_LEVEL = '60';
  string public constant G_INVALID_PAYLOADS_CONTROLLER = '61';
  string public constant G_INVALID_PAYLOAD_CHAIN = '62';
  string public constant POWER_STRATEGY_HAS_NO_TOKENS = '63'; // power strategy should at least have
  string public constant INVALID_VOTING_CONFIG_ACCESS_LEVEL = '64';
  string public constant VOTING_DURATION_TOO_SMALL = '65';
  string public constant NO_BRIDGED_VOTING_ASSETS = '66';
  string public constant INVALID_VOTER = '67';
  string public constant INVALID_DATA_WAREHOUSE = '68';
  string public constant INVALID_VOTING_MACHINE_CROSS_CHAIN_CONTROLLER = '69';
  string public constant INVALID_L1_VOTING_PORTAL = '70';
  string public constant INVALID_VOTING_PORTAL_CHAIN_ID = '71';
  string public constant INVALID_VOTING_STRATEGY = '72';
  string public constant INVALID_VOTE_CONFIGURATION_BLOCKHASH = '73';
  string public constant INVALID_VOTE_CONFIGURATION_VOTING_DURATION = '74';
  string public constant INVALID_GAS_LIMIT = '75';
  string public constant INVALID_VOTING_CONFIGS = '76'; // a lvl2 voting configuration must be sent to initializer
  string public constant INVALID_EXECUTOR_DELAY = '77';
  string public constant REPEATED_STRATEGY_ASSET = '78';
  string public constant EMPTY_ASSET_STORAGE_SLOTS = '79';
  string public constant REPEATED_STRATEGY_ASSET_SLOT = '80';
  string public constant INVALID_EXECUTION_TARGET = '81';
  string public constant MISSING_VOTING_CONFIGURATIONS = '82'; // voting configurations for lvl1 and lvl2 must be included on initialization
  string public constant INVALID_PROPOSITION_POWER = '83';
  string public constant INVALID_YES_THRESHOLD = '84';
  string public constant INVALID_YES_NO_DIFFERENTIAL = '85';
  string public constant ETH_TRANSFER_FAILED = '86';
  string public constant INVALID_INITIAL_VOTING_CONFIGS = '87'; // initial voting configurations can not be of the same level
  string public constant INVALID_VOTING_PORTAL_ADDRESS_IN_VOTING_MACHINE = '88';
  string public constant INVALID_VOTING_PORTAL_OWNER = '89';
  string public constant CANCELLATION_FEE_REDEEM_FAILED = '90'; // cancellation fee was not able to be redeemed
  string public constant INVALID_CANCELLATION_FEE_COLLECTOR = '91'; // collector can not be address 0
  string public constant INVALID_CANCELLATION_FEE_SENT = '92'; // cancellation fee sent does not match the needed amount
  string public constant CANCELLATION_FEE_ALREADY_REDEEMED = '93'; // cancellation fee already redeemed
  string public constant INVALID_STATE_TO_REDEEM_CANCELLATION_FEE = '94'; // proposal state is not a valid state to redeem cancellation fee
  string public constant MISSING_REPRESENTATION_ROOTS = '95'; // to represent a voter the representation roots need to be registered
  string public constant CALLER_IS_NOT_VOTER_REPRESENTATIVE = '96'; // to represent a voter, caller must be the stored representative
  string public constant VM_INVALID_GOVERNANCE_ADDRESS = '97'; // governance address can not be 0
  string public constant ALL_DELEGATION_ACTIONS_FAILED = '98'; // all meta delegation actions failed on MetaDelegateHelper
  string public constant ONLY_BY_PAYLOADS_MANAGER = '99'; // only payloads manager can call this function
  string public constant ONLY_BY_PAYLOADS_MANAGER_OR_GUARDIAN = '100'; // only payloads manager or guardian can call this function
  string public constant FUNCTION_NOT_SUPPORTED = '101'; // function not supported
  string public constant FORBIDDEN_TO_SUBMIT_NON_EXISTENT_ROOTS = '102'; // forbidden to submit non existent account roots
  string public constant FORBIDDEN_TO_SUBMIT_NON_EXISTENT_SLOTS = '103'; // forbidden to submit non existent storage slots
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library SlotUtils {
  /**
   * @notice method to calculate the slot hash of the a mapping indexed by account
   * @param account address of the balance holder
   * @param balanceMappingPosition base position of the storage slot of the balance on a token contract
   * @return the slot hash
   */
  function getAccountSlotHash(
    address account,
    uint256 balanceMappingPosition
  ) internal pure returns (bytes32) {
    return
      keccak256(
        abi.encodePacked(
          bytes32(uint256(uint160(account))),
          balanceMappingPosition
        )
      );
  }

  /**
   * @notice method to calculate the slot hash of the a mapping indexed by voter and chainId
   * @param voter address of the voter
   * @param chainId id of the chain of the votingMachine
   * @param representativesMappingPosition base position of the storage slot of the representatives on governance contract
   * @return the slot hash
   * @dev mapping(address => mapping(uint256 => address))
   */
  function getRepresentativeSlotHash(
    address voter,
    uint256 chainId,
    uint256 representativesMappingPosition
  ) internal pure returns (bytes32) {
    bytes32 voterMappingIndex = keccak256(
      abi.encodePacked(
        bytes32(uint256(uint160(voter))),
        representativesMappingPosition
      )
    );

    return
      keccak256(abi.encodePacked(bytes32(chainId), uint256(voterMappingIndex)));
  }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title IBaseVotingStrategy
 * @author BGD Labs
 * @notice interface containing the objects, events and method definitions of the BaseVotingStrategy contract
 */
interface IBaseVotingStrategy {
  /**
   * @notice object storing the information of the asset used for the voting strategy
   * @param storageSlots list of slots for the balance of the specified token.
            From that slot, by adding the address of the user, the correct balance can be taken.
   */
  struct VotingAssetConfig {
    uint128[] storageSlots;
  }

  /**
   * @notice emitted when an asset is added for the voting strategy
   * @param asset address of the token to be added
   * @param storageSlots array of storage positions of the balance mapping
   */
  event VotingAssetAdd(address indexed asset, uint128[] storageSlots);

  /**
   * @notice method to get the AAVE token address
   * @return AAVE token contract address
   */
  function AAVE() external view returns (address);

  /**
   * @notice method to get the A_AAVE token address
   * @return A_AAVE token contract address
   */
  function A_AAVE() external view returns (address);

  /**
   * @notice method to get the stkAAVE token address
   * @return stkAAVE token contract address
   */
  function STK_AAVE() external view returns (address);

  /**
   * @notice method to get the slot of the balance of the AAVE and stkAAVE
   * @return AAVE and stkAAVE base balance slot
   */
  function BASE_BALANCE_SLOT() external view returns (uint128);

  /**
   * @notice method to get the slot of the balance of the AAVE aToken
   * @return AAVE aToken base balance slot
   */
  function A_AAVE_BASE_BALANCE_SLOT() external view returns (uint128);

  /**
   * @notice method to get the slot of the AAVE aToken delegation state
   * @return AAVE aToken delegation state slot
   */
  function A_AAVE_DELEGATED_STATE_SLOT() external view returns (uint128);

  /**
   * @notice method to check if a token and slot combination is accepted
   * @param token address of the token to check
   * @param slot number of the token slot
   * @return flag indicating if the token slot is accepted
   */
  function isTokenSlotAccepted(
    address token,
    uint128 slot
  ) external view returns (bool);

  /**
   * @notice method to get the addresses of the assets that can be used for voting
   * @return list of addresses of assets
   */
  function getVotingAssetList() external view returns (address[] memory);

  /**
   * @notice method to get the configuration for voting of an asset
   * @param asset address of the asset to get the configuration from
   * @return object with the asset configuration containing the list of storage slots
   */
  function getVotingAssetConfig(
    address asset
  ) external view returns (VotingAssetConfig memory);
}

// SPDX-License-Identifier: Apache-2.0

/*
 * @author Hamdi Allam [email protected]
 * Please reach out with any questions or concerns
 * Code copied from: https://github.com/hamdiallam/Solidity-RLP/blob/master/contracts/RLPReader.sol
 */
pragma solidity ^0.8.0;

library RLPReader {
  uint8 constant STRING_SHORT_START = 0x80;
  uint8 constant STRING_LONG_START = 0xb8;
  uint8 constant LIST_SHORT_START = 0xc0;
  uint8 constant LIST_LONG_START = 0xf8;
  uint8 constant WORD_SIZE = 32;

  struct RLPItem {
    uint256 len;
    uint256 memPtr;
  }

  struct Iterator {
    RLPItem item; // Item that's being iterated over.
    uint256 nextPtr; // Position of the next item in the list.
  }

  /*
   * @dev Returns the next element in the iteration. Reverts if it has not next element.
   * @param self The iterator.
   * @return The next element in the iteration.
   */
  function next(Iterator memory self) internal pure returns (RLPItem memory) {
    require(hasNext(self));

    uint256 ptr = self.nextPtr;
    uint256 itemLength = _itemLength(ptr);
    self.nextPtr = ptr + itemLength;

    return RLPItem(itemLength, ptr);
  }

  /*
   * @dev Returns true if the iteration has more elements.
   * @param self The iterator.
   * @return true if the iteration has more elements.
   */
  function hasNext(Iterator memory self) internal pure returns (bool) {
    RLPItem memory item = self.item;
    return self.nextPtr < item.memPtr + item.len;
  }

  /*
   * @param item RLP encoded bytes
   */
  function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
    uint256 memPtr;
    assembly {
      memPtr := add(item, 0x20)
    }

    return RLPItem(item.length, memPtr);
  }

  /*
   * @dev Create an iterator. Reverts if item is not a list.
   * @param self The RLP item.
   * @return An 'Iterator' over the item.
   */
  function iterator(
    RLPItem memory self
  ) internal pure returns (Iterator memory) {
    require(isList(self));

    uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);
    return Iterator(self, ptr);
  }

  /*
   * @param the RLP item.
   */
  function rlpLen(RLPItem memory item) internal pure returns (uint256) {
    return item.len;
  }

  /*
   * @param the RLP item.
   * @return (memPtr, len) pair: location of the item's payload in memory.
   */
  function payloadLocation(
    RLPItem memory item
  ) internal pure returns (uint256, uint256) {
    uint256 offset = _payloadOffset(item.memPtr);
    uint256 memPtr = item.memPtr + offset;
    uint256 len = item.len - offset; // data length
    return (memPtr, len);
  }

  /*
   * @param the RLP item.
   */
  function payloadLen(RLPItem memory item) internal pure returns (uint256) {
    (, uint256 len) = payloadLocation(item);
    return len;
  }

  /*
   * @param the RLP item containing the encoded list.
   */
  function toList(
    RLPItem memory item
  ) internal pure returns (RLPItem[] memory) {
    require(isList(item));

    uint256 items = numItems(item);
    RLPItem[] memory result = new RLPItem[](items);

    uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
    uint256 dataLen;
    for (uint256 i = 0; i < items; i++) {
      dataLen = _itemLength(memPtr);
      result[i] = RLPItem(dataLen, memPtr);
      memPtr = memPtr + dataLen;
    }

    return result;
  }

  // @return indicator whether encoded payload is a list. negate this function call for isData.
  function isList(RLPItem memory item) internal pure returns (bool) {
    if (item.len == 0) return false;

    uint8 byte0;
    uint256 memPtr = item.memPtr;
    assembly {
      byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < LIST_SHORT_START) return false;
    return true;
  }

  /*
   * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
   * @return keccak256 hash of RLP encoded bytes.
   */
  function rlpBytesKeccak256(
    RLPItem memory item
  ) internal pure returns (bytes32) {
    uint256 ptr = item.memPtr;
    uint256 len = item.len;
    bytes32 result;
    assembly {
      result := keccak256(ptr, len)
    }
    return result;
  }

  /*
   * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
   * @return keccak256 hash of the item payload.
   */
  function payloadKeccak256(
    RLPItem memory item
  ) internal pure returns (bytes32) {
    (uint256 memPtr, uint256 len) = payloadLocation(item);
    bytes32 result;
    assembly {
      result := keccak256(memPtr, len)
    }
    return result;
  }

  /** RLPItem conversions into data types **/

  // @returns raw rlp encoding in bytes
  function toRlpBytes(
    RLPItem memory item
  ) internal pure returns (bytes memory) {
    bytes memory result = new bytes(item.len);
    if (result.length == 0) return result;

    uint256 ptr;
    assembly {
      ptr := add(0x20, result)
    }

    copy(item.memPtr, ptr, item.len);
    return result;
  }

  // any non-zero byte except "0x80" is considered true
  function toBoolean(RLPItem memory item) internal pure returns (bool) {
    require(item.len == 1);
    uint256 result;
    uint256 memPtr = item.memPtr;
    assembly {
      result := byte(0, mload(memPtr))
    }

    // SEE Github Issue #5.
    // Summary: Most commonly used RLP libraries (i.e Geth) will encode
    // "0" as "0x80" instead of as "0". We handle this edge case explicitly
    // here.
    if (result == 0 || result == STRING_SHORT_START) {
      return false;
    } else {
      return true;
    }
  }

  function toAddress(RLPItem memory item) internal pure returns (address) {
    // 1 byte for the length prefix
    require(item.len == 21);

    return address(uint160(toUint(item)));
  }

  function toUint(RLPItem memory item) internal pure returns (uint256) {
    require(item.len > 0 && item.len <= 33);

    (uint256 memPtr, uint256 len) = payloadLocation(item);

    uint256 result;
    assembly {
      result := mload(memPtr)

      // shift to the correct location if neccesary
      if lt(len, 32) {
        result := div(result, exp(256, sub(32, len)))
      }
    }

    return result;
  }

  // enforces 32 byte length
  function toUintStrict(RLPItem memory item) internal pure returns (uint256) {
    // one byte prefix
    require(item.len == 33);

    uint256 result;
    uint256 memPtr = item.memPtr + 1;
    assembly {
      result := mload(memPtr)
    }

    return result;
  }

  function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
    require(item.len > 0);

    (uint256 memPtr, uint256 len) = payloadLocation(item);
    bytes memory result = new bytes(len);

    uint256 destPtr;
    assembly {
      destPtr := add(0x20, result)
    }

    copy(memPtr, destPtr, len);
    return result;
  }

  /*
   * Private Helpers
   */

  // @return number of payload items inside an encoded list.
  function numItems(RLPItem memory item) private pure returns (uint256) {
    if (item.len == 0) return 0;

    uint256 count = 0;
    uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
    uint256 endPtr = item.memPtr + item.len;
    while (currPtr < endPtr) {
      currPtr = currPtr + _itemLength(currPtr); // skip over an item
      count++;
    }

    return count;
  }

  // @return entire rlp item byte length
  function _itemLength(uint256 memPtr) private pure returns (uint256) {
    uint256 itemLen;
    uint256 byte0;
    assembly {
      byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < STRING_SHORT_START) {
      itemLen = 1;
    } else if (byte0 < STRING_LONG_START) {
      itemLen = byte0 - STRING_SHORT_START + 1;
    } else if (byte0 < LIST_SHORT_START) {
      assembly {
        let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
        memPtr := add(memPtr, 1) // skip over the first byte

        /* 32 byte word size */
        let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
        itemLen := add(dataLen, add(byteLen, 1))
      }
    } else if (byte0 < LIST_LONG_START) {
      itemLen = byte0 - LIST_SHORT_START + 1;
    } else {
      assembly {
        let byteLen := sub(byte0, 0xf7)
        memPtr := add(memPtr, 1)

        let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
        itemLen := add(dataLen, add(byteLen, 1))
      }
    }

    return itemLen;
  }

  // @return number of bytes until the data
  function _payloadOffset(uint256 memPtr) private pure returns (uint256) {
    uint256 byte0;
    assembly {
      byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < STRING_SHORT_START) {
      return 0;
    } else if (
      byte0 < STRING_LONG_START ||
      (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)
    ) {
      return 1;
    } else if (byte0 < LIST_SHORT_START) {
      // being explicit
      return byte0 - (STRING_LONG_START - 1) + 1;
    } else {
      return byte0 - (LIST_LONG_START - 1) + 1;
    }
  }

  /*
   * @param src Pointer to source
   * @param dest Pointer to destination
   * @param len Amount of memory to copy from the source
   */
  function copy(uint256 src, uint256 dest, uint256 len) private pure {
    if (len == 0) return;

    // copy as many word sizes as possible
    for (; len >= WORD_SIZE; len -= WORD_SIZE) {
      assembly {
        mstore(dest, mload(src))
      }

      src += WORD_SIZE;
      dest += WORD_SIZE;
    }

    if (len > 0) {
      // left over bytes. Mask is used to remove unwanted bytes from the word
      uint256 mask = 256 ** (WORD_SIZE - len) - 1;
      assembly {
        let srcpart := and(mload(src), not(mask)) // zero out src
        let destpart := and(mload(dest), mask) // retrieve the bytes
        mstore(dest, or(destpart, srcpart))
      }
    }
  }
}

// SPDX-License-Identifier: MIT

/**
 * Copied from https://github.com/lidofinance/curve-merkle-oracle/blob/main/contracts/MerklePatriciaProofVerifier.sol
 */
pragma solidity ^0.8.0;

import {RLPReader} from './RLPReader.sol';

library MerklePatriciaProofVerifier {
  using RLPReader for RLPReader.RLPItem;
  using RLPReader for bytes;

  /// @dev Validates a Merkle-Patricia-Trie proof.
  ///      If the proof proves the inclusion of some key-value pair in the
  ///      trie, the value is returned. Otherwise, i.e. if the proof proves
  ///      the exclusion of a key from the trie, an empty byte array is
  ///      returned.
  /// @param rootHash is the Keccak-256 hash of the root node of the MPT.
  /// @param path is the key of the node whose inclusion/exclusion we are
  ///        proving.
  /// @param stack is the stack of MPT nodes (starting with the root) that
  ///        need to be traversed during verification.
  /// @return value whose inclusion is proved or an empty byte array for
  ///         a proof of exclusion
  function extractProofValue(
    bytes32 rootHash,
    bytes memory path,
    RLPReader.RLPItem[] memory stack
  ) internal pure returns (bytes memory value) {
    bytes memory mptKey = _decodeNibbles(path, 0);
    uint256 mptKeyOffset = 0;

    bytes32 nodeHashHash;
    RLPReader.RLPItem[] memory node;

    RLPReader.RLPItem memory rlpValue;

    if (stack.length == 0) {
      // Root hash of empty Merkle-Patricia-Trie
      require(
        rootHash ==
          0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
      );
      return new bytes(0);
    }

    // Traverse stack of nodes starting at root.
    for (uint256 i = 0; i < stack.length; i++) {
      // We use the fact that an rlp encoded list consists of some
      // encoding of its length plus the concatenation of its
      // *rlp-encoded* items.

      // The root node is hashed with Keccak-256 ...
      if (i == 0 && rootHash != stack[i].rlpBytesKeccak256()) {
        revert();
      }
      // ... whereas all other nodes are hashed with the MPT
      // hash function.
      if (i != 0 && nodeHashHash != _mptHashHash(stack[i])) {
        revert();
      }
      // We verified that stack[i] has the correct hash, so we
      // may safely decode it.
      node = stack[i].toList();

      if (node.length == 2) {
        // Extension or Leaf node

        bool isLeaf;
        bytes memory nodeKey;
        (isLeaf, nodeKey) = _merklePatriciaCompactDecode(node[0].toBytes());

        uint256 prefixLength = _sharedPrefixLength(
          mptKeyOffset,
          mptKey,
          nodeKey
        );
        mptKeyOffset += prefixLength;

        if (prefixLength < nodeKey.length) {
          // Proof claims divergent extension or leaf. (Only
          // relevant for proofs of exclusion.)
          // An Extension/Leaf node is divergent iff it "skips" over
          // the point at which a Branch node should have been had the
          // excluded key been included in the trie.
          // Example: Imagine a proof of exclusion for path [1, 4],
          // where the current node is a Leaf node with
          // path [1, 3, 3, 7]. For [1, 4] to be included, there
          // should have been a Branch node at [1] with a child
          // at 3 and a child at 4.

          // Sanity check
          if (i < stack.length - 1) {
            // divergent node must come last in proof
            revert();
          }

          return new bytes(0);
        }

        if (isLeaf) {
          // Sanity check
          if (i < stack.length - 1) {
            // leaf node must come last in proof
            revert();
          }

          if (mptKeyOffset < mptKey.length) {
            return new bytes(0);
          }

          rlpValue = node[1];
          return rlpValue.toBytes();
        } else {
          // extension
          // Sanity check
          if (i == stack.length - 1) {
            // shouldn't be at last level
            revert();
          }

          if (!node[1].isList()) {
            // rlp(child) was at least 32 bytes. node[1] contains
            // Keccak256(rlp(child)).
            nodeHashHash = node[1].payloadKeccak256();
          } else {
            // rlp(child) was less than 32 bytes. node[1] contains
            // rlp(child).
            nodeHashHash = node[1].rlpBytesKeccak256();
          }
        }
      } else if (node.length == 17) {
        // Branch node

        if (mptKeyOffset != mptKey.length) {
          // we haven't consumed the entire path, so we need to look at a child
          uint8 nibble = uint8(mptKey[mptKeyOffset]);
          mptKeyOffset += 1;
          if (nibble >= 16) {
            // each element of the path has to be a nibble
            revert();
          }

          if (_isEmptyBytesequence(node[nibble])) {
            // Sanity
            if (i != stack.length - 1) {
              // leaf node should be at last level
              revert();
            }

            return new bytes(0);
          } else if (!node[nibble].isList()) {
            nodeHashHash = node[nibble].payloadKeccak256();
          } else {
            nodeHashHash = node[nibble].rlpBytesKeccak256();
          }

          // sanity check
          if (i == stack.length - 1) {
            // need to process the child now. Last node can not be a branch node
            revert();
          }
        } else {
          // we have consumed the entire mptKey, so we need to look at what's contained in this node.

          // Sanity
          if (i != stack.length - 1) {
            // should be at last level
            revert();
          }

          return node[16].toBytes();
        }
      }
    }
  }

  /// @dev Computes the hash of the Merkle-Patricia-Trie hash of the RLP item.
  ///      Merkle-Patricia-Tries use a weird "hash function" that outputs
  ///      *variable-length* hashes: If the item is shorter than 32 bytes,
  ///      the MPT hash is the item. Otherwise, the MPT hash is the
  ///      Keccak-256 hash of the item.
  ///      The easiest way to compare variable-length byte sequences is
  ///      to compare their Keccak-256 hashes.
  /// @param item The RLP item to be hashed.
  /// @return Keccak-256(MPT-hash(item))
  function _mptHashHash(
    RLPReader.RLPItem memory item
  ) private pure returns (bytes32) {
    if (item.len < 32) {
      return item.rlpBytesKeccak256();
    } else {
      return keccak256(abi.encodePacked(item.rlpBytesKeccak256()));
    }
  }

  function _isEmptyBytesequence(
    RLPReader.RLPItem memory item
  ) private pure returns (bool) {
    if (item.len != 1) {
      return false;
    }
    uint8 b;
    uint256 memPtr = item.memPtr;
    assembly {
      b := byte(0, mload(memPtr))
    }
    return b == 0x80 /* empty byte string */;
  }

  function _merklePatriciaCompactDecode(
    bytes memory compact
  ) private pure returns (bool isLeaf, bytes memory nibbles) {
    require(compact.length > 0);
    uint256 first_nibble = (uint8(compact[0]) >> 4) & 0xF;
    uint256 skipNibbles;
    if (first_nibble == 0) {
      skipNibbles = 2;
      isLeaf = false;
    } else if (first_nibble == 1) {
      skipNibbles = 1;
      isLeaf = false;
    } else if (first_nibble == 2) {
      skipNibbles = 2;
      isLeaf = true;
    } else if (first_nibble == 3) {
      skipNibbles = 1;
      isLeaf = true;
    } else {
      // Not supposed to happen!
      revert();
    }
    return (isLeaf, _decodeNibbles(compact, skipNibbles));
  }

  function _decodeNibbles(
    bytes memory compact,
    uint256 skipNibbles
  ) private pure returns (bytes memory nibbles) {
    require(compact.length > 0);

    uint256 length = compact.length * 2;
    require(skipNibbles <= length);
    length -= skipNibbles;

    nibbles = new bytes(length);
    uint256 nibblesLength = 0;

    for (uint256 i = skipNibbles; i < skipNibbles + length; i += 1) {
      if (i % 2 == 0) {
        nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 4) & 0xF);
      } else {
        nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 0) & 0xF);
      }
      nibblesLength += 1;
    }

    assert(nibblesLength == nibbles.length);
  }

  function _sharedPrefixLength(
    uint256 xsOffset,
    bytes memory xs,
    bytes memory ys
  ) private pure returns (uint256) {
    uint256 i;
    for (i = 0; i + xsOffset < xs.length && i < ys.length; i++) {
      if (xs[i + xsOffset] != ys[i]) {
        return i;
      }
    }
    return i;
  }
}

// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import {StateProofVerifier} from '../libs/StateProofVerifier.sol';

/**
 * @title IDataWarehouse
 * @author BGD Labs
 * @notice interface containing the methods definitions of the DataWarehouse contract
 */
interface IDataWarehouse {
  /**
   * @notice event emitted when a storage root has been processed successfully
   * @param caller address that called the processStorageRoot method
   * @param account address where the root is generated
   * @param blockHash hash of the block where the root was generated
   */
  event StorageRootProcessed(
    address indexed caller,
    address indexed account,
    bytes32 indexed blockHash
  );

  /**
   * @notice event emitted when a storage root has been processed successfully
   * @param caller address that called the processStorageSlot method
   * @param account address where the slot is processed
   * @param blockHash hash of the block where the storage proof was generated
   * @param slot storage location to search
   * @param value storage information on the specified location
   */
  event StorageSlotProcessed(
    address indexed caller,
    address indexed account,
    bytes32 indexed blockHash,
    bytes32 slot,
    uint256 value
  );

  /**
   * @notice method to get the storage roots of an account (token) in a certain block hash
   * @param account address of the token to get the storage roots from
   * @param blockHash hash of the block from where the roots are generated
   * @return state root hash of the account on the block hash specified
   */
  function getStorageRoots(
    address account,
    bytes32 blockHash
  ) external view returns (bytes32);

  /**
   * @notice method to process the storage root from an account on a block hash.
   * @param account address of the token to get the storage roots from
   * @param blockHash hash of the block from where the roots are generated
   * @param blockHeaderRLP rlp encoded block header. At same block where the block hash was taken
   * @param accountStateProofRLP rlp encoded account state proof, taken in same block as block hash
   * @return the storage root
   */
  function processStorageRoot(
    address account,
    bytes32 blockHash,
    bytes memory blockHeaderRLP,
    bytes memory accountStateProofRLP
  ) external returns (bytes32);

  /**
   * @notice method to get the storage value at a certain slot and block hash for a certain address
   * @param account address of the token to get the storage roots from
   * @param blockHash hash of the block from where the roots are generated
   * @param slot hash of the explicit storage placement where the value to get is found.
   * @param storageProof generated proof containing the storage, at block hash
   * @return an object containing the slot value at the specified storage slot
   */
  function getStorage(
    address account,
    bytes32 blockHash,
    bytes32 slot,
    bytes memory storageProof
  ) external view returns (StateProofVerifier.SlotValue memory);

  /**
   * @notice method to register the storage value at a certain slot and block hash for a certain address
   * @param account address of the token to get the storage roots from
   * @param blockHash hash of the block from where the roots are generated
   * @param slot hash of the explicit storage placement where the value to get is found.
   * @param storageProof generated proof containing the storage, at block hash
   */
  function processStorageSlot(
    address account,
    bytes32 blockHash,
    bytes32 slot,
    bytes calldata storageProof
  ) external;

  /**
   * @notice method to get the value from storage at a certain block hash, previously registered.
   * @param blockHash hash of the block from where the roots are generated
   * @param account address of the token to get the storage roots from
   * @param slot hash of the explicit storage placement where the value to get is found.
   * @return numeric slot value of the slot. The value must be decoded to get the actual stored information
   */
  function getRegisteredSlot(
    bytes32 blockHash,
    address account,
    bytes32 slot
  ) external view returns (uint256);
}

Settings
{
  "remappings": [
    "aave-delivery-infrastructure/=lib/adi-deploy/lib/aave-delivery-infrastructure/src/",
    "solidity-utils/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/src/",
    "forge-std/=lib/adi-deploy/lib/aave-helpers/lib/forge-std/src/",
    "openzeppelin-contracts/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "aave-helpers/=lib/adi-deploy/lib/aave-helpers/src/",
    "aave-address-book/=lib/adi-deploy/lib/aave-helpers/lib/aave-address-book/src/",
    "aave-v3-origin/=lib/adi-deploy/lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src/",
    "adi-deploy/=lib/adi-deploy/",
    "@openzeppelin/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/openzeppelin-contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "aave-v3-origin-tests/=lib/adi-deploy/lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/tests/",
    "adi-scripts/=lib/adi-deploy/lib/aave-delivery-infrastructure/scripts/",
    "adi-tests/=lib/adi-deploy/lib/aave-delivery-infrastructure/tests/",
    "adi/=lib/adi-deploy/lib/aave-delivery-infrastructure/src/contracts/",
    "ds-test/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "halmos-cheatcodes/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "hyperlane-monorepo/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/hyperlane-monorepo/solidity/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/adi-deploy/lib/aave-delivery-infrastructure/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"dataWarehouse","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint128[]","name":"storageSlots","type":"uint128[]"}],"name":"VotingAssetAdd","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"A_AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"A_AAVE_BASE_BALANCE_SLOT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"A_AAVE_DELEGATED_STATE_SLOT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_BALANCE_SLOT","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DATA_WAREHOUSE","outputs":[{"internalType":"contract IDataWarehouse","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POWER_SCALE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STK_AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"STK_AAVE_SLASHING_EXCHANGE_RATE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STK_AAVE_SLASHING_EXCHANGE_RATE_SLOT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getVotingAssetConfig","outputs":[{"components":[{"internalType":"uint128[]","name":"storageSlots","type":"uint128[]"}],"internalType":"struct IBaseVotingStrategy.VotingAssetConfig","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getVotingAssetList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint128","name":"storageSlot","type":"uint128"},{"internalType":"uint256","name":"power","type":"uint256"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"name":"getVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"name":"hasRequiredRoots","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint128","name":"slot","type":"uint128"}],"name":"isTokenSlotAccepted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]

60a060405234801562000010575f80fd5b506040516200157b3803806200157b8339810160408190526200003391620005b7565b5f6200003e62000341565b8051604080518082019091526002815261313560f01b6020820152919250620000855760405162461bcd60e51b81526004016200007c9190620005e6565b60405180910390fd5b505f5b8151811015620002e9575f620000a082600162000634565b90505b82518110156200014157828181518110620000c257620000c262000654565b60200260200101516001600160a01b0316838381518110620000e857620000e862000654565b60200260200101516001600160a01b031614156040518060400160405280600281526020016106e760f31b81525090620001375760405162461bcd60e51b81526004016200007c9190620005e6565b50600101620000a3565b505f620001708383815181106200015c576200015c62000654565b60200260200101516200044160201b60201c565b805151604080518082019091526002815261373960f01b6020820152919250620001af5760405162461bcd60e51b81526004016200007c9190620005e6565b505f5b8151518110156200027c575f620001cb82600162000634565b90505b82515181101562000272578251805182908110620001f057620001f062000654565b60200260200101516001600160801b0316835f0151838151811062000219576200021962000654565b60200260200101516001600160801b0316141560405180604001604052806002815260200161038360f41b81525090620002685760405162461bcd60e51b81526004016200007c9190620005e6565b50600101620001ce565b50600101620001b2565b5082828151811062000292576200029262000654565b60200260200101516001600160a01b03167fbe5e9292af59bc473a1eb54ed4b2a5bca33735ed12f2752005753b62027a02ca825f0151604051620002d7919062000668565b60405180910390a25060010162000088565b505060408051808201909152600281526106c760f31b60208201526001600160a01b0382166200032e5760405162461bcd60e51b81526004016200007c9190620005e6565b506001600160a01b0316608052620006b6565b604080516003808252608082019092526060915f9190602082018480368337019050509050737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9815f8151811062000390576200039062000654565b6001600160a01b0390921660209283029190910190910152620003c4734da27a545c0c5b758a6ba100e3a049001de870f590565b81600181518110620003da57620003da62000654565b6001600160a01b03909216602092830291909101909101526200040e73a700b4eb416be35b2911fd5dee80678ff64ff6c990565b8160028151811062000424576200042462000654565b6001600160a01b0390921660209283029190910190910152919050565b6040805160208101909152606081526040805160208101909152606081526200047b737fc66500c84a76ad7e9c93437bfc5ac33e2ddae990565b6001600160a01b0316836001600160a01b03161480620004b757506001600160a01b038316734da27a545c0c5b758a6ba100e3a049001de870f5145b156200051957604080516001808252818301909252906020808301908036833750505080825280515f91908290620004f357620004f362000654565b60200260200101906001600160801b031690816001600160801b031681525050620005b1565b73a700b4eb416be35b2911fd5dee80678ff64ff6c8196001600160a01b03841601620005b15760408051600280825260608201835290916020830190803683375050508082528051603491905f9062000576576200057662000654565b60200260200101906001600160801b031690816001600160801b0316815250506040815f0151600181518110620004f357620004f362000654565b92915050565b5f60208284031215620005c8575f80fd5b81516001600160a01b0381168114620005df575f80fd5b9392505050565b5f602080835283518060208501525f5b818110156200061457858101830151858201604001528201620005f6565b505f604082860101526040601f19601f8301168501019250505092915050565b80820180821115620005b157634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b602080825282518282018190525f9190848201906040850190845b81811015620006aa5783516001600160801b03168352928401929184019160010162000683565b50909695505050505050565b608051610e89620006f25f395f8181610240015281816102c6015281816108510152818161094801528181610a360152610b2c0152610e895ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c806365d5fbeb11610093578063bdf2878d11610063578063bdf2878d146101f2578063be0d56d81461020c578063c3533db214610221578063de6bd0821461023b575f80fd5b806365d5fbeb146101ad57806369098bd7146101b5578063840261c5146101ca578063ac5af54b146101ea575f80fd5b806337dde417116100ce57806337dde4171461014157806340cd3d3f1461016457806348ccda3c14610173578063570a9714146101a1575f80fd5b80630c5fc74b146100f45780632a71f9531461011957806335f2a5c41461013a575b5f80fd5b6100fc604081565b6040516001600160801b0390911681526020015b60405180910390f35b61012c610127366004610c49565b610262565b604051908152602001610110565b6100fc5f81565b61015461014f366004610c88565b6105a8565b6040519015158152602001610110565b61012c670de0b6b3a764000081565b737fc66500c84a76ad7e9c93437bfc5ac33e2ddae95b6040516001600160a01b039091168152602001610110565b61012c6402540be40081565b61012c605181565b6101bd610614565b6040516101109190610cb9565b6101dd6101d8366004610d05565b6106fd565b6040516101109190610d25565b6100fc603481565b734da27a545c0c5b758a6ba100e3a049001de870f5610189565b61021f61021a366004610d7d565b61084e565b005b73a700b4eb416be35b2911fd5dee80678ff64ff6c9610189565b6101897f000000000000000000000000000000000000000000000000000000000000000081565b5f80734da27a545c0c5b758a6ba100e3a049001de870f4196001600160a01b038716016103f3576001600160801b0385166103ee576040516302f36c3b60e61b8152600481018490526001600160a01b038781166024830152605160448301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063bcdb0ec090606401602060405180830381865afa15801561030d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103319190610d94565b90506001600160d81b03811661035b6402540be40068ffffffffffffffffff60b089901c16610dbf565b92505f60f887901c600381111561037457610374610dd6565b9050600181600381111561038a5761038a610dd6565b141580156103aa575060038160038111156103a7576103a7610dd6565b14155b156103cb576103c86cffffffffffffffffffffffffff881685610dea565b93505b816103de670de0b6b3a764000086610dbf565b6103e89190610dfd565b93505050505b61059f565b737fc66500c84a76ad7e9c93437bfc5ac33e2ddae8196001600160a01b038716016104ba576001600160801b0385166103ee576104446402540be40068ffffffffffffffffff60b087901c16610dbf565b90505f60f885901c600381111561045d5761045d610dd6565b9050600181600381111561047357610473610dd6565b141580156104935750600381600381111561049057610490610dd6565b14155b156104b4576104b16cffffffffffffffffffffffffff861683610dea565b91505b5061059f565b73a700b4eb416be35b2911fd5dee80678ff64ff6c8196001600160a01b0387160161059f57603f196001600160801b038616016105165761050f6402540be40068ffffffffffffffffff604887901c16610dbf565b905061059f565b6033196001600160801b0386160161059f576effffffffffffffffffffffffffffff84165f60ff607887901c16600381111561055457610554610dd6565b9050600181600381111561056a5761056a610dd6565b1415801561058a5750600381600381111561058757610587610dd6565b14155b1561059c576105998284610dea565b92505b50505b95945050505050565b5f806105b3846106fd565b90505f5b8151518110156106085781518051829081106105d5576105d5610e1c565b60200260200101516001600160801b0316846001600160801b0316036106005760019250505061060e565b6001016105b7565b505f9150505b92915050565b604080516003808252608082019092526060915f9190602082018480368337019050509050737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9815f8151811061066057610660610e1c565b6001600160a01b0390921660209283029190910190910152734da27a545c0c5b758a6ba100e3a049001de870f5816001815181106106a0576106a0610e1c565b6001600160a01b039092166020928302919091019091015273a700b4eb416be35b2911fd5dee80678ff64ff6c9816002815181106106e0576106e0610e1c565b6001600160a01b0390921660209283029190910190910152919050565b604080516020808201835260608083528351918201909352918252906001600160a01b038316737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9148061076057506001600160a01b038316734da27a545c0c5b758a6ba100e3a049001de870f5145b156107bd57604080516001808252818301909252906020808301908036833750505080825280515f9190829061079857610798610e1c565b60200260200101906001600160801b031690816001600160801b03168152505061060e565b73a700b4eb416be35b2911fd5dee80678ff64ff6c8196001600160a01b0384160161060e5760408051600280825260608201835290916020830190803683375050508082528051603491905f9061081657610816610e1c565b60200260200101906001600160801b031690816001600160801b0316815250506040815f015160018151811061079857610798610e1c565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166381ac42b5737fc66500c84a76ad7e9c93437bfc5ac33e2ddae96040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa1580156108dc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109009190610d94565b1415604051806040016040528060028152602001610c8d60f21b815250906109445760405162461bcd60e51b815260040161093b9190610e30565b60405180910390fd5b505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166381ac42b5734da27a545c0c5b758a6ba100e3a049001de870f56040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa1580156109d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f79190610d94565b141560405180604001604052806002815260200161323560f01b81525090610a325760405162461bcd60e51b815260040161093b9190610e30565b505f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166381ac42b573a700b4eb416be35b2911fd5dee80678ff64ff6c96040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa158015610ac1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ae59190610d94565b141560405180604001604052806002815260200161333760f01b81525090610b205760405162461bcd60e51b815260040161093b9190610e30565b505f6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663bcdb0ec083734da27a545c0c5b758a6ba100e3a049001de870f560405160e084901b6001600160e01b031916815260048101929092526001600160a01b0316602482015260516044820152606401602060405180830381865afa158015610bb6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bda9190610d94565b1160405180604001604052806002815260200161191b60f11b81525090610c145760405162461bcd60e51b815260040161093b9190610e30565b5050565b80356001600160a01b0381168114610c2e575f80fd5b919050565b80356001600160801b0381168114610c2e575f80fd5b5f805f8060808587031215610c5c575f80fd5b610c6585610c18565b9350610c7360208601610c33565b93969395505050506040820135916060013590565b5f8060408385031215610c99575f80fd5b610ca283610c18565b9150610cb060208401610c33565b90509250929050565b602080825282518282018190525f9190848201906040850190845b81811015610cf95783516001600160a01b031683529284019291840191600101610cd4565b50909695505050505050565b5f60208284031215610d15575f80fd5b610d1e82610c18565b9392505050565b602080825282518282018290528051604084018190525f9291820190839060608601905b80831015610d725783516001600160801b03168252928401926001929092019190840190610d49565b509695505050505050565b5f60208284031215610d8d575f80fd5b5035919050565b5f60208284031215610da4575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761060e5761060e610dab565b634e487b7160e01b5f52602160045260245ffd5b8082018082111561060e5761060e610dab565b5f82610e1757634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f602080835283518060208501525f5b81811015610e5c57858101830151858201604001528201610e40565b505f604082860101526040601f19601f830116850101925050509291505056fea164736f6c6343000816000a000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c3981

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106100f0575f3560e01c806365d5fbeb11610093578063bdf2878d11610063578063bdf2878d146101f2578063be0d56d81461020c578063c3533db214610221578063de6bd0821461023b575f80fd5b806365d5fbeb146101ad57806369098bd7146101b5578063840261c5146101ca578063ac5af54b146101ea575f80fd5b806337dde417116100ce57806337dde4171461014157806340cd3d3f1461016457806348ccda3c14610173578063570a9714146101a1575f80fd5b80630c5fc74b146100f45780632a71f9531461011957806335f2a5c41461013a575b5f80fd5b6100fc604081565b6040516001600160801b0390911681526020015b60405180910390f35b61012c610127366004610c49565b610262565b604051908152602001610110565b6100fc5f81565b61015461014f366004610c88565b6105a8565b6040519015158152602001610110565b61012c670de0b6b3a764000081565b737fc66500c84a76ad7e9c93437bfc5ac33e2ddae95b6040516001600160a01b039091168152602001610110565b61012c6402540be40081565b61012c605181565b6101bd610614565b6040516101109190610cb9565b6101dd6101d8366004610d05565b6106fd565b6040516101109190610d25565b6100fc603481565b734da27a545c0c5b758a6ba100e3a049001de870f5610189565b61021f61021a366004610d7d565b61084e565b005b73a700b4eb416be35b2911fd5dee80678ff64ff6c9610189565b6101897f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c398181565b5f80734da27a545c0c5b758a6ba100e3a049001de870f4196001600160a01b038716016103f3576001600160801b0385166103ee576040516302f36c3b60e61b8152600481018490526001600160a01b038781166024830152605160448301525f917f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c39819091169063bcdb0ec090606401602060405180830381865afa15801561030d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103319190610d94565b90506001600160d81b03811661035b6402540be40068ffffffffffffffffff60b089901c16610dbf565b92505f60f887901c600381111561037457610374610dd6565b9050600181600381111561038a5761038a610dd6565b141580156103aa575060038160038111156103a7576103a7610dd6565b14155b156103cb576103c86cffffffffffffffffffffffffff881685610dea565b93505b816103de670de0b6b3a764000086610dbf565b6103e89190610dfd565b93505050505b61059f565b737fc66500c84a76ad7e9c93437bfc5ac33e2ddae8196001600160a01b038716016104ba576001600160801b0385166103ee576104446402540be40068ffffffffffffffffff60b087901c16610dbf565b90505f60f885901c600381111561045d5761045d610dd6565b9050600181600381111561047357610473610dd6565b141580156104935750600381600381111561049057610490610dd6565b14155b156104b4576104b16cffffffffffffffffffffffffff861683610dea565b91505b5061059f565b73a700b4eb416be35b2911fd5dee80678ff64ff6c8196001600160a01b0387160161059f57603f196001600160801b038616016105165761050f6402540be40068ffffffffffffffffff604887901c16610dbf565b905061059f565b6033196001600160801b0386160161059f576effffffffffffffffffffffffffffff84165f60ff607887901c16600381111561055457610554610dd6565b9050600181600381111561056a5761056a610dd6565b1415801561058a5750600381600381111561058757610587610dd6565b14155b1561059c576105998284610dea565b92505b50505b95945050505050565b5f806105b3846106fd565b90505f5b8151518110156106085781518051829081106105d5576105d5610e1c565b60200260200101516001600160801b0316846001600160801b0316036106005760019250505061060e565b6001016105b7565b505f9150505b92915050565b604080516003808252608082019092526060915f9190602082018480368337019050509050737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9815f8151811061066057610660610e1c565b6001600160a01b0390921660209283029190910190910152734da27a545c0c5b758a6ba100e3a049001de870f5816001815181106106a0576106a0610e1c565b6001600160a01b039092166020928302919091019091015273a700b4eb416be35b2911fd5dee80678ff64ff6c9816002815181106106e0576106e0610e1c565b6001600160a01b0390921660209283029190910190910152919050565b604080516020808201835260608083528351918201909352918252906001600160a01b038316737fc66500c84a76ad7e9c93437bfc5ac33e2ddae9148061076057506001600160a01b038316734da27a545c0c5b758a6ba100e3a049001de870f5145b156107bd57604080516001808252818301909252906020808301908036833750505080825280515f9190829061079857610798610e1c565b60200260200101906001600160801b031690816001600160801b03168152505061060e565b73a700b4eb416be35b2911fd5dee80678ff64ff6c8196001600160a01b0384160161060e5760408051600280825260608201835290916020830190803683375050508082528051603491905f9061081657610816610e1c565b60200260200101906001600160801b031690816001600160801b0316815250506040815f015160018151811061079857610798610e1c565b5f7f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c39816001600160a01b03166381ac42b5737fc66500c84a76ad7e9c93437bfc5ac33e2ddae96040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa1580156108dc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109009190610d94565b1415604051806040016040528060028152602001610c8d60f21b815250906109445760405162461bcd60e51b815260040161093b9190610e30565b60405180910390fd5b505f7f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c39816001600160a01b03166381ac42b5734da27a545c0c5b758a6ba100e3a049001de870f56040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa1580156109d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109f79190610d94565b141560405180604001604052806002815260200161323560f01b81525090610a325760405162461bcd60e51b815260040161093b9190610e30565b505f7f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c39816001600160a01b03166381ac42b573a700b4eb416be35b2911fd5dee80678ff64ff6c96040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381865afa158015610ac1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ae59190610d94565b141560405180604001604052806002815260200161333760f01b81525090610b205760405162461bcd60e51b815260040161093b9190610e30565b505f6001600160a01b037f000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c39811663bcdb0ec083734da27a545c0c5b758a6ba100e3a049001de870f560405160e084901b6001600160e01b031916815260048101929092526001600160a01b0316602482015260516044820152606401602060405180830381865afa158015610bb6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bda9190610d94565b1160405180604001604052806002815260200161191b60f11b81525090610c145760405162461bcd60e51b815260040161093b9190610e30565b5050565b80356001600160a01b0381168114610c2e575f80fd5b919050565b80356001600160801b0381168114610c2e575f80fd5b5f805f8060808587031215610c5c575f80fd5b610c6585610c18565b9350610c7360208601610c33565b93969395505050506040820135916060013590565b5f8060408385031215610c99575f80fd5b610ca283610c18565b9150610cb060208401610c33565b90509250929050565b602080825282518282018190525f9190848201906040850190845b81811015610cf95783516001600160a01b031683529284019291840191600101610cd4565b50909695505050505050565b5f60208284031215610d15575f80fd5b610d1e82610c18565b9392505050565b602080825282518282018290528051604084018190525f9291820190839060608601905b80831015610d725783516001600160801b03168252928401926001929092019190840190610d49565b509695505050505050565b5f60208284031215610d8d575f80fd5b5035919050565b5f60208284031215610da4575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761060e5761060e610dab565b634e487b7160e01b5f52602160045260245ffd5b8082018082111561060e5761060e610dab565b5f82610e1757634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b5f602080835283518060208501525f5b81811015610e5c57858101830151858201604001528201610e40565b505f604082860101526040601f19601f830116850101925050509291505056fea164736f6c6343000816000a

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

000000000000000000000000a638c14525caee8e498a67b409ccb1b7b34c3981

-----Decoded View---------------
Arg [0] : dataWarehouse (address): 0xa638c14525CAEE8e498A67b409CCb1B7b34c3981

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


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
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.