ETH Price: $2,518.22 (+0.83%)

Transaction Decoder

Block:
20368981 at Jul-23-2024 11:37:59 AM +UTC
Transaction Fee:
0.000467946572012101 ETH $1.18
Gas Used:
58,877 Gas / 7.947867113 Gwei

Emitted Events:

86 GnosisSafeProxy.0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e( 0x442e715f626346e8c54381002da614f62bee8d27386535b2521ec8540898556e, b0813e24cf4bc3ca8cabbcff89ac798261bd7a0dc1571490cc6032669f279456, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
14.905262055577310255 Eth14.905517972896827296 Eth0.000255917319517041
0x4eB25a65...8Ca843BC7 4.864977733728258207 Eth3.864977733728258207 Eth1
0xE878Eb19...12277C066
0.12245702266900599 Eth
Nonce: 86
0.121989076096993889 Eth
Nonce: 87
0.000467946572012101
0xFE7f9Ece...7d6834C0C 0 Eth1 Eth1

Execution Trace

GnosisSafeProxy.6a761202( )
  • GnosisSafe.execTransaction( to=0xFE7f9Ece94500d6381bA1BB0afd77577d6834C0C, value=1000000000000000000, data=0x, operation=0, safeTxGas=0, baseGas=0, gasPrice=0, gasToken=0x0000000000000000000000000000000000000000, refundReceiver=0x0000000000000000000000000000000000000000, signatures=0x95CAA1D61EAF705CB1357854DE35ADCD4F1C780B98F28F1A377AB4A329AC34A818CDE5EB90E5E5F72985E6DF2C5915600B173CCA615681F7FDE29D2C680094F420 ) => ( success=True )
    • Null: 0x000...001.0b1a26e2( )
    • ETH 1 Chronicle_MOG_USD_1.CALL( )
      File 1 of 3: GnosisSafeProxy
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      
      /// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
      /// @author Richard Meissner - <[email protected]>
      interface IProxy {
          function masterCopy() external view returns (address);
      }
      
      /// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
      /// @author Stefan George - <[email protected]>
      /// @author Richard Meissner - <[email protected]>
      contract GnosisSafeProxy {
          // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
          // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
          address internal singleton;
      
          /// @dev Constructor function sets address of singleton contract.
          /// @param _singleton Singleton address.
          constructor(address _singleton) {
              require(_singleton != address(0), "Invalid singleton address provided");
              singleton = _singleton;
          }
      
          /// @dev Fallback function forwards all transactions and returns all received return data.
          fallback() external payable {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                  // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                  if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                      mstore(0, _singleton)
                      return(0, 0x20)
                  }
                  calldatacopy(0, 0, calldatasize())
                  let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
                  returndatacopy(0, 0, returndatasize())
                  if eq(success, 0) {
                      revert(0, returndatasize())
                  }
                  return(0, returndatasize())
              }
          }
      }
      
      /// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
      /// @author Stefan George - <[email protected]>
      contract GnosisSafeProxyFactory {
          event ProxyCreation(GnosisSafeProxy proxy, address singleton);
      
          /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
          /// @param singleton Address of singleton contract.
          /// @param data Payload for message call sent to new proxy contract.
          function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
              proxy = new GnosisSafeProxy(singleton);
              if (data.length > 0)
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
                          revert(0, 0)
                      }
                  }
              emit ProxyCreation(proxy, singleton);
          }
      
          /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
          function proxyRuntimeCode() public pure returns (bytes memory) {
              return type(GnosisSafeProxy).runtimeCode;
          }
      
          /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
          function proxyCreationCode() public pure returns (bytes memory) {
              return type(GnosisSafeProxy).creationCode;
          }
      
          /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
          ///      This method is only meant as an utility to be called from other methods
          /// @param _singleton Address of singleton contract.
          /// @param initializer Payload for message call sent to new proxy contract.
          /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
          function deployProxyWithNonce(
              address _singleton,
              bytes memory initializer,
              uint256 saltNonce
          ) internal returns (GnosisSafeProxy proxy) {
              // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
              bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
              bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
              }
              require(address(proxy) != address(0), "Create2 call failed");
          }
      
          /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
          /// @param _singleton Address of singleton contract.
          /// @param initializer Payload for message call sent to new proxy contract.
          /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
          function createProxyWithNonce(
              address _singleton,
              bytes memory initializer,
              uint256 saltNonce
          ) public returns (GnosisSafeProxy proxy) {
              proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
              if (initializer.length > 0)
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
                          revert(0, 0)
                      }
                  }
              emit ProxyCreation(proxy, _singleton);
          }
      
          /// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
          /// @param _singleton Address of singleton contract.
          /// @param initializer Payload for message call sent to new proxy contract.
          /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
          /// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
          function createProxyWithCallback(
              address _singleton,
              bytes memory initializer,
              uint256 saltNonce,
              IProxyCreationCallback callback
          ) public returns (GnosisSafeProxy proxy) {
              uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
              proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
              if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
          }
      
          /// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
          ///      This method is only meant for address calculation purpose when you use an initializer that would revert,
          ///      therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
          /// @param _singleton Address of singleton contract.
          /// @param initializer Payload for message call sent to new proxy contract.
          /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
          function calculateCreateProxyWithNonceAddress(
              address _singleton,
              bytes calldata initializer,
              uint256 saltNonce
          ) external returns (GnosisSafeProxy proxy) {
              proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
              revert(string(abi.encodePacked(proxy)));
          }
      }
      
      interface IProxyCreationCallback {
          function proxyCreated(
              GnosisSafeProxy proxy,
              address _singleton,
              bytes calldata initializer,
              uint256 saltNonce
          ) external;
      }

      File 2 of 3: GnosisSafe
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "./base/ModuleManager.sol";
      import "./base/OwnerManager.sol";
      import "./base/FallbackManager.sol";
      import "./base/GuardManager.sol";
      import "./common/EtherPaymentFallback.sol";
      import "./common/Singleton.sol";
      import "./common/SignatureDecoder.sol";
      import "./common/SecuredTokenTransfer.sol";
      import "./common/StorageAccessible.sol";
      import "./interfaces/ISignatureValidator.sol";
      import "./external/GnosisSafeMath.sol";
      /// @title Gnosis Safe - A multisignature wallet with support for confirmations using signed messages based on ERC191.
      /// @author Stefan George - <[email protected]>
      /// @author Richard Meissner - <[email protected]>
      contract GnosisSafe is
          EtherPaymentFallback,
          Singleton,
          ModuleManager,
          OwnerManager,
          SignatureDecoder,
          SecuredTokenTransfer,
          ISignatureValidatorConstants,
          FallbackManager,
          StorageAccessible,
          GuardManager
      {
          using GnosisSafeMath for uint256;
          string public constant VERSION = "1.3.0";
          // keccak256(
          //     "EIP712Domain(uint256 chainId,address verifyingContract)"
          // );
          bytes32 private constant DOMAIN_SEPARATOR_TYPEHASH = 0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218;
          // keccak256(
          //     "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
          // );
          bytes32 private constant SAFE_TX_TYPEHASH = 0xbb8310d486368db6bd6f849402fdd73ad53d316b5a4b2644ad6efe0f941286d8;
          event SafeSetup(address indexed initiator, address[] owners, uint256 threshold, address initializer, address fallbackHandler);
          event ApproveHash(bytes32 indexed approvedHash, address indexed owner);
          event SignMsg(bytes32 indexed msgHash);
          event ExecutionFailure(bytes32 txHash, uint256 payment);
          event ExecutionSuccess(bytes32 txHash, uint256 payment);
          uint256 public nonce;
          bytes32 private _deprecatedDomainSeparator;
          // Mapping to keep track of all message hashes that have been approve by ALL REQUIRED owners
          mapping(bytes32 => uint256) public signedMessages;
          // Mapping to keep track of all hashes (message or transaction) that have been approve by ANY owners
          mapping(address => mapping(bytes32 => uint256)) public approvedHashes;
          // This constructor ensures that this contract can only be used as a master copy for Proxy contracts
          constructor() {
              // By setting the threshold it is not possible to call setup anymore,
              // so we create a Safe with 0 owners and threshold 1.
              // This is an unusable Safe, perfect for the singleton
              threshold = 1;
          }
          /// @dev Setup function sets initial storage of contract.
          /// @param _owners List of Safe owners.
          /// @param _threshold Number of required confirmations for a Safe transaction.
          /// @param to Contract address for optional delegate call.
          /// @param data Data payload for optional delegate call.
          /// @param fallbackHandler Handler for fallback calls to this contract
          /// @param paymentToken Token that should be used for the payment (0 is ETH)
          /// @param payment Value that should be paid
          /// @param paymentReceiver Adddress that should receive the payment (or 0 if tx.origin)
          function setup(
              address[] calldata _owners,
              uint256 _threshold,
              address to,
              bytes calldata data,
              address fallbackHandler,
              address paymentToken,
              uint256 payment,
              address payable paymentReceiver
          ) external {
              // setupOwners checks if the Threshold is already set, therefore preventing that this method is called twice
              setupOwners(_owners, _threshold);
              if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);
              // As setupOwners can only be called if the contract has not been initialized we don't need a check for setupModules
              setupModules(to, data);
              if (payment > 0) {
                  // To avoid running into issues with EIP-170 we reuse the handlePayment function (to avoid adjusting code of that has been verified we do not adjust the method itself)
                  // baseGas = 0, gasPrice = 1 and gas = payment => amount = (payment + 0) * 1 = payment
                  handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
              }
              emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
          }
          /// @dev Allows to execute a Safe transaction confirmed by required number of owners and then pays the account that submitted the transaction.
          ///      Note: The fees are always transferred, even if the user transaction fails.
          /// @param to Destination address of Safe transaction.
          /// @param value Ether value of Safe transaction.
          /// @param data Data payload of Safe transaction.
          /// @param operation Operation type of Safe transaction.
          /// @param safeTxGas Gas that should be used for the Safe transaction.
          /// @param baseGas Gas costs that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
          /// @param gasPrice Gas price that should be used for the payment calculation.
          /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
          /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
          /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})
          function execTransaction(
              address to,
              uint256 value,
              bytes calldata data,
              Enum.Operation operation,
              uint256 safeTxGas,
              uint256 baseGas,
              uint256 gasPrice,
              address gasToken,
              address payable refundReceiver,
              bytes memory signatures
          ) public payable virtual returns (bool success) {
              bytes32 txHash;
              // Use scope here to limit variable lifetime and prevent `stack too deep` errors
              {
                  bytes memory txHashData =
                      encodeTransactionData(
                          // Transaction info
                          to,
                          value,
                          data,
                          operation,
                          safeTxGas,
                          // Payment info
                          baseGas,
                          gasPrice,
                          gasToken,
                          refundReceiver,
                          // Signature info
                          nonce
                      );
                  // Increase nonce and execute transaction.
                  nonce++;
                  txHash = keccak256(txHashData);
                  checkSignatures(txHash, txHashData, signatures);
              }
              address guard = getGuard();
              {
                  if (guard != address(0)) {
                      Guard(guard).checkTransaction(
                          // Transaction info
                          to,
                          value,
                          data,
                          operation,
                          safeTxGas,
                          // Payment info
                          baseGas,
                          gasPrice,
                          gasToken,
                          refundReceiver,
                          // Signature info
                          signatures,
                          msg.sender
                      );
                  }
              }
              // We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500)
              // We also include the 1/64 in the check that is not send along with a call to counteract potential shortings because of EIP-150
              require(gasleft() >= ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500, "GS010");
              // Use scope here to limit variable lifetime and prevent `stack too deep` errors
              {
                  uint256 gasUsed = gasleft();
                  // If the gasPrice is 0 we assume that nearly all available gas can be used (it is always more than safeTxGas)
                  // We only substract 2500 (compared to the 3000 before) to ensure that the amount passed is still higher than safeTxGas
                  success = execute(to, value, data, operation, gasPrice == 0 ? (gasleft() - 2500) : safeTxGas);
                  gasUsed = gasUsed.sub(gasleft());
                  // If no safeTxGas and no gasPrice was set (e.g. both are 0), then the internal tx is required to be successful
                  // This makes it possible to use `estimateGas` without issues, as it searches for the minimum gas where the tx doesn't revert
                  require(success || safeTxGas != 0 || gasPrice != 0, "GS013");
                  // We transfer the calculated tx costs to the tx.origin to avoid sending it to intermediate contracts that have made calls
                  uint256 payment = 0;
                  if (gasPrice > 0) {
                      payment = handlePayment(gasUsed, baseGas, gasPrice, gasToken, refundReceiver);
                  }
                  if (success) emit ExecutionSuccess(txHash, payment);
                  else emit ExecutionFailure(txHash, payment);
              }
              {
                  if (guard != address(0)) {
                      Guard(guard).checkAfterExecution(txHash, success);
                  }
              }
          }
          function handlePayment(
              uint256 gasUsed,
              uint256 baseGas,
              uint256 gasPrice,
              address gasToken,
              address payable refundReceiver
          ) private returns (uint256 payment) {
              // solhint-disable-next-line avoid-tx-origin
              address payable receiver = refundReceiver == address(0) ? payable(tx.origin) : refundReceiver;
              if (gasToken == address(0)) {
                  // For ETH we will only adjust the gas price to not be higher than the actual used gas price
                  payment = gasUsed.add(baseGas).mul(gasPrice < tx.gasprice ? gasPrice : tx.gasprice);
                  require(receiver.send(payment), "GS011");
              } else {
                  payment = gasUsed.add(baseGas).mul(gasPrice);
                  require(transferToken(gasToken, receiver, payment), "GS012");
              }
          }
          /**
           * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
           * @param dataHash Hash of the data (could be either a message hash or transaction hash)
           * @param data That should be signed (this is passed to an external validator contract)
           * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
           */
          function checkSignatures(
              bytes32 dataHash,
              bytes memory data,
              bytes memory signatures
          ) public view {
              // Load threshold to avoid multiple storage loads
              uint256 _threshold = threshold;
              // Check that a threshold is set
              require(_threshold > 0, "GS001");
              checkNSignatures(dataHash, data, signatures, _threshold);
          }
          /**
           * @dev Checks whether the signature provided is valid for the provided data, hash. Will revert otherwise.
           * @param dataHash Hash of the data (could be either a message hash or transaction hash)
           * @param data That should be signed (this is passed to an external validator contract)
           * @param signatures Signature data that should be verified. Can be ECDSA signature, contract signature (EIP-1271) or approved hash.
           * @param requiredSignatures Amount of required valid signatures.
           */
          function checkNSignatures(
              bytes32 dataHash,
              bytes memory data,
              bytes memory signatures,
              uint256 requiredSignatures
          ) public view {
              // Check that the provided signature data is not too short
              require(signatures.length >= requiredSignatures.mul(65), "GS020");
              // There cannot be an owner with address 0.
              address lastOwner = address(0);
              address currentOwner;
              uint8 v;
              bytes32 r;
              bytes32 s;
              uint256 i;
              for (i = 0; i < requiredSignatures; i++) {
                  (v, r, s) = signatureSplit(signatures, i);
                  if (v == 0) {
                      // If v is 0 then it is a contract signature
                      // When handling contract signatures the address of the contract is encoded into r
                      currentOwner = address(uint160(uint256(r)));
                      // Check that signature data pointer (s) is not pointing inside the static part of the signatures bytes
                      // This check is not completely accurate, since it is possible that more signatures than the threshold are send.
                      // Here we only check that the pointer is not pointing inside the part that is being processed
                      require(uint256(s) >= requiredSignatures.mul(65), "GS021");
                      // Check that signature data pointer (s) is in bounds (points to the length of data -> 32 bytes)
                      require(uint256(s).add(32) <= signatures.length, "GS022");
                      // Check if the contract signature is in bounds: start of data is s + 32 and end is start + signature length
                      uint256 contractSignatureLen;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          contractSignatureLen := mload(add(add(signatures, s), 0x20))
                      }
                      require(uint256(s).add(32).add(contractSignatureLen) <= signatures.length, "GS023");
                      // Check signature
                      bytes memory contractSignature;
                      // solhint-disable-next-line no-inline-assembly
                      assembly {
                          // The signature data for contract signatures is appended to the concatenated signatures and the offset is stored in s
                          contractSignature := add(add(signatures, s), 0x20)
                      }
                      require(ISignatureValidator(currentOwner).isValidSignature(data, contractSignature) == EIP1271_MAGIC_VALUE, "GS024");
                  } else if (v == 1) {
                      // If v is 1 then it is an approved hash
                      // When handling approved hashes the address of the approver is encoded into r
                      currentOwner = address(uint160(uint256(r)));
                      // Hashes are automatically approved by the sender of the message or when they have been pre-approved via a separate transaction
                      require(msg.sender == currentOwner || approvedHashes[currentOwner][dataHash] != 0, "GS025");
                  } else if (v > 30) {
                      // If v > 30 then default va (27,28) has been adjusted for eth_sign flow
                      // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before applying ecrecover
                      currentOwner = ecrecover(keccak256(abi.encodePacked("\\x19Ethereum Signed Message:\
      32", dataHash)), v - 4, r, s);
                  } else {
                      // Default is the ecrecover flow with the provided data hash
                      // Use ecrecover with the messageHash for EOA signatures
                      currentOwner = ecrecover(dataHash, v, r, s);
                  }
                  require(currentOwner > lastOwner && owners[currentOwner] != address(0) && currentOwner != SENTINEL_OWNERS, "GS026");
                  lastOwner = currentOwner;
              }
          }
          /// @dev Allows to estimate a Safe transaction.
          ///      This method is only meant for estimation purpose, therefore the call will always revert and encode the result in the revert data.
          ///      Since the `estimateGas` function includes refunds, call this method to get an estimated of the costs that are deducted from the safe with `execTransaction`
          /// @param to Destination address of Safe transaction.
          /// @param value Ether value of Safe transaction.
          /// @param data Data payload of Safe transaction.
          /// @param operation Operation type of Safe transaction.
          /// @return Estimate without refunds and overhead fees (base transaction and payload data gas costs).
          /// @notice Deprecated in favor of common/StorageAccessible.sol and will be removed in next version.
          function requiredTxGas(
              address to,
              uint256 value,
              bytes calldata data,
              Enum.Operation operation
          ) external returns (uint256) {
              uint256 startGas = gasleft();
              // We don't provide an error message here, as we use it to return the estimate
              require(execute(to, value, data, operation, gasleft()));
              uint256 requiredGas = startGas - gasleft();
              // Convert response to string and return via error message
              revert(string(abi.encodePacked(requiredGas)));
          }
          /**
           * @dev Marks a hash as approved. This can be used to validate a hash that is used by a signature.
           * @param hashToApprove The hash that should be marked as approved for signatures that are verified by this contract.
           */
          function approveHash(bytes32 hashToApprove) external {
              require(owners[msg.sender] != address(0), "GS030");
              approvedHashes[msg.sender][hashToApprove] = 1;
              emit ApproveHash(hashToApprove, msg.sender);
          }
          /// @dev Returns the chain id used by this contract.
          function getChainId() public view returns (uint256) {
              uint256 id;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  id := chainid()
              }
              return id;
          }
          function domainSeparator() public view returns (bytes32) {
              return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, getChainId(), this));
          }
          /// @dev Returns the bytes that are hashed to be signed by owners.
          /// @param to Destination address.
          /// @param value Ether value.
          /// @param data Data payload.
          /// @param operation Operation type.
          /// @param safeTxGas Gas that should be used for the safe transaction.
          /// @param baseGas Gas costs for that are independent of the transaction execution(e.g. base transaction fee, signature check, payment of the refund)
          /// @param gasPrice Maximum gas price that should be used for this transaction.
          /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
          /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
          /// @param _nonce Transaction nonce.
          /// @return Transaction hash bytes.
          function encodeTransactionData(
              address to,
              uint256 value,
              bytes calldata data,
              Enum.Operation operation,
              uint256 safeTxGas,
              uint256 baseGas,
              uint256 gasPrice,
              address gasToken,
              address refundReceiver,
              uint256 _nonce
          ) public view returns (bytes memory) {
              bytes32 safeTxHash =
                  keccak256(
                      abi.encode(
                          SAFE_TX_TYPEHASH,
                          to,
                          value,
                          keccak256(data),
                          operation,
                          safeTxGas,
                          baseGas,
                          gasPrice,
                          gasToken,
                          refundReceiver,
                          _nonce
                      )
                  );
              return abi.encodePacked(bytes1(0x19), bytes1(0x01), domainSeparator(), safeTxHash);
          }
          /// @dev Returns hash to be signed by owners.
          /// @param to Destination address.
          /// @param value Ether value.
          /// @param data Data payload.
          /// @param operation Operation type.
          /// @param safeTxGas Fas that should be used for the safe transaction.
          /// @param baseGas Gas costs for data used to trigger the safe transaction.
          /// @param gasPrice Maximum gas price that should be used for this transaction.
          /// @param gasToken Token address (or 0 if ETH) that is used for the payment.
          /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).
          /// @param _nonce Transaction nonce.
          /// @return Transaction hash.
          function getTransactionHash(
              address to,
              uint256 value,
              bytes calldata data,
              Enum.Operation operation,
              uint256 safeTxGas,
              uint256 baseGas,
              uint256 gasPrice,
              address gasToken,
              address refundReceiver,
              uint256 _nonce
          ) public view returns (bytes32) {
              return keccak256(encodeTransactionData(to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, _nonce));
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "../common/Enum.sol";
      /// @title Executor - A contract that can execute transactions
      /// @author Richard Meissner - <[email protected]>
      contract Executor {
          function execute(
              address to,
              uint256 value,
              bytes memory data,
              Enum.Operation operation,
              uint256 txGas
          ) internal returns (bool success) {
              if (operation == Enum.Operation.DelegateCall) {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)
                  }
              } else {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
                  }
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "../common/SelfAuthorized.sol";
      /// @title Fallback Manager - A contract that manages fallback calls made to this contract
      /// @author Richard Meissner - <[email protected]>
      contract FallbackManager is SelfAuthorized {
          event ChangedFallbackHandler(address handler);
          // keccak256("fallback_manager.handler.address")
          bytes32 internal constant FALLBACK_HANDLER_STORAGE_SLOT = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5;
          function internalSetFallbackHandler(address handler) internal {
              bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  sstore(slot, handler)
              }
          }
          /// @dev Allows to add a contract to handle fallback calls.
          ///      Only fallback calls without value and with data will be forwarded.
          ///      This can only be done via a Safe transaction.
          /// @param handler contract to handle fallbacks calls.
          function setFallbackHandler(address handler) public authorized {
              internalSetFallbackHandler(handler);
              emit ChangedFallbackHandler(handler);
          }
          // solhint-disable-next-line payable-fallback,no-complex-fallback
          fallback() external {
              bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let handler := sload(slot)
                  if iszero(handler) {
                      return(0, 0)
                  }
                  calldatacopy(0, 0, calldatasize())
                  // The msg.sender address is shifted to the left by 12 bytes to remove the padding
                  // Then the address without padding is stored right after the calldata
                  mstore(calldatasize(), shl(96, caller()))
                  // Add 20 bytes for the address appended add the end
                  let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
                  returndatacopy(0, 0, returndatasize())
                  if iszero(success) {
                      revert(0, returndatasize())
                  }
                  return(0, returndatasize())
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "../common/Enum.sol";
      import "../common/SelfAuthorized.sol";
      interface Guard {
          function checkTransaction(
              address to,
              uint256 value,
              bytes memory data,
              Enum.Operation operation,
              uint256 safeTxGas,
              uint256 baseGas,
              uint256 gasPrice,
              address gasToken,
              address payable refundReceiver,
              bytes memory signatures,
              address msgSender
          ) external;
          function checkAfterExecution(bytes32 txHash, bool success) external;
      }
      /// @title Fallback Manager - A contract that manages fallback calls made to this contract
      /// @author Richard Meissner - <[email protected]>
      contract GuardManager is SelfAuthorized {
          event ChangedGuard(address guard);
          // keccak256("guard_manager.guard.address")
          bytes32 internal constant GUARD_STORAGE_SLOT = 0x4a204f620c8c5ccdca3fd54d003badd85ba500436a431f0cbda4f558c93c34c8;
          /// @dev Set a guard that checks transactions before execution
          /// @param guard The address of the guard to be used or the 0 address to disable the guard
          function setGuard(address guard) external authorized {
              bytes32 slot = GUARD_STORAGE_SLOT;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  sstore(slot, guard)
              }
              emit ChangedGuard(guard);
          }
          function getGuard() internal view returns (address guard) {
              bytes32 slot = GUARD_STORAGE_SLOT;
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  guard := sload(slot)
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "../common/Enum.sol";
      import "../common/SelfAuthorized.sol";
      import "./Executor.sol";
      /// @title Module Manager - A contract that manages modules that can execute transactions via this contract
      /// @author Stefan George - <[email protected]>
      /// @author Richard Meissner - <[email protected]>
      contract ModuleManager is SelfAuthorized, Executor {
          event EnabledModule(address module);
          event DisabledModule(address module);
          event ExecutionFromModuleSuccess(address indexed module);
          event ExecutionFromModuleFailure(address indexed module);
          address internal constant SENTINEL_MODULES = address(0x1);
          mapping(address => address) internal modules;
          function setupModules(address to, bytes memory data) internal {
              require(modules[SENTINEL_MODULES] == address(0), "GS100");
              modules[SENTINEL_MODULES] = SENTINEL_MODULES;
              if (to != address(0))
                  // Setup has to complete successfully or transaction fails.
                  require(execute(to, 0, data, Enum.Operation.DelegateCall, gasleft()), "GS000");
          }
          /// @dev Allows to add a module to the whitelist.
          ///      This can only be done via a Safe transaction.
          /// @notice Enables the module `module` for the Safe.
          /// @param module Module to be whitelisted.
          function enableModule(address module) public authorized {
              // Module address cannot be null or sentinel.
              require(module != address(0) && module != SENTINEL_MODULES, "GS101");
              // Module cannot be added twice.
              require(modules[module] == address(0), "GS102");
              modules[module] = modules[SENTINEL_MODULES];
              modules[SENTINEL_MODULES] = module;
              emit EnabledModule(module);
          }
          /// @dev Allows to remove a module from the whitelist.
          ///      This can only be done via a Safe transaction.
          /// @notice Disables the module `module` for the Safe.
          /// @param prevModule Module that pointed to the module to be removed in the linked list
          /// @param module Module to be removed.
          function disableModule(address prevModule, address module) public authorized {
              // Validate module address and check that it corresponds to module index.
              require(module != address(0) && module != SENTINEL_MODULES, "GS101");
              require(modules[prevModule] == module, "GS103");
              modules[prevModule] = modules[module];
              modules[module] = address(0);
              emit DisabledModule(module);
          }
          /// @dev Allows a Module to execute a Safe transaction without any further confirmations.
          /// @param to Destination address of module transaction.
          /// @param value Ether value of module transaction.
          /// @param data Data payload of module transaction.
          /// @param operation Operation type of module transaction.
          function execTransactionFromModule(
              address to,
              uint256 value,
              bytes memory data,
              Enum.Operation operation
          ) public virtual returns (bool success) {
              // Only whitelisted modules are allowed.
              require(msg.sender != SENTINEL_MODULES && modules[msg.sender] != address(0), "GS104");
              // Execute transaction without further confirmations.
              success = execute(to, value, data, operation, gasleft());
              if (success) emit ExecutionFromModuleSuccess(msg.sender);
              else emit ExecutionFromModuleFailure(msg.sender);
          }
          /// @dev Allows a Module to execute a Safe transaction without any further confirmations and return data
          /// @param to Destination address of module transaction.
          /// @param value Ether value of module transaction.
          /// @param data Data payload of module transaction.
          /// @param operation Operation type of module transaction.
          function execTransactionFromModuleReturnData(
              address to,
              uint256 value,
              bytes memory data,
              Enum.Operation operation
          ) public returns (bool success, bytes memory returnData) {
              success = execTransactionFromModule(to, value, data, operation);
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  // Load free memory location
                  let ptr := mload(0x40)
                  // We allocate memory for the return data by setting the free memory location to
                  // current free memory location + data size + 32 bytes for data size value
                  mstore(0x40, add(ptr, add(returndatasize(), 0x20)))
                  // Store the size
                  mstore(ptr, returndatasize())
                  // Store the data
                  returndatacopy(add(ptr, 0x20), 0, returndatasize())
                  // Point the return data to the correct memory location
                  returnData := ptr
              }
          }
          /// @dev Returns if an module is enabled
          /// @return True if the module is enabled
          function isModuleEnabled(address module) public view returns (bool) {
              return SENTINEL_MODULES != module && modules[module] != address(0);
          }
          /// @dev Returns array of modules.
          /// @param start Start of the page.
          /// @param pageSize Maximum number of modules that should be returned.
          /// @return array Array of modules.
          /// @return next Start of the next page.
          function getModulesPaginated(address start, uint256 pageSize) external view returns (address[] memory array, address next) {
              // Init array with max page size
              array = new address[](pageSize);
              // Populate return array
              uint256 moduleCount = 0;
              address currentModule = modules[start];
              while (currentModule != address(0x0) && currentModule != SENTINEL_MODULES && moduleCount < pageSize) {
                  array[moduleCount] = currentModule;
                  currentModule = modules[currentModule];
                  moduleCount++;
              }
              next = currentModule;
              // Set correct size of returned array
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  mstore(array, moduleCount)
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      import "../common/SelfAuthorized.sol";
      /// @title OwnerManager - Manages a set of owners and a threshold to perform actions.
      /// @author Stefan George - <[email protected]>
      /// @author Richard Meissner - <[email protected]>
      contract OwnerManager is SelfAuthorized {
          event AddedOwner(address owner);
          event RemovedOwner(address owner);
          event ChangedThreshold(uint256 threshold);
          address internal constant SENTINEL_OWNERS = address(0x1);
          mapping(address => address) internal owners;
          uint256 internal ownerCount;
          uint256 internal threshold;
          /// @dev Setup function sets initial storage of contract.
          /// @param _owners List of Safe owners.
          /// @param _threshold Number of required confirmations for a Safe transaction.
          function setupOwners(address[] memory _owners, uint256 _threshold) internal {
              // Threshold can only be 0 at initialization.
              // Check ensures that setup function can only be called once.
              require(threshold == 0, "GS200");
              // Validate that threshold is smaller than number of added owners.
              require(_threshold <= _owners.length, "GS201");
              // There has to be at least one Safe owner.
              require(_threshold >= 1, "GS202");
              // Initializing Safe owners.
              address currentOwner = SENTINEL_OWNERS;
              for (uint256 i = 0; i < _owners.length; i++) {
                  // Owner address cannot be null.
                  address owner = _owners[i];
                  require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this) && currentOwner != owner, "GS203");
                  // No duplicate owners allowed.
                  require(owners[owner] == address(0), "GS204");
                  owners[currentOwner] = owner;
                  currentOwner = owner;
              }
              owners[currentOwner] = SENTINEL_OWNERS;
              ownerCount = _owners.length;
              threshold = _threshold;
          }
          /// @dev Allows to add a new owner to the Safe and update the threshold at the same time.
          ///      This can only be done via a Safe transaction.
          /// @notice Adds the owner `owner` to the Safe and updates the threshold to `_threshold`.
          /// @param owner New owner address.
          /// @param _threshold New threshold.
          function addOwnerWithThreshold(address owner, uint256 _threshold) public authorized {
              // Owner address cannot be null, the sentinel or the Safe itself.
              require(owner != address(0) && owner != SENTINEL_OWNERS && owner != address(this), "GS203");
              // No duplicate owners allowed.
              require(owners[owner] == address(0), "GS204");
              owners[owner] = owners[SENTINEL_OWNERS];
              owners[SENTINEL_OWNERS] = owner;
              ownerCount++;
              emit AddedOwner(owner);
              // Change threshold if threshold was changed.
              if (threshold != _threshold) changeThreshold(_threshold);
          }
          /// @dev Allows to remove an owner from the Safe and update the threshold at the same time.
          ///      This can only be done via a Safe transaction.
          /// @notice Removes the owner `owner` from the Safe and updates the threshold to `_threshold`.
          /// @param prevOwner Owner that pointed to the owner to be removed in the linked list
          /// @param owner Owner address to be removed.
          /// @param _threshold New threshold.
          function removeOwner(
              address prevOwner,
              address owner,
              uint256 _threshold
          ) public authorized {
              // Only allow to remove an owner, if threshold can still be reached.
              require(ownerCount - 1 >= _threshold, "GS201");
              // Validate owner address and check that it corresponds to owner index.
              require(owner != address(0) && owner != SENTINEL_OWNERS, "GS203");
              require(owners[prevOwner] == owner, "GS205");
              owners[prevOwner] = owners[owner];
              owners[owner] = address(0);
              ownerCount--;
              emit RemovedOwner(owner);
              // Change threshold if threshold was changed.
              if (threshold != _threshold) changeThreshold(_threshold);
          }
          /// @dev Allows to swap/replace an owner from the Safe with another address.
          ///      This can only be done via a Safe transaction.
          /// @notice Replaces the owner `oldOwner` in the Safe with `newOwner`.
          /// @param prevOwner Owner that pointed to the owner to be replaced in the linked list
          /// @param oldOwner Owner address to be replaced.
          /// @param newOwner New owner address.
          function swapOwner(
              address prevOwner,
              address oldOwner,
              address newOwner
          ) public authorized {
              // Owner address cannot be null, the sentinel or the Safe itself.
              require(newOwner != address(0) && newOwner != SENTINEL_OWNERS && newOwner != address(this), "GS203");
              // No duplicate owners allowed.
              require(owners[newOwner] == address(0), "GS204");
              // Validate oldOwner address and check that it corresponds to owner index.
              require(oldOwner != address(0) && oldOwner != SENTINEL_OWNERS, "GS203");
              require(owners[prevOwner] == oldOwner, "GS205");
              owners[newOwner] = owners[oldOwner];
              owners[prevOwner] = newOwner;
              owners[oldOwner] = address(0);
              emit RemovedOwner(oldOwner);
              emit AddedOwner(newOwner);
          }
          /// @dev Allows to update the number of required confirmations by Safe owners.
          ///      This can only be done via a Safe transaction.
          /// @notice Changes the threshold of the Safe to `_threshold`.
          /// @param _threshold New threshold.
          function changeThreshold(uint256 _threshold) public authorized {
              // Validate that threshold is smaller than number of owners.
              require(_threshold <= ownerCount, "GS201");
              // There has to be at least one Safe owner.
              require(_threshold >= 1, "GS202");
              threshold = _threshold;
              emit ChangedThreshold(threshold);
          }
          function getThreshold() public view returns (uint256) {
              return threshold;
          }
          function isOwner(address owner) public view returns (bool) {
              return owner != SENTINEL_OWNERS && owners[owner] != address(0);
          }
          /// @dev Returns array of owners.
          /// @return Array of Safe owners.
          function getOwners() public view returns (address[] memory) {
              address[] memory array = new address[](ownerCount);
              // populate return array
              uint256 index = 0;
              address currentOwner = owners[SENTINEL_OWNERS];
              while (currentOwner != SENTINEL_OWNERS) {
                  array[index] = currentOwner;
                  currentOwner = owners[currentOwner];
                  index++;
              }
              return array;
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title Enum - Collection of enums
      /// @author Richard Meissner - <[email protected]>
      contract Enum {
          enum Operation {Call, DelegateCall}
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title EtherPaymentFallback - A contract that has a fallback to accept ether payments
      /// @author Richard Meissner - <[email protected]>
      contract EtherPaymentFallback {
          event SafeReceived(address indexed sender, uint256 value);
          /// @dev Fallback function accepts Ether transactions.
          receive() external payable {
              emit SafeReceived(msg.sender, msg.value);
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title SecuredTokenTransfer - Secure token transfer
      /// @author Richard Meissner - <[email protected]>
      contract SecuredTokenTransfer {
          /// @dev Transfers a token and returns if it was a success
          /// @param token Token that should be transferred
          /// @param receiver Receiver to whom the token should be transferred
          /// @param amount The amount of tokens that should be transferred
          function transferToken(
              address token,
              address receiver,
              uint256 amount
          ) internal returns (bool transferred) {
              // 0xa9059cbb - keccack("transfer(address,uint256)")
              bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount);
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  // We write the return value to scratch space.
                  // See https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory
                  let success := call(sub(gas(), 10000), token, 0, add(data, 0x20), mload(data), 0, 0x20)
                  switch returndatasize()
                      case 0 {
                          transferred := success
                      }
                      case 0x20 {
                          transferred := iszero(or(iszero(success), iszero(mload(0))))
                      }
                      default {
                          transferred := 0
                      }
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title SelfAuthorized - authorizes current contract to perform actions
      /// @author Richard Meissner - <[email protected]>
      contract SelfAuthorized {
          function requireSelfCall() private view {
              require(msg.sender == address(this), "GS031");
          }
          modifier authorized() {
              // This is a function call as it minimized the bytecode size
              requireSelfCall();
              _;
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title SignatureDecoder - Decodes signatures that a encoded as bytes
      /// @author Richard Meissner - <[email protected]>
      contract SignatureDecoder {
          /// @dev divides bytes signature into `uint8 v, bytes32 r, bytes32 s`.
          /// @notice Make sure to peform a bounds check for @param pos, to avoid out of bounds access on @param signatures
          /// @param pos which signature to read. A prior bounds check of this parameter should be performed, to avoid out of bounds access
          /// @param signatures concatenated rsv signatures
          function signatureSplit(bytes memory signatures, uint256 pos)
              internal
              pure
              returns (
                  uint8 v,
                  bytes32 r,
                  bytes32 s
              )
          {
              // The signature format is a compact form of:
              //   {bytes32 r}{bytes32 s}{uint8 v}
              // Compact means, uint8 is not padded to 32 bytes.
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let signaturePos := mul(0x41, pos)
                  r := mload(add(signatures, add(signaturePos, 0x20)))
                  s := mload(add(signatures, add(signaturePos, 0x40)))
                  // Here we are loading the last 32 bytes, including 31 bytes
                  // of 's'. There is no 'mload8' to do this.
                  //
                  // 'byte' is not working due to the Solidity parser, so lets
                  // use the second best option, 'and'
                  v := and(mload(add(signatures, add(signaturePos, 0x41))), 0xff)
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title Singleton - Base for singleton contracts (should always be first super contract)
      ///         This contract is tightly coupled to our proxy contract (see `proxies/GnosisSafeProxy.sol`)
      /// @author Richard Meissner - <[email protected]>
      contract Singleton {
          // singleton always needs to be first declared variable, to ensure that it is at the same location as in the Proxy contract.
          // It should also always be ensured that the address is stored alone (uses a full word)
          address private singleton;
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /// @title StorageAccessible - generic base contract that allows callers to access all internal storage.
      /// @notice See https://github.com/gnosis/util-contracts/blob/bb5fe5fb5df6d8400998094fb1b32a178a47c3a1/contracts/StorageAccessible.sol
      contract StorageAccessible {
          /**
           * @dev Reads `length` bytes of storage in the currents contract
           * @param offset - the offset in the current contract's storage in words to start reading from
           * @param length - the number of words (32 bytes) of data to read
           * @return the bytes that were read.
           */
          function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) {
              bytes memory result = new bytes(length * 32);
              for (uint256 index = 0; index < length; index++) {
                  // solhint-disable-next-line no-inline-assembly
                  assembly {
                      let word := sload(add(offset, index))
                      mstore(add(add(result, 0x20), mul(index, 0x20)), word)
                  }
              }
              return result;
          }
          /**
           * @dev Performs a delegetecall on a targetContract in the context of self.
           * Internally reverts execution to avoid side effects (making it static).
           *
           * This method reverts with data equal to `abi.encode(bool(success), bytes(response))`.
           * Specifically, the `returndata` after a call to this method will be:
           * `success:bool || response.length:uint256 || response:bytes`.
           *
           * @param targetContract Address of the contract containing the code to execute.
           * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments).
           */
          function simulateAndRevert(address targetContract, bytes memory calldataPayload) external {
              // solhint-disable-next-line no-inline-assembly
              assembly {
                  let success := delegatecall(gas(), targetContract, add(calldataPayload, 0x20), mload(calldataPayload), 0, 0)
                  mstore(0x00, success)
                  mstore(0x20, returndatasize())
                  returndatacopy(0x40, 0, returndatasize())
                  revert(0, add(returndatasize(), 0x40))
              }
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      /**
       * @title GnosisSafeMath
       * @dev Math operations with safety checks that revert on error
       * Renamed from SafeMath to GnosisSafeMath to avoid conflicts
       * TODO: remove once open zeppelin update to solc 0.5.0
       */
      library GnosisSafeMath {
          /**
           * @dev Multiplies two numbers, reverts on 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-solidity/pull/522
              if (a == 0) {
                  return 0;
              }
              uint256 c = a * b;
              require(c / a == b);
              return c;
          }
          /**
           * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              require(b <= a);
              uint256 c = a - b;
              return c;
          }
          /**
           * @dev Adds two numbers, reverts on overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a);
              return c;
          }
          /**
           * @dev Returns the largest of two numbers.
           */
          function max(uint256 a, uint256 b) internal pure returns (uint256) {
              return a >= b ? a : b;
          }
      }
      // SPDX-License-Identifier: LGPL-3.0-only
      pragma solidity >=0.7.0 <0.9.0;
      contract ISignatureValidatorConstants {
          // bytes4(keccak256("isValidSignature(bytes,bytes)")
          bytes4 internal constant EIP1271_MAGIC_VALUE = 0x20c13b0b;
      }
      abstract contract ISignatureValidator is ISignatureValidatorConstants {
          /**
           * @dev Should return whether the signature provided is valid for the provided data
           * @param _data Arbitrary length data signed on the behalf of address(this)
           * @param _signature Signature byte array associated with _data
           *
           * MUST return the bytes4 magic value 0x20c13b0b when function passes.
           * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
           * MUST allow external calls
           */
          function isValidSignature(bytes memory _data, bytes memory _signature) public view virtual returns (bytes4);
      }
      

      File 3 of 3: Chronicle_MOG_USD_1
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity ^0.8.16;
      import {IChronicle} from "chronicle-std/IChronicle.sol";
      import {IScribeOptimistic} from "./IScribeOptimistic.sol";
      import {IScribe} from "./IScribe.sol";
      import {Scribe} from "./Scribe.sol";
      import {LibSchnorr} from "./libs/LibSchnorr.sol";
      import {LibSecp256k1} from "./libs/LibSecp256k1.sol";
      /**
       * @title ScribeOptimistic
       *
       * @notice Scribe based optimistic Oracle with onchain fault resolution
       */
      contract ScribeOptimistic is IScribeOptimistic, Scribe {
          using LibSchnorr for LibSecp256k1.Point;
          using LibSecp256k1 for LibSecp256k1.Point;
          using LibSecp256k1 for LibSecp256k1.Point[];
          // -- Storage --
          /// @inheritdoc IScribeOptimistic
          uint16 public opChallengePeriod;
          /// @inheritdoc IScribeOptimistic
          uint8 public opFeedId;
          /// @dev The truncated hash of the schnorrData provided in last opPoke.
          ///      Binds the opFeed to their schnorrData.
          uint160 internal _schnorrDataCommitment;
          /// @dev The age of the pokeData provided in last opPoke.
          ///      Ensures Schnorr signature can be verified after setting pokeData's
          ///      age to block.timestamp during opPoke.
          uint32 internal _originalOpPokeDataAge;
          /// @dev opScribe's last opPoke'd value and corresponding age.
          PokeData internal _opPokeData;
          /// @inheritdoc IScribeOptimistic
          uint public maxChallengeReward;
          // -- Constructor and Receive Functionality --
          constructor(address initialAuthed, bytes32 wat_)
              payable
              Scribe(initialAuthed, wat_)
          {
              // Note to have a non-zero challenge period.
              _setOpChallengePeriod(20 minutes);
              // Set maxChallengeReward to type(uint).max.
              _setMaxChallengeRewards(type(uint).max);
          }
          receive() external payable {}
          // -- Poke Functionality --
          function _poke(PokeData calldata pokeData, SchnorrData calldata schnorrData)
              internal
              override(Scribe)
          {
              // Load current age from storage.
              uint32 age = _currentPokeData().age;
              // Revert if pokeData stale.
              if (pokeData.age <= age) {
                  revert StaleMessage(pokeData.age, age);
              }
              // Revert if pokeData from the future.
              if (pokeData.age > uint32(block.timestamp)) {
                  revert FutureMessage(pokeData.age, uint32(block.timestamp));
              }
              // Revert if schnorrData does not prove integrity of pokeData.
              bool ok;
              bytes memory err;
              // forgefmt: disable-next-item
              (ok, err) = _verifySchnorrSignature(
                  constructPokeMessage(pokeData),
                  schnorrData
              );
              if (!ok) {
                  _revert(err);
              }
              // Store pokeData's val in _pokeData storage and set its age to now.
              _pokeData.val = pokeData.val;
              _pokeData.age = uint32(block.timestamp);
              emit Poked(msg.sender, pokeData.val, pokeData.age);
          }
          // -- opPoke Functionality --
          /// @dev Optimized function selector: 0x00000000.
          ///      Note that this function is _not_ defined via the IScribeOptimistic
          ///      interface and one should _not_ depend on it.
          function opPoke_optimized_397084999(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData,
              ECDSAData calldata ecdsaData
          ) external payable {
              _opPoke(pokeData, schnorrData, ecdsaData);
          }
          /// @inheritdoc IScribeOptimistic
          function opPoke(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData,
              ECDSAData calldata ecdsaData
          ) external {
              _opPoke(pokeData, schnorrData, ecdsaData);
          }
          function _opPoke(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData,
              ECDSAData calldata ecdsaData
          ) internal {
              // Revert if schnorrData.feedIds' length is higher than bar's maximum
              // value.
              //
              // Note that this prevents opPoke's with such big schnorrData that it
              // becomes economically unprofitable to challenge them.
              if (schnorrData.feedIds.length > type(uint8).max) {
                  revert BarNotReached(type(uint8).max, bar);
              }
              // Load _opPokeData from storage.
              PokeData memory opPokeData = _opPokeData;
              // Decide whether _opPokeData finalized.
              bool opPokeDataFinalized =
                  opPokeData.age + opChallengePeriod <= uint32(block.timestamp);
              // Revert if _opPokeData not finalized, i.e. still challengeable.
              if (!opPokeDataFinalized) {
                  revert InChallengePeriod();
              }
              // Decide current age.
              uint32 age =
                  opPokeData.age > _pokeData.age ? opPokeData.age : _pokeData.age;
              // Revert if pokeData stale.
              if (pokeData.age <= age) {
                  revert StaleMessage(pokeData.age, age);
              }
              // Revert if pokeData from the future.
              if (pokeData.age > uint32(block.timestamp)) {
                  revert FutureMessage(pokeData.age, uint32(block.timestamp));
              }
              // Recover ECDSA signer.
              address signer = ecrecover(
                  _constructOpPokeMessage(pokeData, schnorrData),
                  ecdsaData.v,
                  ecdsaData.r,
                  ecdsaData.s
              );
              // Compute feed id of signer.
              uint8 feedId = uint8(uint(uint160(signer)) >> 152);
              // Revert if signer not feed.
              // assert(_pubKeys[feedId].toAddress() != address(0));
              if (_pubKeys[feedId].toAddress() != signer) {
                  revert SignerNotFeed(signer);
              }
              // Store the feed's id as opFeedId and bind them to their provided
              // schnorrData.
              opFeedId = feedId;
              _schnorrDataCommitment = uint160(
                  uint(
                      keccak256(
                          abi.encodePacked(
                              schnorrData.signature,
                              schnorrData.commitment,
                              schnorrData.feedIds
                          )
                      )
                  )
              );
              // If _opPokeData provides the current val, move it to the _pokeData
              // storage to free _opPokeData storage. If the current val is provided
              // by _pokeData, _opPokeData can be overwritten.
              if (opPokeData.age == age) {
                  _pokeData = opPokeData;
              }
              // Store provided pokeData's val in _opPokeData storage.
              _opPokeData.val = pokeData.val;
              _opPokeData.age = uint32(block.timestamp);
              // Store pokeData's age to allow recreating original pokeMessage.
              _originalOpPokeDataAge = pokeData.age;
              emit OpPoked(msg.sender, signer, schnorrData, pokeData);
          }
          /// @inheritdoc IScribeOptimistic
          function opChallenge(SchnorrData calldata schnorrData)
              external
              returns (bool)
          {
              // Load _opPokeData from storage.
              PokeData memory opPokeData = _opPokeData;
              // Decide whether _opPokeData is challengeable.
              bool opPokeDataChallengeable =
                  opPokeData.age + opChallengePeriod > uint32(block.timestamp);
              // Revert if _opPokeData is not challengeable.
              if (!opPokeDataChallengeable) {
                  revert NoOpPokeToChallenge();
              }
              // Construct truncated hash from schnorrData.
              uint160 schnorrDataHash = uint160(
                  uint(
                      keccak256(
                          abi.encodePacked(
                              schnorrData.signature,
                              schnorrData.commitment,
                              schnorrData.feedIds
                          )
                      )
                  )
              );
              // Revert if schnorrDataHash does not match _schnorrDataCommitment.
              if (schnorrDataHash != _schnorrDataCommitment) {
                  revert SchnorrDataMismatch(schnorrDataHash, _schnorrDataCommitment);
              }
              // Decide whether schnorrData verifies opPokeData.
              bool ok;
              bytes memory err;
              (ok, err) = _verifySchnorrSignature(
                  constructPokeMessage(
                      PokeData({val: opPokeData.val, age: _originalOpPokeDataAge})
                  ),
                  schnorrData
              );
              if (ok) {
                  // Decide whether _opPokeData stale already.
                  bool opPokeDataStale = opPokeData.age <= _pokeData.age;
                  // If _opPokeData not stale, finalize it by moving it to the
                  // _pokeData storage. Note to also clean the _opPokeData storage to
                  // not block new opPoke's as _opPokeData's challenge period not over.
                  if (!opPokeDataStale) {
                      _pokeData = _opPokeData;
                      delete _opPokeData;
                  }
                  emit OpPokeChallengedUnsuccessfully(msg.sender, schnorrData);
              } else {
                  // Drop opFeed and delete invalid _opPokeData.
                  // Note to use address(this) as caller to indicate self-governed
                  // drop of feed.
                  _drop(address(this), opFeedId);
                  // Pay ETH reward to challenger.
                  uint reward = challengeReward();
                  if (_sendETH(payable(msg.sender), reward)) {
                      emit OpChallengeRewardPaid(msg.sender, schnorrData, reward);
                  }
                  emit OpPokeChallengedSuccessfully(msg.sender, schnorrData, err);
              }
              // Return whether challenging was successful.
              return !ok;
          }
          /// @inheritdoc IScribeOptimistic
          function constructOpPokeMessage(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData
          ) external view returns (bytes32) {
              return _constructOpPokeMessage(pokeData, schnorrData);
          }
          function _constructOpPokeMessage(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData
          ) internal view returns (bytes32) {
              return keccak256(
                  abi.encodePacked(
                      "\\x19Ethereum Signed Message:\
      32",
                      keccak256(
                          abi.encodePacked(
                              wat,
                              pokeData.val,
                              pokeData.age,
                              schnorrData.signature,
                              schnorrData.commitment,
                              schnorrData.feedIds
                          )
                      )
                  )
              );
          }
          // -- Toll'ed Read Functionality --
          // - IChronicle Functions
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function read()
              external
              view
              override(IChronicle, Scribe)
              toll
              returns (uint)
          {
              uint val = _currentPokeData().val;
              require(val != 0);
              return val;
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function tryRead()
              external
              view
              override(IChronicle, Scribe)
              toll
              returns (bool, uint)
          {
              uint val = _currentPokeData().val;
              return (val != 0, val);
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function readWithAge()
              external
              view
              override(IChronicle, Scribe)
              toll
              returns (uint, uint)
          {
              PokeData memory pokeData = _currentPokeData();
              require(pokeData.val != 0);
              return (pokeData.val, pokeData.age);
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function tryReadWithAge()
              external
              view
              override(IChronicle, Scribe)
              toll
              returns (bool, uint, uint)
          {
              PokeData memory pokeData = _currentPokeData();
              return pokeData.val != 0
                  ? (true, pokeData.val, pokeData.age)
                  : (false, 0, 0);
          }
          // - MakerDAO Compatibility
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function peek()
              external
              view
              override(IScribe, Scribe)
              toll
              returns (uint, bool)
          {
              uint val = _currentPokeData().val;
              return (val, val != 0);
          }
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function peep()
              external
              view
              override(IScribe, Scribe)
              toll
              returns (uint, bool)
          {
              uint val = _currentPokeData().val;
              return (val, val != 0);
          }
          // - Chainlink Compatibility
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function latestRoundData()
              external
              view
              override(IScribe, Scribe)
              toll
              returns (
                  uint80 roundId,
                  int answer,
                  uint startedAt,
                  uint updatedAt,
                  uint80 answeredInRound
              )
          {
              PokeData memory pokeData = _currentPokeData();
              roundId = 1;
              answer = int(uint(pokeData.val));
              // assert(uint(answer) == uint(pokeData.val));
              startedAt = 0;
              updatedAt = pokeData.age;
              answeredInRound = roundId;
          }
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function latestAnswer()
              external
              view
              virtual
              override(IScribe, Scribe)
              toll
              returns (int)
          {
              uint val = _currentPokeData().val;
              return int(val);
          }
          function _currentPokeData() internal view returns (PokeData memory) {
              // Load pokeData slots from storage.
              PokeData memory pokeData = _pokeData;
              PokeData memory opPokeData = _opPokeData;
              // Decide whether _opPokeData is finalized.
              bool opPokeDataFinalized =
                  opPokeData.age + opChallengePeriod <= uint32(block.timestamp);
              // Decide and return current pokeData.
              if (opPokeDataFinalized && opPokeData.age > pokeData.age) {
                  return opPokeData;
              } else {
                  return pokeData;
              }
          }
          // -- Auth'ed Functionality --
          /// @inheritdoc IScribeOptimistic
          function setOpChallengePeriod(uint16 opChallengePeriod_) external auth {
              _setOpChallengePeriod(opChallengePeriod_);
          }
          function _setOpChallengePeriod(uint16 opChallengePeriod_) internal {
              require(opChallengePeriod_ != 0);
              if (opChallengePeriod != opChallengePeriod_) {
                  emit OpChallengePeriodUpdated(
                      msg.sender, opChallengePeriod, opChallengePeriod_
                  );
                  opChallengePeriod = opChallengePeriod_;
              }
              _afterAuthedAction();
          }
          function _drop(address caller, uint8 feedId) internal override(Scribe) {
              super._drop(caller, feedId);
              _afterAuthedAction();
          }
          function _setBar(uint8 bar_) internal override(Scribe) {
              super._setBar(bar_);
              _afterAuthedAction();
          }
          /// @dev Ensures an auth'ed configuration update does not enable
          ///      successfully challenging a prior to the update valid opPoke.
          ///
          /// @custom:invariant Val is provided if _pokeData prior to the tx is
          ///                   non-empty. Note that this is the case if there were
          ///                   at least two valid calls ∊ {poke, opPoke}.
          ///                     preTx(_pokeData) != (0, 0)
          ///                       → (true, _) = postTx(tryRead())
          /// @custom:invariant Val is provided via _pokeData after the tx.
          ///                     postTx(readWithAge()) = postTx(_pokeData)
          /// @custom:invariant _opPokeData is empty after the tx.
          ///                     (0, 0) = postTx(_opPokeData)
          function _afterAuthedAction() internal {
              // Do nothing during deployment.
              if (address(this).code.length == 0) return;
              // Load _opPokeData from storage.
              PokeData memory opPokeData = _opPokeData;
              // Decide whether _opPokeData is finalized.
              //
              // Note that the decision is based on the possibly updated
              // opChallengePeriod! This means a once finalized opPoke may be dropped
              // if the opChallengePeriod was increased.
              bool opPokeDataFinalized =
                  opPokeData.age + opChallengePeriod <= uint32(block.timestamp);
              // Note that _opPokeData is in one of the following three states:
              // 1. finalized and newer than _pokeData
              // 2. finalized but older than _pokeData
              // 3. non-finalized
              //
              // Note that for state 1 _opPokeData can be moved to _pokeData and
              // afterwards deleted.
              // Note that for state 2 and 3 _opPokeData can be directly deleted.
              // If _opPokeData is in state 1, move it to the _pokeData storage.
              //
              // Note that this ensures the current value is provided via _pokeData.
              if (opPokeDataFinalized && opPokeData.age > _pokeData.age) {
                  _pokeData = opPokeData;
              }
              // If _opPokeData is in state 3, emit event to indicate a possibly valid
              // opPoke was dropped.
              if (!opPokeDataFinalized) {
                  emit OpPokeDataDropped(msg.sender, opPokeData);
              }
              // Now it is safe to delete _opPokeData.
              delete _opPokeData;
              // Note that the current value is now provided via _pokeData.
              // assert(_currentPokeData().val == _pokeData.val);
              // assert(_currentPokeData().age == _pokeData.age);
              // Set the age of contract's current value to block.timestamp.
              //
              // Note that this ensures an already signed, but now possibly invalid
              // with regards to contract configurations, opPoke payload cannot be
              // opPoke'd anymore.
              _pokeData.age = uint32(block.timestamp);
          }
          // -- Searcher Incentivization Logic --
          /// @inheritdoc IScribeOptimistic
          function challengeReward() public view returns (uint) {
              uint balance = address(this).balance;
              return balance > maxChallengeReward ? maxChallengeReward : balance;
          }
          /// @inheritdoc IScribeOptimistic
          function setMaxChallengeReward(uint maxChallengeReward_) external auth {
              _setMaxChallengeRewards(maxChallengeReward_);
          }
          function _setMaxChallengeRewards(uint maxChallengeReward_) internal {
              if (maxChallengeReward != maxChallengeReward_) {
                  emit MaxChallengeRewardUpdated(
                      msg.sender, maxChallengeReward, maxChallengeReward_
                  );
                  maxChallengeReward = maxChallengeReward_;
              }
          }
          function _sendETH(address payable to, uint amount)
              internal
              returns (bool)
          {
              (bool ok,) = to.call{value: amount}("");
              return ok;
          }
      }
      /**
       * @dev Contract overwrite to deploy contract instances with specific naming.
       *
       *      For more info, see docs/Deployment.md.
       */
      contract Chronicle_MOG_USD_1 is ScribeOptimistic {
          constructor(address initialAuthed, bytes32 wat_)
              ScribeOptimistic(initialAuthed, wat_)
          {}
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      /**
       * @title IChronicle
       *
       * @notice Interface for Chronicle Protocol's oracle products
       */
      interface IChronicle {
          /// @notice Returns the oracle's identifier.
          /// @return wat The oracle's identifier.
          function wat() external view returns (bytes32 wat);
          /// @notice Returns the oracle's current value.
          /// @dev Reverts if no value set.
          /// @return value The oracle's current value.
          function read() external view returns (uint value);
          /// @notice Returns the oracle's current value and its age.
          /// @dev Reverts if no value set.
          /// @return value The oracle's current value.
          /// @return age The value's age.
          function readWithAge() external view returns (uint value, uint age);
          /// @notice Returns the oracle's current value.
          /// @return isValid True if value exists, false otherwise.
          /// @return value The oracle's current value if it exists, zero otherwise.
          function tryRead() external view returns (bool isValid, uint value);
          /// @notice Returns the oracle's current value and its age.
          /// @return isValid True if value exists, false otherwise.
          /// @return value The oracle's current value if it exists, zero otherwise.
          /// @return age The value's age if value exists, zero otherwise.
          function tryReadWithAge()
              external
              view
              returns (bool isValid, uint value, uint age);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      import {IScribe} from "./IScribe.sol";
      interface IScribeOptimistic is IScribe {
          /// @notice Thrown if attempted to opPoke while a previous opPoke is still
          ///         in challenge period.
          error InChallengePeriod();
          /// @notice Thrown if opChallenge called while no challengeable opPoke exists.
          error NoOpPokeToChallenge();
          /// @notice Thrown if opChallenge called with SchnorrData not matching
          ///         opPoke's SchnorrData.
          /// @param gotHash The truncated keccak256 hash of the SchnorrData argument.
          /// @param wantHash The truncated expected keccak256 hash of the SchnorrData
          ///                 argument.
          error SchnorrDataMismatch(uint160 gotHash, uint160 wantHash);
          /// @notice Thrown if opPoke called with non-feed ECDSA signature.
          /// @param signer The ECDSA signature's signer.
          error SignerNotFeed(address signer);
          /// @notice Emitted when oracles was successfully opPoked.
          /// @param caller The caller's address.
          /// @param opFeed The feed that signed the opPoke.
          /// @param schnorrData The schnorrData opPoked.
          /// @param pokeData The pokeData opPoked.
          event OpPoked(
              address indexed caller,
              address indexed opFeed,
              IScribe.SchnorrData schnorrData,
              IScribe.PokeData pokeData
          );
          /// @notice Emitted when successfully challenged an opPoke.
          /// @param caller The caller's address.
          /// @param schnorrData The schnorrData challenged.
          /// @param schnorrErr The abi-encoded custom error returned from the failed
          ///                   Schnorr signature verification.
          event OpPokeChallengedSuccessfully(
              address indexed caller,
              IScribe.SchnorrData schnorrData,
              bytes schnorrErr
          );
          /// @notice Emitted when unsuccessfully challenged an opPoke.
          /// @param caller The caller's address.
          /// @param schnorrData The schnorrData challenged.
          event OpPokeChallengedUnsuccessfully(
              address indexed caller, IScribe.SchnorrData schnorrData
          );
          /// @notice Emitted when ETH reward paid for successfully challenging an
          ///         opPoke.
          /// @param challenger The challenger to which the reward was send.
          /// @param schnorrData The schnorrData challenged.
          /// @param reward The ETH rewards paid.
          event OpChallengeRewardPaid(
              address indexed challenger, IScribe.SchnorrData schnorrData, uint reward
          );
          /// @notice Emitted when an opPoke dropped.
          /// @dev opPoke's are dropped if security parameters are updated that could
          ///      lead to an initially valid opPoke becoming invalid or if an opPoke
          ///      was successfully challenged.
          /// @param caller The caller's address.
          /// @param pokeData The pokeData dropped.
          event OpPokeDataDropped(address indexed caller, IScribe.PokeData pokeData);
          /// @notice Emitted when length of opChallengePeriod updated.
          /// @param caller The caller's address.
          /// @param oldOpChallengePeriod The old opChallengePeriod's length.
          /// @param newOpChallengePeriod The new opChallengePeriod's length.
          event OpChallengePeriodUpdated(
              address indexed caller,
              uint16 oldOpChallengePeriod,
              uint16 newOpChallengePeriod
          );
          /// @notice Emitted when maxChallengeReward updated.
          /// @param caller The caller's address.
          /// @param oldMaxChallengeReward The old maxChallengeReward.
          /// @param newMaxChallengeReward The new maxChallengeReward.
          event MaxChallengeRewardUpdated(
              address indexed caller,
              uint oldMaxChallengeReward,
              uint newMaxChallengeReward
          );
          /// @notice Optimistically pokes the oracle.
          /// @dev Expects `pokeData`'s age to be greater than the timestamp of the
          ///      last successful poke.
          /// @dev Expects `pokeData`'s age to not be greater than the current time.
          /// @dev Expects `ecdsaData` to be a signature from a feed.
          /// @dev Expects `ecdsaData` to prove the integrity of the `pokeData` and
          ///      `schnorrData`.
          /// @dev If the `schnorrData` is proven to be invalid via the opChallenge
          ///      function, the `ecdsaData` signing feed will be dropped.
          /// @param pokeData The PokeData being poked.
          /// @param schnorrData The SchnorrData optimistically assumed to be
          ///                    proving the `pokeData`'s integrity.
          /// @param ecdsaData The ECDSAData proving the integrity of the
          ///                  `pokeData` and `schnorrData`.
          function opPoke(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData,
              ECDSAData calldata ecdsaData
          ) external;
          /// @notice Challenges the current challengeable opPoke.
          /// @dev If opPoke is determined to be invalid, the caller receives an ETH
          ///      bounty. The bounty is defined via the `challengeReward()(uint)`
          ///      function.
          /// @dev If opPoke is determined to be invalid, the corresponding feed is
          ///      dropped.
          /// @param schnorrData The SchnorrData initially provided via
          ///                    opPoke.
          /// @return ok True if opPoke declared invalid, false otherwise.
          function opChallenge(SchnorrData calldata schnorrData)
              external
              returns (bool ok);
          /// @notice Returns the message expected to be signed via ECDSA for calling
          ///         opPoke.
          /// @dev The message is defined as:
          ///         H(tag ‖ H(wat ‖ pokeData ‖ schnorrData)), where H() is the keccak256 function.
          /// @param pokeData The pokeData being optimistically poked.
          /// @param schnorrData The schnorrData proving `pokeData`'s integrity.
          /// @return opPokeMessage Message to be signed for an opPoke for `pokeData`
          ///                       and `schnorrData`.
          function constructOpPokeMessage(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData
          ) external view returns (bytes32 opPokeMessage);
          /// @notice Returns the feed id of the feed last opPoke'd.
          /// @return opFeedId Feed id of the feed last opPoke'd.
          function opFeedId() external view returns (uint8 opFeedId);
          /// @notice Returns the opChallengePeriod security parameter.
          /// @return opChallengePeriod The opChallengePeriod security parameter.
          function opChallengePeriod()
              external
              view
              returns (uint16 opChallengePeriod);
          /// @notice Returns the maxChallengeRewards parameter.
          /// @return maxChallengeReward The maxChallengeReward parameter.
          function maxChallengeReward()
              external
              view
              returns (uint maxChallengeReward);
          /// @notice Returns the ETH rewards being paid for successfully challenging
          ///         an opPoke.
          /// @return challengeReward The ETH reward for successfully challenging an
          ///                         opPoke.
          function challengeReward() external view returns (uint challengeReward);
          /// @notice Updates the opChallengePeriod security parameter.
          /// @dev Only callable by auth'ed address.
          /// @dev Reverts if opChallengePeriod is zero.
          /// @dev Note that evaluating whether an opPoke is finalized happens via the
          ///      _current_ opChallengePeriod.
          ///      This means a finalized opPoke is dropped if opChallengePeriod is
          ///      decreased to a value less than opPoke's age.
          /// @param opChallengePeriod The value to update opChallengePeriod to.
          function setOpChallengePeriod(uint16 opChallengePeriod) external;
          /// @notice Updates the maxChallengeReward parameter.
          /// @dev Only callable by auth'ed address.
          /// @param maxChallengeReward The value to update maxChallengeReward to.
          function setMaxChallengeReward(uint maxChallengeReward) external;
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      import {IChronicle} from "chronicle-std/IChronicle.sol";
      import {LibSecp256k1} from "./libs/LibSecp256k1.sol";
      interface IScribe is IChronicle {
          /// @dev PokeData encapsulates a value and its age.
          struct PokeData {
              uint128 val;
              uint32 age;
          }
          /// @dev SchnorrData encapsulates a (aggregated) Schnorr signature.
          ///      Schnorr signatures are used to prove a PokeData's integrity.
          struct SchnorrData {
              bytes32 signature;
              address commitment;
              bytes feedIds;
          }
          /// @dev ECDSAData encapsulates an ECDSA signature.
          struct ECDSAData {
              uint8 v;
              bytes32 r;
              bytes32 s;
          }
          /// @notice Thrown if a poked value's age is not greater than the oracle's
          ///         current value's age.
          /// @param givenAge The poked value's age.
          /// @param currentAge The oracle's current value's age.
          error StaleMessage(uint32 givenAge, uint32 currentAge);
          /// @notice Thrown if a poked value's age is greater than the current
          ///         time.
          /// @param givenAge The poked value's age.
          /// @param currentTimestamp The current time.
          error FutureMessage(uint32 givenAge, uint32 currentTimestamp);
          /// @notice Thrown if Schnorr signature not signed by exactly bar many
          ///         signers.
          /// @param numberSigners The number of signers for given Schnorr signature.
          /// @param bar The bar security parameter.
          error BarNotReached(uint8 numberSigners, uint8 bar);
          /// @notice Thrown if given feed id invalid.
          /// @param feedId The invalid feed id.
          error InvalidFeedId(uint8 feedId);
          /// @notice Thrown if double signing attempted.
          /// @param feedId The id of the feed attempting to double sign.
          error DoubleSigningAttempted(uint8 feedId);
          /// @notice Thrown if Schnorr signature verification failed.
          error SchnorrSignatureInvalid();
          /// @notice Emitted when oracle was successfully poked.
          /// @param caller The caller's address.
          /// @param val The value poked.
          /// @param age The age of the value poked.
          event Poked(address indexed caller, uint128 val, uint32 age);
          /// @notice Emitted when new feed lifted.
          /// @param caller The caller's address.
          /// @param feed The feed address lifted.
          event FeedLifted(address indexed caller, address indexed feed);
          /// @notice Emitted when feed dropped.
          /// @param caller The caller's address.
          /// @param feed The feed address dropped.
          event FeedDropped(address indexed caller, address indexed feed);
          /// @notice Emitted when bar updated.
          /// @param caller The caller's address.
          /// @param oldBar The old bar's value.
          /// @param newBar The new bar's value.
          event BarUpdated(address indexed caller, uint8 oldBar, uint8 newBar);
          /// @notice Returns the feed registration message.
          /// @dev This message must be signed by a feed in order to be lifted.
          /// @return feedRegistrationMessage Chronicle Protocol's feed registration
          ///                                 message.
          function feedRegistrationMessage()
              external
              view
              returns (bytes32 feedRegistrationMessage);
          /// @notice Returns the bar security parameter.
          /// @return bar The bar security parameter.
          function bar() external view returns (uint8 bar);
          /// @notice Returns the number of decimals of the oracle's value.
          /// @dev Provides partial compatibility with Chainlink's
          ///      IAggregatorV3Interface.
          /// @return decimals The oracle value's number of decimals.
          function decimals() external view returns (uint8 decimals);
          /// @notice Returns the oracle's latest value.
          /// @dev Provides partial compatibility with Chainlink's
          ///      IAggregatorV3Interface.
          /// @return roundId 1.
          /// @return answer The oracle's latest value.
          /// @return startedAt 0.
          /// @return updatedAt The timestamp of oracle's latest update.
          /// @return answeredInRound 1.
          function latestRoundData()
              external
              view
              returns (
                  uint80 roundId,
                  int answer,
                  uint startedAt,
                  uint updatedAt,
                  uint80 answeredInRound
              );
          /// @notice Returns the oracle's latest value.
          /// @dev Provides partial compatibility with Chainlink's
          ///      IAggregatorV3Interface.
          /// @custom:deprecated See https://docs.chain.link/data-feeds/api-reference/#latestanswer.
          /// @return answer The oracle's latest value.
          function latestAnswer() external view returns (int);
          /// @notice Pokes the oracle.
          /// @dev Expects `pokeData`'s age to be greater than the timestamp of the
          ///      last successful poke.
          /// @dev Expects `pokeData`'s age to not be greater than the current time.
          /// @dev Expects `schnorrData` to prove `pokeData`'s integrity.
          ///      See `isAcceptableSchnorrSignatureNow(bytes32,SchnorrData)(bool)`.
          /// @param pokeData The PokeData being poked.
          /// @param schnorrData The SchnorrData proving the `pokeData`'s
          ///                    integrity.
          function poke(PokeData calldata pokeData, SchnorrData calldata schnorrData)
              external;
          /// @notice Returns whether the Schnorr signature `schnorrData` is
          ///         currently acceptable for message `message`.
          /// @dev Note that a valid Schnorr signature is only acceptable if the
          ///      signature was signed by exactly bar many feeds.
          ///      For more info, see `bar()(uint8)` and `feeds()(address[])`.
          /// @dev Note that bar and feeds are configurable, meaning a once acceptable
          ///      Schnorr signature may become unacceptable in the future.
          /// @param message The message expected to be signed via `schnorrData`.
          /// @param schnorrData The SchnorrData to verify whether it proves
          ///                    the `message`'s integrity.
          /// @return ok True if Schnorr signature is acceptable, false otherwise.
          function isAcceptableSchnorrSignatureNow(
              bytes32 message,
              SchnorrData calldata schnorrData
          ) external view returns (bool ok);
          /// @notice Returns the message expected to be signed via Schnorr for
          ///         `pokeData`.
          /// @dev The message is defined as:
          ///         H(tag ‖ H(wat ‖ pokeData)), where H() is the keccak256 function.
          /// @param pokeData The pokeData to create the message for.
          /// @return pokeMessage Message for `pokeData`.
          function constructPokeMessage(PokeData calldata pokeData)
              external
              view
              returns (bytes32 pokeMessage);
          /// @notice Returns whether address `who` is a feed.
          /// @param who The address to check.
          /// @return isFeed True if `who` is feed, false otherwise.
          function feeds(address who) external view returns (bool isFeed);
          /// @notice Returns whether feed id `feedId` is a feed and, if so, the
          ///         feed's address.
          /// @param feedId The feed id to check.
          /// @return isFeed True if `feedId` is a feed, false otherwise.
          /// @return feed Address of the feed with id `feedId` if `feedId` is a feed,
          ///              zero-address otherwise.
          function feeds(uint8 feedId)
              external
              view
              returns (bool isFeed, address feed);
          /// @notice Returns list of feed addresses.
          /// @dev Note that this function has a high gas consumption and is not
          ///      intended to be called onchain.
          /// @return feeds List of feed addresses.
          function feeds() external view returns (address[] memory feeds);
          /// @notice Lifts public key `pubKey` to being a feed.
          /// @dev Only callable by auth'ed address.
          /// @dev The message expected to be signed by `ecdsaData` is defined via
          ///      `feedRegistrationMessage()(bytes32)`.
          /// @param pubKey The public key of the feed.
          /// @param ecdsaData ECDSA signed message by the feed's public key.
          /// @return feedId The id of the newly lifted feed.
          function lift(LibSecp256k1.Point memory pubKey, ECDSAData memory ecdsaData)
              external
              returns (uint8 feedId);
          /// @notice Lifts public keys `pubKeys` to being feeds.
          /// @dev Only callable by auth'ed address.
          /// @dev The message expected to be signed by `ecdsaDatas` is defined via
          ///      `feedRegistrationMessage()(bytes32)`.
          /// @param pubKeys The public keys of the feeds.
          /// @param ecdsaDatas ECDSA signed message by the feeds' public keys.
          /// @return List of feed ids of the newly lifted feeds.
          function lift(
              LibSecp256k1.Point[] memory pubKeys,
              ECDSAData[] memory ecdsaDatas
          ) external returns (uint8[] memory);
          /// @notice Drops feed with id `feedId`.
          /// @dev Only callable by auth'ed address.
          /// @param feedId The feed id to drop.
          function drop(uint8 feedId) external;
          /// @notice Drops feeds with ids' `feedIds`.
          /// @dev Only callable by auth'ed address.
          /// @param feedIds The feed ids to drop.
          function drop(uint8[] memory feedIds) external;
          /// @notice Updates the bar security parameters to `bar`.
          /// @dev Only callable by auth'ed address.
          /// @dev Reverts if `bar` is zero.
          /// @param bar The value to update bar to.
          function setBar(uint8 bar) external;
          /// @notice Returns the oracle's current value.
          /// @custom:deprecated Use `tryRead()(bool,uint)` instead.
          /// @return value The oracle's current value if it exists, zero otherwise.
          /// @return isValid True if value exists, false otherwise.
          function peek() external view returns (uint value, bool isValid);
          /// @notice Returns the oracle's current value.
          /// @custom:deprecated Use `tryRead()(bool,uint)` instead.
          /// @return value The oracle's current value if it exists, zero otherwise.
          /// @return isValid True if value exists, false otherwise.
          function peep() external view returns (uint value, bool isValid);
      }
      // SPDX-License-Identifier: BUSL-1.1
      pragma solidity ^0.8.16;
      import {IChronicle} from "chronicle-std/IChronicle.sol";
      import {Auth} from "chronicle-std/auth/Auth.sol";
      import {Toll} from "chronicle-std/toll/Toll.sol";
      import {IScribe} from "./IScribe.sol";
      import {LibSchnorr} from "./libs/LibSchnorr.sol";
      import {LibSecp256k1} from "./libs/LibSecp256k1.sol";
      /**
       * @title Scribe
       * @custom:version 2.0.0
       *
       * @notice Efficient Schnorr multi-signature based Oracle
       */
      contract Scribe is IScribe, Auth, Toll {
          using LibSchnorr for LibSecp256k1.Point;
          using LibSecp256k1 for LibSecp256k1.Point;
          using LibSecp256k1 for LibSecp256k1.JacobianPoint;
          /// @inheritdoc IScribe
          uint8 public constant decimals = 18;
          /// @inheritdoc IScribe
          bytes32 public constant feedRegistrationMessage = keccak256(
              abi.encodePacked(
                  "\\x19Ethereum Signed Message:\
      32",
                  keccak256("Chronicle Feed Registration")
              )
          );
          /// @inheritdoc IChronicle
          bytes32 public immutable wat;
          // -- Storage --
          /// @dev Scribe's current value and corresponding age.
          PokeData internal _pokeData;
          /// @dev Statically allocated array of feeds' public keys.
          ///      Indexed via the public keys address' highest-order byte.
          LibSecp256k1.Point[256] internal _pubKeys;
          /// @inheritdoc IScribe
          /// @dev Note to have as last in storage to enable downstream contracts to
          ///      pack the slot.
          uint8 public bar;
          // -- Constructor --
          constructor(address initialAuthed, bytes32 wat_)
              payable
              Auth(initialAuthed)
          {
              require(wat_ != 0);
              // Set wat immutable.
              wat = wat_;
              // Let initial bar be 2.
              _setBar(2);
          }
          // -- Poke Functionality --
          /// @dev Optimized function selector: 0x00000082.
          ///      Note that this function is _not_ defined via the IScribe interface
          ///      and one should _not_ depend on it.
          function poke_optimized_7136211(
              PokeData calldata pokeData,
              SchnorrData calldata schnorrData
          ) external {
              _poke(pokeData, schnorrData);
          }
          /// @inheritdoc IScribe
          function poke(PokeData calldata pokeData, SchnorrData calldata schnorrData)
              external
          {
              _poke(pokeData, schnorrData);
          }
          function _poke(PokeData calldata pokeData, SchnorrData calldata schnorrData)
              internal
              virtual
          {
              // Revert if pokeData stale.
              if (pokeData.age <= _pokeData.age) {
                  revert StaleMessage(pokeData.age, _pokeData.age);
              }
              // Revert if pokeData from the future.
              if (pokeData.age > uint32(block.timestamp)) {
                  revert FutureMessage(pokeData.age, uint32(block.timestamp));
              }
              // Revert if schnorrData does not prove integrity of pokeData.
              bool ok;
              bytes memory err;
              // forgefmt: disable-next-item
              (ok, err) = _verifySchnorrSignature(
                  constructPokeMessage(pokeData),
                  schnorrData
              );
              if (!ok) {
                  _revert(err);
              }
              // Store pokeData's val in _pokeData storage and set its age to now.
              _pokeData.val = pokeData.val;
              _pokeData.age = uint32(block.timestamp);
              emit Poked(msg.sender, pokeData.val, pokeData.age);
          }
          /// @inheritdoc IScribe
          function constructPokeMessage(PokeData memory pokeData)
              public
              view
              returns (bytes32)
          {
              return keccak256(
                  abi.encodePacked(
                      "\\x19Ethereum Signed Message:\
      32",
                      keccak256(abi.encodePacked(wat, pokeData.val, pokeData.age))
                  )
              );
          }
          // -- Schnorr Signature Verification --
          /// @inheritdoc IScribe
          function isAcceptableSchnorrSignatureNow(
              bytes32 message,
              SchnorrData calldata schnorrData
          ) external view returns (bool) {
              bool ok;
              (ok, /*err*/ ) = _verifySchnorrSignature(message, schnorrData);
              return ok;
          }
          /// @custom:invariant Reverts iff out of gas.
          /// @custom:invariant Runtime is O(bar).
          function _verifySchnorrSignature(
              bytes32 message,
              SchnorrData calldata schnorrData
          ) internal view returns (bool, bytes memory) {
              // Let feedPubKey be the currently processed feed's public key.
              LibSecp256k1.Point memory feedPubKey;
              // Let feedId be the currently processed feed's id.
              uint8 feedId;
              // Let aggPubKey be the sum of processed feeds' public keys.
              // Note that Jacobian coordinates are used.
              LibSecp256k1.JacobianPoint memory aggPubKey;
              // Let bloom be a bloom filter to check for double signing attempts.
              uint bloom;
              // Fail if number feeds unequal to bar.
              //
              // Note that requiring equality constrains the verification's runtime
              // from Ω(bar) to Θ(bar).
              uint numberFeeds = schnorrData.feedIds.length;
              if (numberFeeds != bar) {
                  return (false, _errorBarNotReached(uint8(numberFeeds), bar));
              }
              // Initiate feed variables with schnorrData's 0's feed index.
              feedId = uint8(schnorrData.feedIds[0]);
              feedPubKey = _pubKeys[feedId];
              // Fail if feed not lifted.
              if (feedPubKey.isZeroPoint()) {
                  return (false, _errorInvalidFeedId(feedId));
              }
              // Initiate bloom filter with feedId set.
              bloom = 1 << feedId;
              // Initiate aggPubKey with value of first feed's public key.
              aggPubKey = feedPubKey.toJacobian();
              for (uint8 i = 1; i < numberFeeds;) {
                  // Update feed variables.
                  feedId = uint8(schnorrData.feedIds[i]);
                  feedPubKey = _pubKeys[feedId];
                  // Fail if feed not lifted.
                  if (feedPubKey.isZeroPoint()) {
                      return (false, _errorInvalidFeedId(feedId));
                  }
                  // Fail if double signing attempted.
                  if (bloom & (1 << feedId) != 0) {
                      return (false, _errorDoubleSigningAttempted(feedId));
                  }
                  // Update bloom filter.
                  bloom |= 1 << feedId;
                  // assert(aggPubKey.x != feedPubKey.x); // Indicates rogue-key attack
                  // Add feedPubKey to already aggregated public keys.
                  aggPubKey.addAffinePoint(feedPubKey);
                  // forgefmt: disable-next-item
                  unchecked { ++i; }
              }
              // Fail if signature verification fails.
              bool ok = aggPubKey.toAffine().verifySignature(
                  message, schnorrData.signature, schnorrData.commitment
              );
              if (!ok) {
                  return (false, _errorSchnorrSignatureInvalid());
              }
              // Otherwise Schnorr signature is valid.
              return (true, new bytes(0));
          }
          // -- Toll'ed Read Functionality --
          // - IChronicle Functions
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function read() external view virtual toll returns (uint) {
              uint val = _pokeData.val;
              require(val != 0);
              return val;
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function tryRead() external view virtual toll returns (bool, uint) {
              uint val = _pokeData.val;
              return (val != 0, val);
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function readWithAge() external view virtual toll returns (uint, uint) {
              uint val = _pokeData.val;
              uint age = _pokeData.age;
              require(val != 0);
              return (val, age);
          }
          /// @inheritdoc IChronicle
          /// @dev Only callable by toll'ed address.
          function tryReadWithAge()
              external
              view
              virtual
              toll
              returns (bool, uint, uint)
          {
              uint val = _pokeData.val;
              uint age = _pokeData.age;
              return val != 0 ? (true, val, age) : (false, 0, 0);
          }
          // - MakerDAO Compatibility
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function peek() external view virtual toll returns (uint, bool) {
              uint val = _pokeData.val;
              return (val, val != 0);
          }
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function peep() external view virtual toll returns (uint, bool) {
              uint val = _pokeData.val;
              return (val, val != 0);
          }
          // - Chainlink Compatibility
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function latestRoundData()
              external
              view
              virtual
              toll
              returns (
                  uint80 roundId,
                  int answer,
                  uint startedAt,
                  uint updatedAt,
                  uint80 answeredInRound
              )
          {
              roundId = 1;
              answer = int(uint(_pokeData.val));
              // assert(uint(answer) == uint(_pokeData.val));
              startedAt = 0;
              updatedAt = _pokeData.age;
              answeredInRound = roundId;
          }
          /// @inheritdoc IScribe
          /// @dev Only callable by toll'ed address.
          function latestAnswer() external view virtual toll returns (int) {
              uint val = _pokeData.val;
              return int(val);
          }
          // -- Public Read Functionality --
          /// @inheritdoc IScribe
          function feeds(address who) external view returns (bool) {
              uint8 feedId = uint8(uint(uint160(who)) >> 152);
              LibSecp256k1.Point memory pubKey = _pubKeys[feedId];
              return !pubKey.isZeroPoint() && pubKey.toAddress() == who;
          }
          /// @inheritdoc IScribe
          function feeds(uint8 feedId) external view returns (bool, address) {
              LibSecp256k1.Point memory pubKey = _pubKeys[feedId];
              return pubKey.isZeroPoint()
                  ? (false, address(0))
                  : (true, pubKey.toAddress());
          }
          /// @inheritdoc IScribe
          function feeds() external view returns (address[] memory) {
              address[] memory feeds_ = new address[](256);
              LibSecp256k1.Point memory pubKey;
              address feed;
              uint ctr;
              for (uint i; i < 256;) {
                  pubKey = _pubKeys[uint8(i)];
                  if (!pubKey.isZeroPoint()) {
                      feed = pubKey.toAddress();
                      feeds_[ctr] = feed;
                      // forgefmt: disable-next-item
                      unchecked { ++ctr; }
                  }
                  // forgefmt: disable-next-item
                  unchecked { ++i; }
              }
              assembly ("memory-safe") {
                  mstore(feeds_, ctr)
              }
              return feeds_;
          }
          // -- Auth'ed Functionality --
          /// @inheritdoc IScribe
          function lift(LibSecp256k1.Point memory pubKey, ECDSAData memory ecdsaData)
              external
              auth
              returns (uint8)
          {
              return _lift(pubKey, ecdsaData);
          }
          /// @inheritdoc IScribe
          function lift(
              LibSecp256k1.Point[] memory pubKeys,
              ECDSAData[] memory ecdsaDatas
          ) external auth returns (uint8[] memory) {
              require(pubKeys.length == ecdsaDatas.length);
              uint8[] memory feedIds = new uint8[](pubKeys.length);
              for (uint i; i < pubKeys.length;) {
                  feedIds[i] = _lift(pubKeys[i], ecdsaDatas[i]);
                  // forgefmt: disable-next-item
                  unchecked { ++i; }
              }
              return feedIds;
          }
          function _lift(LibSecp256k1.Point memory pubKey, ECDSAData memory ecdsaData)
              internal
              returns (uint8)
          {
              address feed = pubKey.toAddress();
              // assert(feed != address(0));
              // forgefmt: disable-next-item
              address recovered = ecrecover(
                  feedRegistrationMessage,
                  ecdsaData.v,
                  ecdsaData.r,
                  ecdsaData.s
              );
              require(feed == recovered);
              uint8 feedId = uint8(uint(uint160(feed)) >> 152);
              LibSecp256k1.Point memory sPubKey = _pubKeys[feedId];
              if (sPubKey.isZeroPoint()) {
                  _pubKeys[feedId] = pubKey;
                  emit FeedLifted(msg.sender, feed);
              } else {
                  // Note to be idempotent. However, disallow updating an id's feed
                  // via lifting without dropping the previous feed.
                  require(feed == sPubKey.toAddress());
              }
              return feedId;
          }
          /// @inheritdoc IScribe
          function drop(uint8 feedId) external auth {
              _drop(msg.sender, feedId);
          }
          /// @inheritdoc IScribe
          function drop(uint8[] memory feedIds) external auth {
              for (uint i; i < feedIds.length;) {
                  _drop(msg.sender, feedIds[i]);
                  // forgefmt: disable-next-item
                  unchecked { ++i; }
              }
          }
          function _drop(address caller, uint8 feedId) internal virtual {
              LibSecp256k1.Point memory pubKey = _pubKeys[feedId];
              if (!pubKey.isZeroPoint()) {
                  delete _pubKeys[feedId];
                  emit FeedDropped(caller, pubKey.toAddress());
              }
          }
          /// @inheritdoc IScribe
          function setBar(uint8 bar_) external auth {
              _setBar(bar_);
          }
          function _setBar(uint8 bar_) internal virtual {
              require(bar_ != 0);
              if (bar != bar_) {
                  emit BarUpdated(msg.sender, bar, bar_);
                  bar = bar_;
              }
          }
          // -- Internal Helpers --
          function _revert(bytes memory err) internal pure {
              // assert(err.length != 0);
              assembly ("memory-safe") {
                  let size := mload(err)
                  let offset := add(err, 0x20)
                  revert(offset, size)
              }
          }
          function _errorBarNotReached(uint8 got, uint8 want)
              internal
              pure
              returns (bytes memory)
          {
              // assert(got != want);
              return abi.encodeWithSelector(IScribe.BarNotReached.selector, got, want);
          }
          function _errorInvalidFeedId(uint8 feedId)
              internal
              pure
              returns (bytes memory)
          {
              // assert(_pubKeys[feedId].isZeroPoint());
              return abi.encodeWithSelector(IScribe.InvalidFeedId.selector, feedId);
          }
          function _errorDoubleSigningAttempted(uint8 feedId)
              internal
              pure
              returns (bytes memory)
          {
              return abi.encodeWithSelector(
                  IScribe.DoubleSigningAttempted.selector, feedId
              );
          }
          function _errorSchnorrSignatureInvalid()
              internal
              pure
              returns (bytes memory)
          {
              return abi.encodeWithSelector(IScribe.SchnorrSignatureInvalid.selector);
          }
          // -- Overridden Toll Functions --
          /// @dev Defines authorization for IToll's authenticated functions.
          function toll_auth() internal override(Toll) auth {}
      }
      /**
       * @dev Contract overwrite to deploy contract instances with specific naming.
       *
       *      For more info, see docs/Deployment.md.
       */
      contract Chronicle_MOG_USD_1 is Scribe {
          constructor(address initialAuthed, bytes32 wat_)
              Scribe(initialAuthed, wat_)
          {}
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      import {LibSecp256k1} from "./LibSecp256k1.sol";
      /**
       * @title LibSchnorr
       *
       * @notice Custom-purpose library for Schnorr signature verification on the
       *         secp256k1 curve
       */
      library LibSchnorr {
          using LibSecp256k1 for LibSecp256k1.Point;
          /// @dev Returns whether `signature` and `commitment` sign via `pubKey`
          ///      message `message`.
          ///
          /// @custom:invariant Reverts iff out of gas.
          /// @custom:invariant Uses constant amount of gas.
          function verifySignature(
              LibSecp256k1.Point memory pubKey,
              bytes32 message,
              bytes32 signature,
              address commitment
          ) internal pure returns (bool) {
              // Return false if signature or commitment is zero.
              if (signature == 0 || commitment == address(0)) {
                  return false;
              }
              // Note to enforce pubKey is valid secp256k1 point.
              //
              // While the Scribe contract ensures to only verify signatures for valid
              // public keys, this check is enabled as an additional defense
              // mechanism.
              if (!pubKey.isOnCurve()) {
                  return false;
              }
              // Note to enforce signature is less than Q to prevent signature
              // malleability.
              //
              // While the Scribe contract only accepts messages with strictly
              // monotonically increasing timestamps, circumventing replay attack
              // vectors and therefore also signature malleability issues at a higher
              // level, this check is enabled as an additional defense mechanism.
              if (uint(signature) >= LibSecp256k1.Q()) {
                  return false;
              }
              // Construct challenge = H(Pₓ ‖ Pₚ ‖ m ‖ Rₑ) mod Q
              uint challenge = uint(
                  keccak256(
                      abi.encodePacked(
                          pubKey.x, uint8(pubKey.yParity()), message, commitment
                      )
                  )
              ) % LibSecp256k1.Q();
              // Compute msgHash = -sig * Pₓ      (mod Q)
              //                 = Q - (sig * Pₓ) (mod Q)
              //
              // Unchecked because the only protected operation performed is the
              // subtraction from Q where the subtrahend is the result of a (mod Q)
              // computation, i.e. the subtrahend is guaranteed to be less than Q.
              uint msgHash;
              unchecked {
                  msgHash = LibSecp256k1.Q()
                      - mulmod(uint(signature), pubKey.x, LibSecp256k1.Q());
              }
              // Compute v = Pₚ + 27
              //
              // Unchecked because pubKey.yParity() ∊ {0, 1} which cannot overflow
              // by adding 27.
              uint v;
              unchecked {
                  v = pubKey.yParity() + 27;
              }
              // Set r = Pₓ
              uint r = pubKey.x;
              // Compute s = Q - (e * Pₓ) (mod Q)
              //
              // Unchecked because the only protected operation performed is the
              // subtraction from Q where the subtrahend is the result of a (mod Q)
              // computation, i.e. the subtrahend is guaranteed to be less than Q.
              uint s;
              unchecked {
                  s = LibSecp256k1.Q() - mulmod(challenge, pubKey.x, LibSecp256k1.Q());
              }
              // Compute ([s]G - [e]P)ₑ via ecrecover.
              address recovered =
                  ecrecover(bytes32(msgHash), uint8(v), bytes32(r), bytes32(s));
              // Verification succeeds iff ([s]G - [e]P)ₑ = Rₑ.
              //
              // Note that commitment is guaranteed to not be zero.
              return commitment == recovered;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      /**
       * @title LibSecp256k1
       *
       * @notice Library for secp256k1 elliptic curve computations
       *
       * @dev This library was developed to efficiently compute aggregated public
       *      keys for Schnorr signatures based on secp256k1, i.e. it is _not_ a
       *      general purpose elliptic curve library!
       *
       *      References to the Ethereum Yellow Paper are based on the following
       *      version: "BERLIN VERSION beacfbd – 2022-10-24".
       */
      library LibSecp256k1 {
          using LibSecp256k1 for LibSecp256k1.Point;
          using LibSecp256k1 for LibSecp256k1.JacobianPoint;
          uint private constant ADDRESS_MASK =
              0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
          // -- Secp256k1 Constants --
          //
          // Taken from https://www.secg.org/sec2-v2.pdf.
          // See section 2.4.1 "Recommended Parameters secp256k1".
          uint private constant _A = 0;
          uint private constant _B = 7;
          uint private constant _P =
              0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
          /// @dev Returns the order of the group.
          function Q() internal pure returns (uint) {
              return
                  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
          }
          /// @dev Returns the generator G.
          ///      Note that the generator is also called base point.
          function G() internal pure returns (Point memory) {
              return Point({
                  x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
                  y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
              });
          }
          /// @dev Returns the zero point.
          function ZERO_POINT() internal pure returns (Point memory) {
              return Point({x: 0, y: 0});
          }
          // -- (Affine) Point --
          /// @dev Point encapsulates a secp256k1 point in Affine coordinates.
          struct Point {
              uint x;
              uint y;
          }
          /// @dev Returns the Ethereum address of `self`.
          ///
          /// @dev An Ethereum address is defined as the rightmost 160 bits of the
          ///      keccak256 hash of the concatenation of the hex-encoded x and y
          ///      coordinates of the corresponding ECDSA public key.
          ///      See "Appendix F: Signing Transactions" §134 in the Yellow Paper.
          function toAddress(Point memory self) internal pure returns (address) {
              address addr;
              // Functionally equivalent Solidity code:
              // addr = address(uint160(uint(keccak256(abi.encode(self.x, self.y)))));
              assembly ("memory-safe") {
                  addr := and(keccak256(self, 0x40), ADDRESS_MASK)
              }
              return addr;
          }
          /// @dev Returns Affine point `self` in Jacobian coordinates.
          function toJacobian(Point memory self)
              internal
              pure
              returns (JacobianPoint memory)
          {
              return JacobianPoint({x: self.x, y: self.y, z: 1});
          }
          /// @dev Returns whether `self` is the zero point.
          function isZeroPoint(Point memory self) internal pure returns (bool) {
              return (self.x | self.y) == 0;
          }
          /// @dev Returns whether `self` is a point on the curve.
          ///
          /// @dev The secp256k1 curve is specified as y² ≡ x³ + ax + b (mod P)
          ///      where:
          ///         a = 0
          ///         b = 7
          function isOnCurve(Point memory self) internal pure returns (bool) {
              uint left = mulmod(self.y, self.y, _P);
              // Note that adding a * x can be waived as ∀x: a * x = 0.
              uint right =
                  addmod(mulmod(self.x, mulmod(self.x, self.x, _P), _P), _B, _P);
              return left == right;
          }
          /// @dev Returns the parity of `self`'s y coordinate.
          ///
          /// @dev The value 0 represents an even y value and 1 represents an odd y
          ///      value.
          ///      See "Appendix F: Signing Transactions" in the Yellow Paper.
          function yParity(Point memory self) internal pure returns (uint) {
              return self.y & 1;
          }
          // -- Jacobian Point --
          /// @dev JacobianPoint encapsulates a secp256k1 point in Jacobian
          ///      coordinates.
          struct JacobianPoint {
              uint x;
              uint y;
              uint z;
          }
          /// @dev Returns Jacobian point `self` in Affine coordinates.
          ///
          /// @custom:invariant Reverts iff out of gas.
          /// @custom:invariant Does not run into an infinite loop.
          function toAffine(JacobianPoint memory self)
              internal
              pure
              returns (Point memory)
          {
              Point memory result;
              // Compute z⁻¹, i.e. the modular inverse of self.z.
              uint zInv = _invMod(self.z);
              // Compute (z⁻¹)² (mod P)
              uint zInv_2 = mulmod(zInv, zInv, _P);
              // Compute self.x * (z⁻¹)² (mod P), i.e. the x coordinate of given
              // Jacobian point in Affine representation.
              result.x = mulmod(self.x, zInv_2, _P);
              // Compute self.y * (z⁻¹)³ (mod P), i.e. the y coordinate of given
              // Jacobian point in Affine representation.
              result.y = mulmod(self.y, mulmod(zInv, zInv_2, _P), _P);
              return result;
          }
          /// @dev Adds Affine point `p` to Jacobian point `self`.
          ///
          ///      It is the caller's responsibility to ensure given points are on the
          ///      curve!
          ///
          ///      Computation based on: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-madd-2007-bl.
          ///
          ///      Note that the formula assumes z2 = 1, which always holds if z2's
          ///      point is given in Affine coordinates.
          ///
          ///      Note that eventhough the function is marked as pure, to be
          ///      understood as only being dependent on the input arguments, it
          ///      nevertheless has side effects by writing the result into the
          ///      `self` memory variable.
          ///
          /// @custom:invariant Only mutates `self` memory variable.
          /// @custom:invariant Reverts iff out of gas.
          /// @custom:invariant Uses constant amount of gas.
          function addAffinePoint(JacobianPoint memory self, Point memory p)
              internal
              pure
          {
              // Addition formula:
              //      x = r² - j - (2 * v)             (mod P)
              //      y = (r * (v - x)) - (2 * y1 * j) (mod P)
              //      z = (z1 + h)² - z1² - h²         (mod P)
              //
              // where:
              //      r = 2 * (s - y1) (mod P)
              //      j = h * i        (mod P)
              //      v = x1 * i       (mod P)
              //      h = u - x1       (mod P)
              //      s = y2 * z1³     (mod P)       Called s2 in reference
              //      i = 4 * h²       (mod P)
              //      u = x2 * z1²     (mod P)       Called u2 in reference
              //
              // and:
              //      x1 = self.x
              //      y1 = self.y
              //      z1 = self.z
              //      x2 = p.x
              //      y2 = p.y
              //
              // Note that in order to save memory allocations the result is stored
              // in the self variable, i.e. the following holds true after the
              // functions execution:
              //      x = self.x
              //      y = self.y
              //      z = self.z
              // Cache self's coordinates on stack.
              uint x1 = self.x;
              uint y1 = self.y;
              uint z1 = self.z;
              // Compute z1_2 = z1²     (mod P)
              //              = z1 * z1 (mod P)
              uint z1_2 = mulmod(z1, z1, _P);
              // Compute h = u        - x1       (mod P)
              //           = u        + (P - x1) (mod P)
              //           = x2 * z1² + (P - x1) (mod P)
              //
              // Unchecked because the only protected operation performed is P - x1
              // where x1 is guaranteed by the caller to be an x coordinate belonging
              // to a point on the curve, i.e. being less than P.
              uint h;
              unchecked {
                  h = addmod(mulmod(p.x, z1_2, _P), _P - x1, _P);
              }
              // Compute h_2 = h²    (mod P)
              //             = h * h (mod P)
              uint h_2 = mulmod(h, h, _P);
              // Compute i = 4 * h² (mod P)
              uint i = mulmod(4, h_2, _P);
              // Compute z = (z1 + h)² - z1²       - h²       (mod P)
              //           = (z1 + h)² - z1²       + (P - h²) (mod P)
              //           = (z1 + h)² + (P - z1²) + (P - h²) (mod P)
              //             ╰───────╯   ╰───────╯   ╰──────╯
              //               left         mid       right
              //
              // Unchecked because the only protected operations performed are
              // subtractions from P where the subtrahend is the result of a (mod P)
              // computation, i.e. the subtrahend being guaranteed to be less than P.
              unchecked {
                  uint left = mulmod(addmod(z1, h, _P), addmod(z1, h, _P), _P);
                  uint mid = _P - z1_2;
                  uint right = _P - h_2;
                  self.z = addmod(left, addmod(mid, right, _P), _P);
              }
              // Compute v = x1 * i (mod P)
              uint v = mulmod(x1, i, _P);
              // Compute j = h * i (mod P)
              uint j = mulmod(h, i, _P);
              // Compute r = 2 * (s               - y1)       (mod P)
              //           = 2 * (s               + (P - y1)) (mod P)
              //           = 2 * ((y2 * z1³)      + (P - y1)) (mod P)
              //           = 2 * ((y2 * z1² * z1) + (P - y1)) (mod P)
              //
              // Unchecked because the only protected operation performed is P - y1
              // where y1 is guaranteed by the caller to be an y coordinate belonging
              // to a point on the curve, i.e. being less than P.
              uint r;
              unchecked {
                  r = mulmod(
                      2,
                      addmod(mulmod(p.y, mulmod(z1_2, z1, _P), _P), _P - y1, _P),
                      _P
                  );
              }
              // Compute x = r² - j - (2 * v)             (mod P)
              //           = r² - j + (P - (2 * v))       (mod P)
              //           = r² + (P - j) + (P - (2 * v)) (mod P)
              //                  ╰─────╯   ╰───────────╯
              //                    mid         right
              //
              // Unchecked because the only protected operations performed are
              // subtractions from P where the subtrahend is the result of a (mod P)
              // computation, i.e. the subtrahend being guaranteed to be less than P.
              unchecked {
                  uint r_2 = mulmod(r, r, _P);
                  uint mid = _P - j;
                  uint right = _P - mulmod(2, v, _P);
                  self.x = addmod(r_2, addmod(mid, right, _P), _P);
              }
              // Compute y = (r * (v - x))       - (2 * y1 * j)       (mod P)
              //           = (r * (v - x))       + (P - (2 * y1 * j)) (mod P)
              //           = (r * (v + (P - x))) + (P - (2 * y1 * j)) (mod P)
              //             ╰─────────────────╯   ╰────────────────╯
              //                    left                 right
              //
              // Unchecked because the only protected operations performed are
              // subtractions from P where the subtrahend is the result of a (mod P)
              // computation, i.e. the subtrahend being guaranteed to be less than P.
              unchecked {
                  uint left = mulmod(r, addmod(v, _P - self.x, _P), _P);
                  uint right = _P - mulmod(2, mulmod(y1, j, _P), _P);
                  self.y = addmod(left, right, _P);
              }
          }
          // -- Private Helpers --
          /// @dev Returns the modular inverse of `x` for modulo `_P`.
          ///
          ///      It is the caller's responsibility to ensure `x` is less than `_P`!
          ///
          ///      The modular inverse of `x` is x⁻¹ such that x * x⁻¹ ≡ 1 (mod P).
          ///
          /// @dev Modified from Jordi Baylina's [ecsol](https://github.com/jbaylina/ecsol/blob/c2256afad126b7500e6f879a9369b100e47d435d/ec.sol#L51-L67).
          ///
          /// @custom:invariant Reverts iff out of gas.
          /// @custom:invariant Does not run into an infinite loop.
          function _invMod(uint x) private pure returns (uint) {
              uint t;
              uint q;
              uint newT = 1;
              uint r = _P;
              assembly ("memory-safe") {
                  // Implemented in assembly to circumvent division-by-zero
                  // and over-/underflow protection.
                  //
                  // Functionally equivalent Solidity code:
                  //      while (x != 0) {
                  //          q = r / x;
                  //          (t, newT) = (newT, addmod(t, (_P - mulmod(q, newT, _P)), _P));
                  //          (r, x) = (x, r - (q * x));
                  //      }
                  //
                  // For the division r / x, x is guaranteed to not be zero via the
                  // loop condition.
                  //
                  // The subtraction of form P - mulmod(_, _, P) is guaranteed to not
                  // underflow due to the subtrahend being a (mod P) result,
                  // i.e. the subtrahend being guaranteed to be less than P.
                  //
                  // The subterm q * x is guaranteed to not overflow because
                  // q * x ≤ r due to q = ⎣r / x⎦.
                  //
                  // The term r - (q * x) is guaranteed to not underflow because
                  // q * x ≤ r and therefore r - (q * x) ≥ 0.
                  for {} x {} {
                      q := div(r, x)
                      let tmp := t
                      t := newT
                      newT := addmod(tmp, sub(_P, mulmod(q, newT, _P)), _P)
                      tmp := r
                      r := x
                      x := sub(tmp, mul(q, x))
                  }
              }
              return t;
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      import {IAuth} from "./IAuth.sol";
      /**
       * @title Auth Module
       *
       * @dev The `Auth` contract module provides a basic access control mechanism,
       *      where a set of addresses are granted access to protected functions.
       *      These addresses are said to be _auth'ed_.
       *
       *      Initially, the address given as constructor argument is the only address
       *      auth'ed. Through the `rely(address)` and `deny(address)` functions,
       *      auth'ed callers are able to grant/renounce auth to/from addresses.
       *
       *      This module is used through inheritance. It will make available the
       *      modifier `auth`, which can be applied to functions to restrict their
       *      use to only auth'ed callers.
       */
      abstract contract Auth is IAuth {
          /// @dev Mapping storing whether address is auth'ed.
          /// @custom:invariant Image of mapping is {0, 1}.
          ///                     ∀x ∊ Address: _wards[x] ∊ {0, 1}
          /// @custom:invariant Only address given as constructor argument is authenticated after deployment.
          ///                     deploy(initialAuthed) → (∀x ∊ Address: _wards[x] == 1 → x == initialAuthed)
          /// @custom:invariant Only functions `rely` and `deny` may mutate the mapping's state.
          ///                     ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x])
          ///                                     → (msg.sig == "rely" ∨ msg.sig == "deny")
          /// @custom:invariant Mapping's state may only be mutated by authenticated caller.
          ///                     ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x]) → _wards[msg.sender] = 1
          mapping(address => uint) private _wards;
          /// @dev List of addresses possibly being auth'ed.
          /// @dev May contain duplicates.
          /// @dev May contain addresses not being auth'ed anymore.
          /// @custom:invariant Every address being auth'ed once is element of the list.
          ///                     ∀x ∊ Address: authed(x) -> x ∊ _wardsTouched
          address[] private _wardsTouched;
          /// @dev Ensures caller is auth'ed.
          modifier auth() {
              assembly ("memory-safe") {
                  // Compute slot of _wards[msg.sender].
                  mstore(0x00, caller())
                  mstore(0x20, _wards.slot)
                  let slot := keccak256(0x00, 0x40)
                  // Revert if caller not auth'ed.
                  let isAuthed := sload(slot)
                  if iszero(isAuthed) {
                      // Store selector of `NotAuthorized(address)`.
                      mstore(0x00, 0x4a0bfec1)
                      // Store msg.sender.
                      mstore(0x20, caller())
                      // Revert with (offset, size).
                      revert(0x1c, 0x24)
                  }
              }
              _;
          }
          constructor(address initialAuthed) {
              _wards[initialAuthed] = 1;
              _wardsTouched.push(initialAuthed);
              // Note to use address(0) as caller to indicate address was auth'ed
              // during deployment.
              emit AuthGranted(address(0), initialAuthed);
          }
          /// @inheritdoc IAuth
          function rely(address who) external auth {
              if (_wards[who] == 1) return;
              _wards[who] = 1;
              _wardsTouched.push(who);
              emit AuthGranted(msg.sender, who);
          }
          /// @inheritdoc IAuth
          function deny(address who) external auth {
              if (_wards[who] == 0) return;
              _wards[who] = 0;
              emit AuthRenounced(msg.sender, who);
          }
          /// @inheritdoc IAuth
          function authed(address who) public view returns (bool) {
              return _wards[who] == 1;
          }
          /// @inheritdoc IAuth
          /// @custom:invariant Only contains auth'ed addresses.
          ///                     ∀x ∊ authed(): _wards[x] == 1
          /// @custom:invariant Contains all auth'ed addresses.
          ///                     ∀x ∊ Address: _wards[x] == 1 → x ∊ authed()
          function authed() public view returns (address[] memory) {
              // Initiate array with upper limit length.
              address[] memory wardsList = new address[](_wardsTouched.length);
              // Iterate through all possible auth'ed addresses.
              uint ctr;
              for (uint i; i < wardsList.length; i++) {
                  // Add address only if still auth'ed.
                  if (_wards[_wardsTouched[i]] == 1) {
                      wardsList[ctr++] = _wardsTouched[i];
                  }
              }
              // Set length of array to number of auth'ed addresses actually included.
              assembly ("memory-safe") {
                  mstore(wardsList, ctr)
              }
              return wardsList;
          }
          /// @inheritdoc IAuth
          function wards(address who) public view returns (uint) {
              return _wards[who];
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      import {IToll} from "./IToll.sol";
      /**
       * @title Toll Module
       *
       * @notice "Toll paid, we kiss - but dissension looms, maybe diss?"
       *
       * @dev The `Toll` contract module provides a basic access control mechanism,
       *      where a set of addresses are granted access to protected functions.
       *      These addresses are said the be _tolled_.
       *
       *      Initially, no address is tolled. Through the `kiss(address)` and
       *      `diss(address)` functions, auth'ed callers are able to toll/de-toll
       *      addresses. Authentication for these functions is defined via the
       *      downstream implemented `toll_auth()` function.
       *
       *      This module is used through inheritance. It will make available the
       *      modifier `toll`, which can be applied to functions to restrict their
       *      use to only tolled callers.
       */
      abstract contract Toll is IToll {
          /// @dev Mapping storing whether address is tolled.
          /// @custom:invariant Image of mapping is {0, 1}.
          ///                     ∀x ∊ Address: _buds[x] ∊ {0, 1}
          /// @custom:invariant Only functions `kiss` and `diss` may mutate the mapping's state.
          ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
          ///                                     → (msg.sig == "kiss" ∨ msg.sig == "diss")
          /// @custom:invariant Mapping's state may only be mutated by authenticated caller.
          ///                     ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
          ///                                     → toll_auth()
          mapping(address => uint) private _buds;
          /// @dev List of addresses possibly being tolled.
          /// @dev May contain duplicates.
          /// @dev May contain addresses not being tolled anymore.
          /// @custom:invariant Every address being tolled once is element of the list.
          ///                     ∀x ∊ Address: tolled(x) → x ∊ _budsTouched
          address[] private _budsTouched;
          /// @dev Ensures caller is tolled.
          modifier toll() {
              assembly ("memory-safe") {
                  // Compute slot of _buds[msg.sender].
                  mstore(0x00, caller())
                  mstore(0x20, _buds.slot)
                  let slot := keccak256(0x00, 0x40)
                  // Revert if caller not tolled.
                  let isTolled := sload(slot)
                  if iszero(isTolled) {
                      // Store selector of `NotTolled(address)`.
                      mstore(0x00, 0xd957b595)
                      // Store msg.sender.
                      mstore(0x20, caller())
                      // Revert with (offset, size).
                      revert(0x1c, 0x24)
                  }
              }
              _;
          }
          /// @dev Reverts if caller not allowed to access protected function.
          /// @dev Must be implemented in downstream contract.
          function toll_auth() internal virtual;
          /// @inheritdoc IToll
          function kiss(address who) external {
              toll_auth();
              if (_buds[who] == 1) return;
              _buds[who] = 1;
              _budsTouched.push(who);
              emit TollGranted(msg.sender, who);
          }
          /// @inheritdoc IToll
          function diss(address who) external {
              toll_auth();
              if (_buds[who] == 0) return;
              _buds[who] = 0;
              emit TollRenounced(msg.sender, who);
          }
          /// @inheritdoc IToll
          function tolled(address who) public view returns (bool) {
              return _buds[who] == 1;
          }
          /// @inheritdoc IToll
          /// @custom:invariant Only contains tolled addresses.
          ///                     ∀x ∊ tolled(): _tolled[x]
          /// @custom:invariant Contains all tolled addresses.
          ///                     ∀x ∊ Address: _tolled[x] == 1 → x ∊ tolled()
          function tolled() public view returns (address[] memory) {
              // Initiate array with upper limit length.
              address[] memory budsList = new address[](_budsTouched.length);
              // Iterate through all possible tolled addresses.
              uint ctr;
              for (uint i; i < budsList.length; i++) {
                  // Add address only if still tolled.
                  if (_buds[_budsTouched[i]] == 1) {
                      budsList[ctr++] = _budsTouched[i];
                  }
              }
              // Set length of array to number of tolled addresses actually included.
              assembly ("memory-safe") {
                  mstore(budsList, ctr)
              }
              return budsList;
          }
          /// @inheritdoc IToll
          function bud(address who) public view returns (uint) {
              return _buds[who];
          }
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      interface IAuth {
          /// @notice Thrown by protected function if caller not auth'ed.
          /// @param caller The caller's address.
          error NotAuthorized(address caller);
          /// @notice Emitted when auth granted to address.
          /// @param caller The caller's address.
          /// @param who The address auth got granted to.
          event AuthGranted(address indexed caller, address indexed who);
          /// @notice Emitted when auth renounced from address.
          /// @param caller The caller's address.
          /// @param who The address auth got renounced from.
          event AuthRenounced(address indexed caller, address indexed who);
          /// @notice Grants address `who` auth.
          /// @dev Only callable by auth'ed address.
          /// @param who The address to grant auth.
          function rely(address who) external;
          /// @notice Renounces address `who`'s auth.
          /// @dev Only callable by auth'ed address.
          /// @param who The address to renounce auth.
          function deny(address who) external;
          /// @notice Returns whether address `who` is auth'ed.
          /// @param who The address to check.
          /// @return True if `who` is auth'ed, false otherwise.
          function authed(address who) external view returns (bool);
          /// @notice Returns full list of addresses granted auth.
          /// @dev May contain duplicates.
          /// @return List of addresses granted auth.
          function authed() external view returns (address[] memory);
          /// @notice Returns whether address `who` is auth'ed.
          /// @custom:deprecated Use `authed(address)(bool)` instead.
          /// @param who The address to check.
          /// @return 1 if `who` is auth'ed, 0 otherwise.
          function wards(address who) external view returns (uint);
      }
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.16;
      interface IToll {
          /// @notice Thrown by protected function if caller not tolled.
          /// @param caller The caller's address.
          error NotTolled(address caller);
          /// @notice Emitted when toll granted to address.
          /// @param caller The caller's address.
          /// @param who The address toll got granted to.
          event TollGranted(address indexed caller, address indexed who);
          /// @notice Emitted when toll renounced from address.
          /// @param caller The caller's address.
          /// @param who The address toll got renounced from.
          event TollRenounced(address indexed caller, address indexed who);
          /// @notice Grants address `who` toll.
          /// @dev Only callable by auth'ed address.
          /// @param who The address to grant toll.
          function kiss(address who) external;
          /// @notice Renounces address `who`'s toll.
          /// @dev Only callable by auth'ed address.
          /// @param who The address to renounce toll.
          function diss(address who) external;
          /// @notice Returns whether address `who` is tolled.
          /// @param who The address to check.
          /// @return True if `who` is tolled, false otherwise.
          function tolled(address who) external view returns (bool);
          /// @notice Returns full list of addresses tolled.
          /// @dev May contain duplicates.
          /// @return List of addresses tolled.
          function tolled() external view returns (address[] memory);
          /// @notice Returns whether address `who` is tolled.
          /// @custom:deprecated Use `tolled(address)(bool)` instead.
          /// @param who The address to check.
          /// @return 1 if `who` is tolled, 0 otherwise.
          function bud(address who) external view returns (uint);
      }