ETH Price: $1,841.81 (-2.23%)

Transaction Decoder

Block:
21478291 at Dec-25-2024 08:27:35 AM +UTC
Transaction Fee:
0.000389886086226105 ETH $0.72
Gas Used:
113,215 Gas / 3.443767047 Gwei

Emitted Events:

579 InstaToken.Transfer( from=[Receiver] FluidMerkleDistributor, to=[Sender] 0xa588672229a4dd7fb0ea8b018920eb37df6edc20, amount=2046186440159206 )
580 FluidMerkleDistributor.LogClaimed( user=[Sender] 0xa588672229a4dd7fb0ea8b018920eb37df6edc20, amount=2046186440159206, cycle=40, positionType=1, positionId=0000000000000000000000009FB7B4477576FE5B32BE4C1843AFB1E55F251B33, timestamp=1735115255, blockNumber=21478291 )

Account State Difference:

  Address   Before After State Difference Code
0x6f40d4A6...EECd303eb
0x7060FE0D...18fD163B0
(beaverbuild)
14.431759097930351945 Eth14.431762381165351945 Eth0.000003283235
0xa5886722...7dF6EDc20
0.00348914385088844 Eth
Nonce: 7
0.003099257764662335 Eth
Nonce: 8
0.000389886086226105

Execution Trace

FluidMerkleDistributor.claim( )
  • InstaToken.a9059cbb( )
    • InstaTokenDelegate.transfer( dst=0xa588672229a4DD7Fb0Ea8b018920eb37dF6EDc20, rawAmount=2046186440159206 ) => ( True )
      File 1 of 3: FluidMerkleDistributor
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
      pragma solidity ^0.8.0;
      import "../utils/Context.sol";
      /**
       * @dev Contract module which allows children to implement an emergency stop
       * mechanism that can be triggered by an authorized account.
       *
       * This module is used through inheritance. It will make available the
       * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
       * the functions of your contract. Note that they will not be pausable by
       * simply including this module, only once the modifiers are put in place.
       */
      abstract contract Pausable is Context {
          /**
           * @dev Emitted when the pause is triggered by `account`.
           */
          event Paused(address account);
          /**
           * @dev Emitted when the pause is lifted by `account`.
           */
          event Unpaused(address account);
          bool private _paused;
          /**
           * @dev Initializes the contract in unpaused state.
           */
          constructor() {
              _paused = false;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          modifier whenNotPaused() {
              _requireNotPaused();
              _;
          }
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          modifier whenPaused() {
              _requirePaused();
              _;
          }
          /**
           * @dev Returns true if the contract is paused, and false otherwise.
           */
          function paused() public view virtual returns (bool) {
              return _paused;
          }
          /**
           * @dev Throws if the contract is paused.
           */
          function _requireNotPaused() internal view virtual {
              require(!paused(), "Pausable: paused");
          }
          /**
           * @dev Throws if the contract is not paused.
           */
          function _requirePaused() internal view virtual {
              require(paused(), "Pausable: not paused");
          }
          /**
           * @dev Triggers stopped state.
           *
           * Requirements:
           *
           * - The contract must not be paused.
           */
          function _pause() internal virtual whenNotPaused {
              _paused = true;
              emit Paused(_msgSender());
          }
          /**
           * @dev Returns to normal state.
           *
           * Requirements:
           *
           * - The contract must be paused.
           */
          function _unpause() internal virtual whenPaused {
              _paused = false;
              emit Unpaused(_msgSender());
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       */
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP.
       */
      interface IERC20 {
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
          /**
           * @dev Moves `amount` tokens from the caller's account to `to`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address to, uint256 amount) external returns (bool);
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
           * @dev Moves `amount` tokens from `from` to `to` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(
              address from,
              address to,
              uint256 amount
          ) external returns (bool);
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
      pragma solidity ^0.8.0;
      import "../IERC20.sol";
      import "../extensions/draft-IERC20Permit.sol";
      import "../../../utils/Address.sol";
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
          function safeTransfer(
              IERC20 token,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
          function safeTransferFrom(
              IERC20 token,
              address from,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
          /**
           * @dev Deprecated. This function has issues similar to the ones found in
           * {IERC20-approve}, and its usage is discouraged.
           *
           * Whenever possible, use {safeIncreaseAllowance} and
           * {safeDecreaseAllowance} instead.
           */
          function safeApprove(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              // safeApprove should only be called when setting an initial allowance,
              // or when resetting it to zero. To increase and decrease it, use
              // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
              require(
                  (value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
          function safeIncreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              uint256 newAllowance = token.allowance(address(this), spender) + value;
              _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
          function safeDecreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              unchecked {
                  uint256 oldAllowance = token.allowance(address(this), spender);
                  require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
                  uint256 newAllowance = oldAllowance - value;
                  _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
              }
          }
          function safePermit(
              IERC20Permit token,
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) internal {
              uint256 nonceBefore = token.nonces(owner);
              token.permit(owner, spender, value, deadline, v, r, s);
              uint256 nonceAfter = token.nonces(owner);
              require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
          }
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
              bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
              if (returndata.length > 0) {
                  // Return data is optional
                  require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
      pragma solidity ^0.8.1;
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           *
           * [IMPORTANT]
           * ====
           * You shouldn't rely on `isContract` to protect against flash loan attacks!
           *
           * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
           * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
           * constructor.
           * ====
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies on extcodesize/address.code.length, which returns 0
              // for contracts in construction, since the code is only stored at the end
              // of the constructor execution.
              return account.code.length > 0;
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
              (bool success, ) = recipient.call{value: amount}("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
          /**
           * @dev Performs a Solidity function call using a low level `call`. A
           * plain `call` is an unsafe replacement for a function call: use this
           * function instead.
           *
           * If `target` reverts with a revert reason, it is bubbled up by this
           * function (like regular Solidity function calls).
           *
           * Returns the raw returned data. To convert to the expected return value,
           * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
           *
           * Requirements:
           *
           * - `target` must be a contract.
           * - calling `target` with `data` must not revert.
           *
           * _Available since v3.1._
           */
          function functionCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, "Address: low-level call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
           * `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, 0, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but also transferring `value` wei to `target`.
           *
           * Requirements:
           *
           * - the calling contract must have an ETH balance of at least `value`.
           * - the called Solidity function must be `payable`.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
          }
          /**
           * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
           * with `errorMessage` as a fallback revert reason when `target` reverts.
           *
           * _Available since v3.1._
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value,
              string memory errorMessage
          ) internal returns (bytes memory) {
              require(address(this).balance >= value, "Address: insufficient balance for call");
              (bool success, bytes memory returndata) = target.call{value: value}(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
              return functionStaticCall(target, data, "Address: low-level static call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a static call.
           *
           * _Available since v3.3._
           */
          function functionStaticCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
              return functionDelegateCall(target, data, "Address: low-level delegate call failed");
          }
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
           * but performing a delegate call.
           *
           * _Available since v3.4._
           */
          function functionDelegateCall(
              address target,
              bytes memory data,
              string memory errorMessage
          ) internal returns (bytes memory) {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata, errorMessage);
          }
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
           * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
           *
           * _Available since v4.8._
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal view returns (bytes memory) {
              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
                      require(isContract(target), "Address: call to non-contract");
                  }
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
          /**
           * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
           * revert reason or using the provided one.
           *
           * _Available since v4.3._
           */
          function verifyCallResult(
              bool success,
              bytes memory returndata,
              string memory errorMessage
          ) internal pure returns (bytes memory) {
              if (success) {
                  return returndata;
              } else {
                  _revert(returndata, errorMessage);
              }
          }
          function _revert(bytes memory returndata, string memory errorMessage) private pure {
              // Look for revert reason and bubble it up if present
              if (returndata.length > 0) {
                  // The easiest way to bubble the revert reason is using memory via assembly
                  /// @solidity memory-safe-assembly
                  assembly {
                      let returndata_size := mload(returndata)
                      revert(add(32, returndata), returndata_size)
                  }
              } else {
                  revert(errorMessage);
              }
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      }
      // SPDX-License-Identifier: MIT
      // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)
      pragma solidity ^0.8.0;
      /**
       * @dev These functions deal with verification of Merkle Tree proofs.
       *
       * The tree and the proofs can be generated using our
       * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
       * You will find a quickstart guide in the readme.
       *
       * WARNING: You should avoid using leaf values that are 64 bytes long prior to
       * hashing, or use a hash function other than keccak256 for hashing leaves.
       * This is because the concatenation of a sorted pair of internal nodes in
       * the merkle tree could be reinterpreted as a leaf value.
       * OpenZeppelin's JavaScript library generates merkle trees that are safe
       * against this attack out of the box.
       */
      library MerkleProof {
          /**
           * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
           * defined by `root`. For this, a `proof` must be provided, containing
           * sibling hashes on the branch from the leaf to the root of the tree. Each
           * pair of leaves and each pair of pre-images are assumed to be sorted.
           */
          function verify(
              bytes32[] memory proof,
              bytes32 root,
              bytes32 leaf
          ) internal pure returns (bool) {
              return processProof(proof, leaf) == root;
          }
          /**
           * @dev Calldata version of {verify}
           *
           * _Available since v4.7._
           */
          function verifyCalldata(
              bytes32[] calldata proof,
              bytes32 root,
              bytes32 leaf
          ) internal pure returns (bool) {
              return processProofCalldata(proof, leaf) == root;
          }
          /**
           * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
           * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
           * hash matches the root of the tree. When processing the proof, the pairs
           * of leafs & pre-images are assumed to be sorted.
           *
           * _Available since v4.4._
           */
          function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = _hashPair(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @dev Calldata version of {processProof}
           *
           * _Available since v4.7._
           */
          function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
              bytes32 computedHash = leaf;
              for (uint256 i = 0; i < proof.length; i++) {
                  computedHash = _hashPair(computedHash, proof[i]);
              }
              return computedHash;
          }
          /**
           * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
           * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
           *
           * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * _Available since v4.7._
           */
          function multiProofVerify(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32 root,
              bytes32[] memory leaves
          ) internal pure returns (bool) {
              return processMultiProof(proof, proofFlags, leaves) == root;
          }
          /**
           * @dev Calldata version of {multiProofVerify}
           *
           * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * _Available since v4.7._
           */
          function multiProofVerifyCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32 root,
              bytes32[] memory leaves
          ) internal pure returns (bool) {
              return processMultiProofCalldata(proof, proofFlags, leaves) == root;
          }
          /**
           * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
           * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
           * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
           * respectively.
           *
           * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
           * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
           * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
           *
           * _Available since v4.7._
           */
          function processMultiProof(
              bytes32[] memory proof,
              bool[] memory proofFlags,
              bytes32[] memory leaves
          ) internal pure returns (bytes32 merkleRoot) {
              // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 totalHashes = proofFlags.length;
              // Check proof validity.
              require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](totalHashes);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < totalHashes; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
                  hashes[i] = _hashPair(a, b);
              }
              if (totalHashes > 0) {
                  return hashes[totalHashes - 1];
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
          /**
           * @dev Calldata version of {processMultiProof}.
           *
           * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
           *
           * _Available since v4.7._
           */
          function processMultiProofCalldata(
              bytes32[] calldata proof,
              bool[] calldata proofFlags,
              bytes32[] memory leaves
          ) internal pure returns (bytes32 merkleRoot) {
              // This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
              // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
              // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
              // the merkle tree.
              uint256 leavesLen = leaves.length;
              uint256 totalHashes = proofFlags.length;
              // Check proof validity.
              require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
              // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
              // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
              bytes32[] memory hashes = new bytes32[](totalHashes);
              uint256 leafPos = 0;
              uint256 hashPos = 0;
              uint256 proofPos = 0;
              // At each step, we compute the next hash using two values:
              // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
              //   get the next hash.
              // - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
              //   `proof` array.
              for (uint256 i = 0; i < totalHashes; i++) {
                  bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
                  bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
                  hashes[i] = _hashPair(a, b);
              }
              if (totalHashes > 0) {
                  return hashes[totalHashes - 1];
              } else if (leavesLen > 0) {
                  return leaves[0];
              } else {
                  return proof[0];
              }
          }
          function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
              return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
          }
          function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
              /// @solidity memory-safe-assembly
              assembly {
                  mstore(0x00, a)
                  mstore(0x20, b)
                  value := keccak256(0x00, 0x40)
              }
          }
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity 0.8.21;
      abstract contract Errors {
          error Unauthorized();
          error InvalidParams();
          // claim related errors:
          error InvalidCycle();
          error InvalidProof();
          error NothingToClaim();
          error MsgSenderNotRecipient();
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity 0.8.21;
      abstract contract Events {
          /// @notice Emitted when an address is added or removed from the allowed proposers
          event LogUpdateProposer(address proposer, bool isProposer);
          /// @notice Emitted when an address is added or removed from the allowed approvers
          event LogUpdateApprover(address approver, bool isApprover);
          /// @notice Emitted when a new cycle root hash is proposed
          event LogRootProposed(uint256 cycle, bytes32 root, bytes32 contentHash, uint256 timestamp, uint256 blockNumber);
          /// @notice Emitted when a new cycle root hash is approved by the owner and becomes the new active root
          event LogRootUpdated(uint256 cycle, bytes32 root, bytes32 contentHash, uint256 timestamp, uint256 blockNumber);
          /// @notice Emitted when a `user` claims `amount` via a valid merkle proof
          event LogClaimed(
              address user,
              uint256 amount,
              uint256 cycle,
              uint8 positionType,
              bytes32 positionId,
              uint256 timestamp,
              uint256 blockNumber
          );
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity 0.8.21;
      import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
      import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
      import { Address } from "@openzeppelin/contracts/utils/Address.sol";
      import { Structs } from "./structs.sol";
      import { Variables } from "./variables.sol";
      import { Events } from "./events.sol";
      import { Errors } from "./errors.sol";
      // ---------------------------------------------------------------------------------------------
      //
      // @dev WARNING: DO NOT USE `multiProof` related methods of `MerkleProof`.
      // This repo uses OpenZeppelin 4.8.2 which has a vulnerability for multi proofs. See:
      // https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-wprv-93r4-jj2p
      //
      // ---------------------------------------------------------------------------------------------
      abstract contract FluidMerkleDistributorCore is Structs, Variables, Events, Errors {
          /// @dev validates that an address is not the zero address
          modifier validAddress(address value_) {
              if (value_ == address(0)) {
                  revert InvalidParams();
              }
              _;
          }
      }
      abstract contract FluidMerkleDistributorAdmin is FluidMerkleDistributorCore {
          /// @notice                  Updates an address status as a root proposer
          /// @param proposer_         The address to update
          /// @param isProposer_       Whether or not the address should be an allowed proposer
          function updateProposer(address proposer_, bool isProposer_) public onlyOwner validAddress(proposer_) {
              _proposers[proposer_] = isProposer_;
              emit LogUpdateProposer(proposer_, isProposer_);
          }
          /// @notice                  Updates an address status as a root approver
          /// @param approver_         The address to update
          /// @param isApprover_       Whether or not the address should be an allowed approver
          function updateApprover(address approver_, bool isApprover_) public onlyOwner validAddress(approver_) {
              _approvers[approver_] = isApprover_;
              emit LogUpdateApprover(approver_, isApprover_);
          }
          /// @dev open payload method for admin to resolve emergency cases
          function spell(address[] memory targets_, bytes[] memory calldatas_) public onlyOwner {
              for (uint256 i = 0; i < targets_.length; i++) {
                  Address.functionDelegateCall(targets_[i], calldatas_[i]);
              }
          }
          /// @notice Pause contract functionality of new roots and claiming
          function pause() external onlyOwner {
              _pause();
          }
          /// @notice Unpause contract functionality of new roots and claiming
          function unpause() external onlyOwner {
              _unpause();
          }
      }
      abstract contract FluidMerkleDistributorApprover is FluidMerkleDistributorCore {
          /// @dev Checks that the sender is an approver
          modifier onlyApprover() {
              if (!isApprover(msg.sender)) {
                  revert Unauthorized();
              }
              _;
          }
          /// @notice checks if the `approver_` is an allowed root approver
          function isApprover(address approver_) public view returns (bool) {
              return (_approvers[approver_] || owner == approver_);
          }
          /// @notice Approve the current pending root and content hash
          function approveRoot(
              bytes32 root_,
              bytes32 contentHash_,
              uint40 cycle_,
              uint40 startBlock_,
              uint40 endBlock_
          ) external onlyApprover {
              MerkleCycle memory merkleCycle_ = _pendingMerkleCycle;
              if (
                  root_ != merkleCycle_.merkleRoot ||
                  contentHash_ != merkleCycle_.merkleContentHash ||
                  cycle_ != merkleCycle_.cycle ||
                  startBlock_ != merkleCycle_.startBlock ||
                  endBlock_ != merkleCycle_.endBlock
              ) {
                  revert InvalidParams();
              }
              previousMerkleRoot = _currentMerkleCycle.merkleRoot;
              merkleCycle_.timestamp = uint40(block.timestamp);
              merkleCycle_.publishBlock = uint40(block.number);
              _currentMerkleCycle = merkleCycle_;
              emit LogRootUpdated(cycle_, root_, contentHash_, block.timestamp, block.number);
          }
      }
      abstract contract FluidMerkleDistributorProposer is FluidMerkleDistributorCore {
          /// @dev Checks that the sender is a proposer
          modifier onlyProposer() {
              if (!isProposer(msg.sender)) {
                  revert Unauthorized();
              }
              _;
          }
          /// @notice checks if the `proposer_` is an allowed root proposer
          function isProposer(address proposer_) public view returns (bool) {
              return (_proposers[proposer_] || owner == proposer_);
          }
          /// @notice Propose a new root and content hash, which will be stored as pending until approved
          function proposeRoot(
              bytes32 root_,
              bytes32 contentHash_,
              uint40 cycle_,
              uint40 startBlock_,
              uint40 endBlock_
          ) external whenNotPaused onlyProposer {
              if (cycle_ != _currentMerkleCycle.cycle + 1 || startBlock_ > endBlock_) {
                  revert InvalidParams();
              }
              _pendingMerkleCycle = MerkleCycle({
                  merkleRoot: root_,
                  merkleContentHash: contentHash_,
                  cycle: cycle_,
                  startBlock: startBlock_,
                  endBlock: endBlock_,
                  timestamp: uint40(block.timestamp),
                  publishBlock: uint40(block.number)
              });
              emit LogRootProposed(cycle_, root_, contentHash_, block.timestamp, block.number);
          }
      }
      contract FluidMerkleDistributor is
          FluidMerkleDistributorCore,
          FluidMerkleDistributorAdmin,
          FluidMerkleDistributorApprover,
          FluidMerkleDistributorProposer
      {
          constructor(
              string memory name_,
              address owner_,
              address proposer_,
              address approver_,
              address rewardToken_
          )
              validAddress(owner_)
              validAddress(proposer_)
              validAddress(approver_)
              validAddress(rewardToken_)
              Variables(owner_, rewardToken_)
          {   
              name = name_;
              
              _proposers[proposer_] = true;
              emit LogUpdateProposer(proposer_, true);
              _approvers[approver_] = true;
              emit LogUpdateApprover(approver_, true);
          }
          /// @notice checks if there is a proposed root waiting to be approved
          function hasPendingRoot() external view returns (bool) {
              return _pendingMerkleCycle.cycle == _currentMerkleCycle.cycle + 1;
          }
          /// @notice merkle root data related to current cycle (proposed and approved).
          function currentMerkleCycle() public view returns (MerkleCycle memory) {
              return _currentMerkleCycle;
          }
          /// @notice merkle root data related to pending cycle (proposed but not yet approved).
          function pendingMerkleCycle() public view returns (MerkleCycle memory) {
              return _pendingMerkleCycle;
          }
          function encodeClaim(
              address recipient_,
              uint256 cumulativeAmount_,
              uint8 positionType_,
              bytes32 positionId_,
              uint256 cycle_,
              bytes memory metadata_
          ) public pure returns (bytes memory encoded_, bytes32 hash_) {
              encoded_ = abi.encode(positionType_, positionId_, recipient_, cycle_, cumulativeAmount_, metadata_);
              hash_ = keccak256(bytes.concat(keccak256(encoded_)));
          }
          function claim(
              address recipient_,
              uint256 cumulativeAmount_,
              uint8 positionType_,
              bytes32 positionId_,
              uint256 cycle_,
              bytes32[] calldata merkleProof_,
              bytes memory metadata_
          ) external whenNotPaused {
              if(msg.sender != recipient_) revert MsgSenderNotRecipient();
              uint256 currentCycle_ = uint256(_currentMerkleCycle.cycle);
              if (!(cycle_ == currentCycle_ || (currentCycle_ > 0 && cycle_ == currentCycle_ - 1))) {
                  revert InvalidCycle();
              }
              // Verify the merkle proof.
              bytes32 node_ = keccak256(
                  bytes.concat(keccak256(abi.encode(positionType_, positionId_, recipient_, cycle_, cumulativeAmount_, metadata_)))
              );
              if (
                  !MerkleProof.verify(
                      merkleProof_,
                      cycle_ == currentCycle_ ? _currentMerkleCycle.merkleRoot : previousMerkleRoot,
                      node_
                  )
              ) {
                  revert InvalidProof();
              }
              uint256 claimable_ = cumulativeAmount_ - claimed[recipient_][positionId_];
              if (claimable_ == 0) {
                  revert NothingToClaim();
              }
              claimed[recipient_][positionId_] = cumulativeAmount_;
              SafeERC20.safeTransfer(TOKEN, recipient_, claimable_);
              emit LogClaimed(recipient_, claimable_, cycle_, positionType_, positionId_, block.timestamp, block.number);
          }
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity 0.8.21;
      abstract contract Structs {
          struct MerkleCycle {
              // slot 1
              bytes32 merkleRoot;
              // slot 2
              bytes32 merkleContentHash;
              // slot 3
              uint40 cycle;
              uint40 timestamp;
              uint40 publishBlock;
              uint40 startBlock;
              uint40 endBlock;
          }
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity 0.8.21;
      import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      import { Owned } from "solmate/src/auth/Owned.sol";
      import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol";
      import { Structs } from "./structs.sol";
      abstract contract Constants {
          IERC20 public immutable TOKEN;
          constructor(address rewardToken_) {
              TOKEN = IERC20(rewardToken_);
          }
      }
      abstract contract Variables is Owned, Pausable, Constants, Structs {
          // ------------ storage variables from inherited contracts (Owned, Pausable) come before vars here --------
          // ----------------------- slot 0 ---------------------------
          // address public owner; -> from Owned
          // bool private _paused; -> from Pausable
          // 11 bytes empty
          // ----------------------- slot 1 ---------------------------
          /// @dev Name of the Merkle Distributor
          string public name;
          // ----------------------- slot 2 ---------------------------
          /// @dev allow list for allowed root proposer addresses
          mapping(address => bool) internal _proposers;
          // ----------------------- slot 3 ---------------------------
          /// @dev allow list for allowed root proposer addresses
          mapping(address => bool) internal _approvers;
          // ----------------------- slot 4-6 ---------------------------
          /// @dev merkle root data related to current cycle (proposed and approved).
          /// @dev timestamp & publishBlock = data from last publish.
          // with custom getter to return whole struct at once instead of default solidity getter splitting it into tuple
          MerkleCycle internal _currentMerkleCycle;
          // ----------------------- slot 7-9 ---------------------------
          /// @dev merkle root data related to pending cycle (proposed but not yet approved).
          /// @dev timestamp & publishBlock = data from last propose.
          // with custom getter to return whole struct at once instead of default solidity getter splitting it into tuple
          MerkleCycle internal _pendingMerkleCycle;
          // ----------------------- slot 10 ---------------------------
          /// @notice merkle root of the previous cycle
          bytes32 public previousMerkleRoot;
          // ----------------------- slot 11 ---------------------------
          /// @notice total claimed amount per user address and fToken. user => positionId => claimed amount
          mapping(address => mapping(bytes32 => uint256)) public claimed;
          constructor(address owner_, address rewardToken_) Constants(rewardToken_) Owned(owner_) {}
      }
      // SPDX-License-Identifier: AGPL-3.0-only
      pragma solidity >=0.8.0;
      /// @notice Simple single owner authorization mixin.
      /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
      abstract contract Owned {
          /*//////////////////////////////////////////////////////////////
                                       EVENTS
          //////////////////////////////////////////////////////////////*/
          event OwnershipTransferred(address indexed user, address indexed newOwner);
          /*//////////////////////////////////////////////////////////////
                                  OWNERSHIP STORAGE
          //////////////////////////////////////////////////////////////*/
          address public owner;
          modifier onlyOwner() virtual {
              require(msg.sender == owner, "UNAUTHORIZED");
              _;
          }
          /*//////////////////////////////////////////////////////////////
                                     CONSTRUCTOR
          //////////////////////////////////////////////////////////////*/
          constructor(address _owner) {
              owner = _owner;
              emit OwnershipTransferred(address(0), _owner);
          }
          /*//////////////////////////////////////////////////////////////
                                   OWNERSHIP LOGIC
          //////////////////////////////////////////////////////////////*/
          function transferOwnership(address newOwner) public virtual onlyOwner {
              owner = newOwner;
              emit OwnershipTransferred(msg.sender, newOwner);
          }
      }
      

      File 2 of 3: InstaToken
      pragma solidity ^0.7.0;
      pragma experimental ABIEncoderV2;
      import { TokenDelegatorStorage, TokenEvents } from "./TokenInterfaces.sol";
      contract InstaToken is TokenDelegatorStorage, TokenEvents {
          constructor(
              address account,
              address implementation_,
              uint initialSupply_,
              uint mintingAllowedAfter_,
              bool transferPaused_
          ) {
              require(implementation_ != address(0), "TokenDelegator::constructor invalid address");
              delegateTo(
                  implementation_,
                  abi.encodeWithSignature(
                      "initialize(address,uint256,uint256,bool)",
                      account,
                      initialSupply_,
                      mintingAllowedAfter_,
                      transferPaused_
                  )
              );
              implementation = implementation_;
              emit NewImplementation(address(0), implementation);
          }
          /**
           * @notice Called by the admin to update the implementation of the delegator
           * @param implementation_ The address of the new implementation for delegation
           */
          function _setImplementation(address implementation_) external isMaster {
              require(implementation_ != address(0), "TokenDelegator::_setImplementation: invalid implementation address");
              address oldImplementation = implementation;
              implementation = implementation_;
              emit NewImplementation(oldImplementation, implementation);
          }
          /**
           * @notice Internal method to delegate execution to another contract
           * @dev It returns to the external caller whatever the implementation returns or forwards reverts
           * @param callee The contract to delegatecall
           * @param data The raw data to delegatecall
           */
          function delegateTo(address callee, bytes memory data) internal {
              (bool success, bytes memory returnData) = callee.delegatecall(data);
              assembly {
                  if eq(success, 0) {
                      revert(add(returnData, 0x20), returndatasize())
                  }
              }
          }
          /**
           * @dev Delegates execution to an implementation contract.
           * It returns to the external caller whatever the implementation returns
           * or forwards reverts.
           */
          fallback () external payable {
              // delegate all other functions to current implementation
              (bool success, ) = implementation.delegatecall(msg.data);
              assembly {
                  let free_mem_ptr := mload(0x40)
                  returndatacopy(free_mem_ptr, 0, returndatasize())
                  switch success
                  case 0 { revert(free_mem_ptr, returndatasize()) }
                  default { return(free_mem_ptr, returndatasize()) }
              }
          }
      }
      pragma solidity ^0.7.0;
      pragma experimental ABIEncoderV2;
      interface IndexInterface {
          function master() external view returns (address);
      }
      contract TokenEvents {
          
          /// @notice An event thats emitted when an account changes its delegate
          event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
          /// @notice An event thats emitted when a delegate account's vote balance changes
          event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
          /// @notice An event thats emitted when the minter changes
          event MinterChanged(address indexed oldMinter, address indexed newMinter);
          /// @notice The standard EIP-20 transfer event
          event Transfer(address indexed from, address indexed to, uint256 amount);
          /// @notice The standard EIP-20 approval event
          event Approval(address indexed owner, address indexed spender, uint256 amount);
          /// @notice Emitted when implementation is changed
          event NewImplementation(address oldImplementation, address newImplementation);
          /// @notice An event thats emitted when the token transfered is paused
          event TransferPaused(address indexed minter);
          /// @notice An event thats emitted when the token transfered is unpaused
          event TransferUnpaused(address indexed minter);
          /// @notice An event thats emitted when the token symbol is changed
          event ChangedSymbol(string oldSybmol, string newSybmol);
          /// @notice An event thats emitted when the token name is changed
          event ChangedName(string oldName, string newName);
      }
      contract TokenDelegatorStorage {
          /// @notice InstaIndex contract
          IndexInterface constant public instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
          /// @notice Active brains of Token
          address public implementation;
          /// @notice EIP-20 token name for this token
          string public name = "Instadapp";
          /// @notice EIP-20 token symbol for this token
          string public symbol = "INST";
          /// @notice Total number of tokens in circulation
          uint public totalSupply;
          /// @notice EIP-20 token decimals for this token
          uint8 public constant decimals = 18;
          modifier isMaster() {
              require(instaIndex.master() == msg.sender, "Tkn::isMaster: msg.sender not master");
              _;
          }
      }
      /**
       * @title Storage for Token Delegate
       * @notice For future upgrades, do not change TokenDelegateStorageV1. Create a new
       * contract which implements TokenDelegateStorageV1 and following the naming convention
       * TokenDelegateStorageVX.
       */
      contract TokenDelegateStorageV1 is TokenDelegatorStorage {
          /// @notice The timestamp after which minting may occur
          uint public mintingAllowedAfter;
          /// @notice token transfer pause state
          bool public transferPaused;
          // Allowance amounts on behalf of others
          mapping (address => mapping (address => uint96)) internal allowances;
          // Official record of token balances for each account
          mapping (address => uint96) internal balances;
          /// @notice A record of each accounts delegate
          mapping (address => address) public delegates;
          /// @notice A checkpoint for marking number of votes from a given block
          struct Checkpoint {
              uint32 fromBlock;
              uint96 votes;
          }
          /// @notice A record of votes checkpoints for each account, by index
          mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
          /// @notice The number of checkpoints for each account
          mapping (address => uint32) public numCheckpoints;
          /// @notice A record of states for signing / validating signatures
          mapping (address => uint) public nonces;
      }

      File 3 of 3: InstaTokenDelegate
      pragma solidity ^0.7.0;
      pragma experimental ABIEncoderV2;
      import { TokenDelegateStorageV1, TokenEvents} from "./TokenInterfaces.sol";
      import { SafeMath } from "./SafeMath.sol";
      contract InstaTokenDelegate is TokenDelegateStorageV1, TokenEvents {
          /// @notice Minimum time between mints
          uint32 public constant minimumTimeBetweenMints = 1 days * 365; // 365 days
          /// @notice Cap on the percentage of totalSupply that can be minted at each mint
          uint8 public constant mintCap = 2; // 2%
          /// @notice The EIP-712 typehash for the contract's domain
          bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
          /// @notice The EIP-712 typehash for the delegation struct used by the contract
          bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
          /// @notice The EIP-712 typehash for the permit struct used by the contract
          bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
          /**
            * @notice Used to initialize the contract during delegator constructor
            * @param account The address to recieve initial suppply
            * @param mintingAllowedAfter_ Timestamp of the next allowed minting
            * @param transferPaused_ Flag to make the token non-transferable
            */
          function initialize(address account, uint initialSupply_, uint mintingAllowedAfter_, bool transferPaused_) public {
              require(mintingAllowedAfter == 0, "Token::initialize: can only initialize once");
              require(totalSupply == 0, "Token::initialize: can only initialize once");
              require(mintingAllowedAfter_ >= block.timestamp, "Token::constructor: minting can only begin after deployment");
              require(account != address(0), "Token::initialize: invalid address");
              require(initialSupply_ > 0, "Token::initialize: invalid initial supply");
              totalSupply = initialSupply_;
              balances[account] = uint96(totalSupply);
              emit Transfer(address(0), account, totalSupply);
              mintingAllowedAfter = mintingAllowedAfter_;
              transferPaused = transferPaused_;
              if (transferPaused) {
                  emit TransferPaused(msg.sender);
              } else {
                  emit TransferUnpaused(msg.sender);
              }
          }
          /**
           * @notice Pause the token transfer
           */
          function pauseTransfer() external isMaster {
              transferPaused = true;
              emit TransferPaused(msg.sender);
          }
          /**
           * @notice Unpause the token transfer
           */
          function unpauseTransfer() external isMaster {
              transferPaused = false;
              emit TransferUnpaused(msg.sender);
          }
          /**
           * @notice Change token name
           * @param name_ New token name
           */
          function changeName(string calldata name_) external isMaster {
              require(bytes(name_).length > 0, "Tkn::changeName: name_ length invaild");
              emit ChangedName(name, name_);
              name = name_;
          }
          /**
           * @notice Change token symbol
           * @param symbol_ New token symbol
           */
          function changeSymbol(string calldata symbol_) external isMaster {
              require(bytes(symbol_).length > 0, "Tkn::changeSymbol: name_name_ length invaild");
              emit ChangedName(symbol, symbol_);
              symbol = symbol_;
          }
          /**
           * @notice Get the number of tokens `spender` is approved to spend on behalf of `account`
           * @param account The address of the account holding the funds
           * @param spender The address of the account spending the funds
           * @return The number of tokens approved
           */
          function allowance(address account, address spender) external view returns (uint) {
              return allowances[account][spender];
          }
          /**
           * @notice Approve `spender` to transfer up to `amount` from `src`
           * @dev This will overwrite the approval amount for `spender`
           *  and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
           * @param spender The address of the account which may transfer tokens
           * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
           * @return Whether or not the approval succeeded
           */
          function approve(address spender, uint rawAmount) external returns (bool) {
              uint96 amount;
              if (rawAmount == uint(-1)) {
                  amount = uint96(-1);
              } else {
                  amount = safe96(rawAmount, "Tkn::approve: amount exceeds 96 bits");
              }
              allowances[msg.sender][spender] = amount;
              emit Approval(msg.sender, spender, amount);
              return true;
          }
          /**
           * @notice Triggers an approval from owner to spends
           * @param owner The address to approve from
           * @param spender The address to be approved
           * @param rawAmount The number of tokens that are approved (2^256-1 means infinite)
           * @param deadline The time at which to expire the signature
           * @param v The recovery byte of the signature
           * @param r Half of the ECDSA signature pair
           * @param s Half of the ECDSA signature pair
           */
          function permit(address owner, address spender, uint rawAmount, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
              uint96 amount;
              if (rawAmount == uint(-1)) {
                  amount = uint96(-1);
              } else {
                  amount = safe96(rawAmount, "Tkn::permit: amount exceeds 96 bits");
              }
              bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
              bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, rawAmount, nonces[owner]++, deadline));
              bytes32 digest = keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
              address signatory = ecrecover(digest, v, r, s);
              require(signatory != address(0), "Tkn::permit: invalid signature");
              require(signatory == owner, "Tkn::permit: unauthorized");
              require(block.timestamp <= deadline, "Tkn::permit: signature expired");
              allowances[owner][spender] = amount;
              emit Approval(owner, spender, amount);
          }
          /**
           * @notice Get the number of tokens held by the `account`
           * @param account The address of the account to get the balance of
           * @return The number of tokens held
           */
          function balanceOf(address account) external view returns (uint) {
              return balances[account];
          }
          /**
           * @notice Transfer `amount` tokens from `msg.sender` to `dst`
           * @param dst The address of the destination account
           * @param rawAmount The number of tokens to transfer
           * @return Whether or not the transfer succeeded
           */
          function transfer(address dst, uint rawAmount) external returns (bool) {
              uint96 amount = safe96(rawAmount, "Tkn::transfer: amount exceeds 96 bits");
              _transferTokens(msg.sender, dst, amount);
              return true;
          }
          /**
           * @notice Transfer `amount` tokens from `src` to `dst`
           * @param src The address of the source account
           * @param dst The address of the destination account
           * @param rawAmount The number of tokens to transfer
           * @return Whether or not the transfer succeeded
           */
          function transferFrom(address src, address dst, uint rawAmount) external returns (bool) {
              address spender = msg.sender;
              uint96 spenderAllowance = allowances[src][spender];
              uint96 amount = safe96(rawAmount, "Tkn::approve: amount exceeds 96 bits");
              if (spender != src && spenderAllowance != uint96(-1)) {
                  uint96 newAllowance = sub96(spenderAllowance, amount, "Tkn::transferFrom: transfer amount exceeds spender allowance");
                  allowances[src][spender] = newAllowance;
                  emit Approval(src, spender, newAllowance);
              }
              _transferTokens(src, dst, amount);
              return true;
          }
          /**
           * @notice Mint new tokens
           * @param dst The address of the destination account
           * @param rawAmount The number of tokens to be minted
           */
          function mint(address dst, uint rawAmount) external isMaster {
              require(block.timestamp >= mintingAllowedAfter, "Uni::mint: minting not allowed yet");
              require(dst != address(0), "Tkn::mint: cannot transfer to the zero address");
              // record the mint
              mintingAllowedAfter = SafeMath.add(block.timestamp, minimumTimeBetweenMints);
              // mint the amount
              uint96 amount = safe96(rawAmount, "Tkn::mint: amount exceeds 96 bits");
              require(amount <= SafeMath.div(SafeMath.mul(totalSupply, mintCap), 100), "Uni::mint: exceeded mint cap");
              totalSupply = safe96(SafeMath.add(totalSupply, amount), "Uni::mint: totalSupply exceeds 96 bits");
              // transfer the amount to the recipient
              balances[dst] = add96(balances[dst], amount, "Tkn::mint: transfer amount overflows");
              emit Transfer(address(0), dst, amount);
              // move delegates
              _moveDelegates(address(0), delegates[dst], amount);
          }
          /**
           * @notice Delegate votes from `msg.sender` to `delegatee`
           * @param delegatee The address to delegate votes to
           */
          function delegate(address delegatee) public {
              return _delegate(msg.sender, delegatee);
          }
          /**
           * @notice Delegates votes from signatory to `delegatee`
           * @param delegatee The address to delegate votes to
           * @param nonce The contract state required to match the signature
           * @param expiry The time at which to expire the signature
           * @param v The recovery byte of the signature
           * @param r Half of the ECDSA signature pair
           * @param s Half of the ECDSA signature pair
           */
          function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public {
              bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this)));
              bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
              bytes32 digest = keccak256(abi.encodePacked("\\x19\\x01", domainSeparator, structHash));
              address signatory = ecrecover(digest, v, r, s);
              require(signatory != address(0), "Tkn::delegateBySig: invalid signature");
              require(nonce == nonces[signatory]++, "Tkn::delegateBySig: invalid nonce");
              require(block.timestamp <= expiry, "Tkn::delegateBySig: signature expired");
              return _delegate(signatory, delegatee);
          }
          /**
           * @notice Gets the current votes balance for `account`
           * @param account The address to get votes balance
           * @return The number of current votes for `account`
           */
          function getCurrentVotes(address account) external view returns (uint96) {
              uint32 nCheckpoints = numCheckpoints[account];
              return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
          }
          /**
           * @notice Determine the prior number of votes for an account as of a block number
           * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
           * @param account The address of the account to check
           * @param blockNumber The block number to get the vote balance at
           * @return The number of votes the account had as of the given block
           */
          function getPriorVotes(address account, uint blockNumber) public view returns (uint96) {
              require(blockNumber < block.number, "Tkn::getPriorVotes: not yet determined");
              uint32 nCheckpoints = numCheckpoints[account];
              if (nCheckpoints == 0) {
                  return 0;
              }
              // First check most recent balance
              if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
                  return checkpoints[account][nCheckpoints - 1].votes;
              }
              // Next check implicit zero balance
              if (checkpoints[account][0].fromBlock > blockNumber) {
                  return 0;
              }
              uint32 lower = 0;
              uint32 upper = nCheckpoints - 1;
              while (upper > lower) {
                  uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
                  Checkpoint memory cp = checkpoints[account][center];
                  if (cp.fromBlock == blockNumber) {
                      return cp.votes;
                  } else if (cp.fromBlock < blockNumber) {
                      lower = center;
                  } else {
                      upper = center - 1;
                  }
              }
              return checkpoints[account][lower].votes;
          }
          function _delegate(address delegator, address delegatee) internal {
              address currentDelegate = delegates[delegator];
              uint96 delegatorBalance = balances[delegator];
              delegates[delegator] = delegatee;
              emit DelegateChanged(delegator, currentDelegate, delegatee);
              _moveDelegates(currentDelegate, delegatee, delegatorBalance);
          }
          function _transferTokens(address src, address dst, uint96 amount) internal {
              require(!transferPaused, "Tkn::_transferTokens: transfer paused");
              require(src != address(0), "Tkn::_transferTokens: cannot transfer from the zero address");
              require(dst != address(0), "Tkn::_transferTokens: cannot transfer to the zero address");
              balances[src] = sub96(balances[src], amount, "Tkn::_transferTokens: transfer amount exceeds balance");
              balances[dst] = add96(balances[dst], amount, "Tkn::_transferTokens: transfer amount overflows");
              emit Transfer(src, dst, amount);
              _moveDelegates(delegates[src], delegates[dst], amount);
          }
          function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
              if (srcRep != dstRep && amount > 0) {
                  if (srcRep != address(0)) {
                      uint32 srcRepNum = numCheckpoints[srcRep];
                      uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                      uint96 srcRepNew = sub96(srcRepOld, amount, "Tkn::_moveVotes: vote amount underflows");
                      _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
                  }
                  if (dstRep != address(0)) {
                      uint32 dstRepNum = numCheckpoints[dstRep];
                      uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                      uint96 dstRepNew = add96(dstRepOld, amount, "Tkn::_moveVotes: vote amount overflows");
                      _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
                  }
              }
          }
          function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
              uint32 blockNumber = safe32(block.number, "Tkn::_writeCheckpoint: block number exceeds 32 bits");
              if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
                  checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
              } else {
                  checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
                  numCheckpoints[delegatee] = nCheckpoints + 1;
              }
              emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
          }
          function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
              require(n < 2**32, errorMessage);
              return uint32(n);
          }
          function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
              require(n < 2**96, errorMessage);
              return uint96(n);
          }
          function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
              uint96 c = a + b;
              require(c >= a, errorMessage);
              return c;
          }
          function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
              require(b <= a, errorMessage);
              return a - b;
          }
          function getChainId() internal pure returns (uint) {
              uint256 chainId;
              assembly { chainId := chainid() }
              return chainId;
          }
      }pragma solidity ^0.7.0;
      pragma experimental ABIEncoderV2;
      interface IndexInterface {
          function master() external view returns (address);
      }
      contract TokenEvents {
          
          /// @notice An event thats emitted when an account changes its delegate
          event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
          /// @notice An event thats emitted when a delegate account's vote balance changes
          event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
          /// @notice An event thats emitted when the minter changes
          event MinterChanged(address indexed oldMinter, address indexed newMinter);
          /// @notice The standard EIP-20 transfer event
          event Transfer(address indexed from, address indexed to, uint256 amount);
          /// @notice The standard EIP-20 approval event
          event Approval(address indexed owner, address indexed spender, uint256 amount);
          /// @notice Emitted when implementation is changed
          event NewImplementation(address oldImplementation, address newImplementation);
          /// @notice An event thats emitted when the token transfered is paused
          event TransferPaused(address indexed minter);
          /// @notice An event thats emitted when the token transfered is unpaused
          event TransferUnpaused(address indexed minter);
          /// @notice An event thats emitted when the token symbol is changed
          event ChangedSymbol(string oldSybmol, string newSybmol);
          /// @notice An event thats emitted when the token name is changed
          event ChangedName(string oldName, string newName);
      }
      contract TokenDelegatorStorage {
          /// @notice InstaIndex contract
          IndexInterface constant public instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723);
          /// @notice Active brains of Token
          address public implementation;
          /// @notice EIP-20 token name for this token
          string public name = "Instadapp";
          /// @notice EIP-20 token symbol for this token
          string public symbol = "INST";
          /// @notice Total number of tokens in circulation
          uint public totalSupply;
          /// @notice EIP-20 token decimals for this token
          uint8 public constant decimals = 18;
          modifier isMaster() {
              require(instaIndex.master() == msg.sender, "Tkn::isMaster: msg.sender not master");
              _;
          }
      }
      /**
       * @title Storage for Token Delegate
       * @notice For future upgrades, do not change TokenDelegateStorageV1. Create a new
       * contract which implements TokenDelegateStorageV1 and following the naming convention
       * TokenDelegateStorageVX.
       */
      contract TokenDelegateStorageV1 is TokenDelegatorStorage {
          /// @notice The timestamp after which minting may occur
          uint public mintingAllowedAfter;
          /// @notice token transfer pause state
          bool public transferPaused;
          // Allowance amounts on behalf of others
          mapping (address => mapping (address => uint96)) internal allowances;
          // Official record of token balances for each account
          mapping (address => uint96) internal balances;
          /// @notice A record of each accounts delegate
          mapping (address => address) public delegates;
          /// @notice A checkpoint for marking number of votes from a given block
          struct Checkpoint {
              uint32 fromBlock;
              uint96 votes;
          }
          /// @notice A record of votes checkpoints for each account, by index
          mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
          /// @notice The number of checkpoints for each account
          mapping (address => uint32) public numCheckpoints;
          /// @notice A record of states for signing / validating signatures
          mapping (address => uint) public nonces;
      }pragma solidity ^0.7.0;
      // From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol
      // Subject to the MIT license.
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
              return c;
          }
          /**
           * @dev Returns the addition of two unsigned integers, reverting with custom message on overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, errorMessage);
              return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot underflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction underflow");
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot underflow.
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
              return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
              return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b, errorMessage);
              return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers.
           * Reverts on division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
          /**
           * @dev Returns the integer division of two unsigned integers.
           * Reverts with custom message on division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              // Solidity only automatically asserts when dividing by 0
              require(b > 0, errorMessage);
              uint256 c = a / b;
              // assert(a == b * c + a % b); // There is no case in which this doesn't hold
              return c;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }