diff --git a/abi/contracts/libraries/Suave.sol/Suave.json b/abi/contracts/libraries/Suave.sol/Suave.json index cac1eee..5171f4b 100644 --- a/abi/contracts/libraries/Suave.sol/Suave.json +++ b/abi/contracts/libraries/Suave.sol/Suave.json @@ -95,7 +95,7 @@ }, { "inputs": [], - "name": "ETHCALL", + "name": "ETHstaticcall", "outputs": [ { "internalType": "address", @@ -158,6 +158,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "NEW_BUILDER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "NEW_DATA_RECORD", @@ -171,6 +184,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "PRIVATE_KEY_GEN", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "SIGN_ETH_TRANSACTION", @@ -184,6 +210,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "SIGN_MESSAGE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "SIMULATE_BUNDLE", @@ -197,6 +236,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "SIMULATE_TRANSACTION", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "SUBMIT_BUNDLE_JSON_RPC", @@ -212,7 +264,7 @@ }, { "inputs": [], - "name": "SUBMIT_ETH_BLOCK_BID_TO_RELAY", + "name": "SUBMIT_ETH_BLOCK_TO_RELAY", "outputs": [ { "internalType": "address", diff --git a/abi/contracts/libraries/Transactions.sol/Transactions.json b/abi/contracts/libraries/Transactions.sol/Transactions.json new file mode 100644 index 0000000..8af6d3c --- /dev/null +++ b/abi/contracts/libraries/Transactions.sol/Transactions.json @@ -0,0 +1,31 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + } + ], + "name": "decodeSignature", + "outputs": [ + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "stateMutability": "pure", + "type": "function" + } +] diff --git a/abi/contracts/oracle/BinanceOracle.sol/BinanceOracle.json b/abi/contracts/oracle/BinanceOracle.sol/BinanceOracle.json new file mode 100644 index 0000000..b341fa6 --- /dev/null +++ b/abi/contracts/oracle/BinanceOracle.sol/BinanceOracle.json @@ -0,0 +1,269 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "PeekerReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "SuaveError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "message", + "type": "string" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "SuaveErrorWithData", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "PriceSubmission", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "DECIMALS", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_BUNDLE_ENDPOINT", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_CHAINID", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_CHAINID_STR", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "S_NAMESPACE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "URL_PARTIAL", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "confidentialConstructor", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Suave.DataId", + "name": "_pkBidId", + "type": "bytes16" + }, + { + "internalType": "address", + "name": "pkAddress", + "type": "address" + } + ], + "name": "confidentialConstructorCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "controller", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pkBidId", + "outputs": [ + { + "internalType": "Suave.DataId", + "name": "", + "type": "bytes16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "settlementBlockNum", + "type": "uint64" + } + ], + "name": "queryAndSubmit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "queryAndSubmitCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + } + ], + "name": "queryLatestPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/abi/contracts/oracle/SettlementContract.sol/OracleSettlementContract.json b/abi/contracts/oracle/SettlementContract.sol/OracleSettlementContract.json new file mode 100644 index 0000000..da8de80 --- /dev/null +++ b/abi/contracts/oracle/SettlementContract.sol/OracleSettlementContract.json @@ -0,0 +1,95 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "_controller", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "controller", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + } + ], + "name": "getPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "name": "latestPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newController", + "type": "address" + } + ], + "name": "setController", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "updatePrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/contracts/blockad/lib/Builder.sol b/contracts/blockad/lib/Builder.sol index 3896a03..1ab6492 100644 --- a/contracts/blockad/lib/Builder.sol +++ b/contracts/blockad/lib/Builder.sol @@ -43,7 +43,7 @@ contract Builder is EthBlockContract, SuaveContract { } function submitToRelay(bytes memory builderBid) internal view { - (bool success, bytes memory data) = Suave.SUBMIT_ETH_BLOCK_BID_TO_RELAY + (bool success, bytes memory data) = Suave.SUBMIT_ETH_BLOCK_TO_RELAY .staticcall(abi.encode(boostRelayUrl, builderBid)); if (!success) { revert SuaveErrorWithData(string(data), builderBid); diff --git a/contracts/libraries/Bundle.sol b/contracts/libraries/Bundle.sol new file mode 100644 index 0000000..6a31142 --- /dev/null +++ b/contracts/libraries/Bundle.sol @@ -0,0 +1,59 @@ +// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol + + +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.13; + +import "./Suave.sol"; +import "solady/src/utils/LibString.sol"; + +// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle +library Bundle { + struct BundleObj { + uint64 blockNumber; + uint64 minTimestamp; + uint64 maxTimestamp; + bytes[] txns; + } + + function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) { + Suave.HttpRequest memory request = encodeBundle(bundle); + request.url = url; + return Suave.doHTTPRequest(request); + } + + function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) { + require(args.txns.length > 0, "Bundle: no txns"); + + bytes memory params = + abi.encodePacked('{"blockNumber": "', LibString.toHexString(args.blockNumber), '", "txs": ['); + for (uint256 i = 0; i < args.txns.length; i++) { + params = abi.encodePacked(params, '"', LibString.toHexString(args.txns[i]), '"'); + if (i < args.txns.length - 1) { + params = abi.encodePacked(params, ","); + } else { + params = abi.encodePacked(params, "]"); + } + } + if (args.minTimestamp > 0) { + params = abi.encodePacked(params, ', "minTimestamp": ', LibString.toString(args.minTimestamp)); + } + if (args.maxTimestamp > 0) { + params = abi.encodePacked(params, ', "maxTimestamp": ', LibString.toString(args.maxTimestamp)); + } + params = abi.encodePacked(params, ', "maxTimestamp": ', LibString.toString(args.maxTimestamp)); + params = abi.encodePacked(params, "}"); + + bytes memory body = + abi.encodePacked('{"jsonrpc":"2.0","method":"eth_sendBundle","params":[', params, '],"id":1}'); + + Suave.HttpRequest memory request; + request.method = "POST"; + request.body = body; + request.headers = new string[](1); + request.headers[0] = "Content-Type: application/json"; + request.withFlashbotsSignature = true; + + return request; + } +} \ No newline at end of file diff --git a/contracts/libraries/RLPWriter.sol b/contracts/libraries/RLPWriter.sol new file mode 100644 index 0000000..43831e2 --- /dev/null +++ b/contracts/libraries/RLPWriter.sol @@ -0,0 +1,219 @@ +// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/** + * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode + * @title RLPWriter + * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's + * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor + * modifications to improve legibility. + */ +library RLPWriter { + /** + * @notice RLP encodes a byte string. + * + * @param _in The byte string to encode. + * + * @return The RLP encoded string in bytes. + */ + function writeBytes(bytes memory _in) internal pure returns (bytes memory) { + bytes memory encoded; + + if (_in.length == 1 && uint8(_in[0]) < 128) { + encoded = _in; + } else { + encoded = abi.encodePacked(_writeLength(_in.length, 128), _in); + } + + return encoded; + } + + /** + * @notice RLP encodes a list of RLP encoded byte byte strings. + * + * @param _in The list of RLP encoded byte strings. + * + * @return The RLP encoded list of items in bytes. + */ + function writeList(bytes[] memory _in) internal pure returns (bytes memory) { + bytes memory list = _flatten(_in); + return abi.encodePacked(_writeLength(list.length, 192), list); + } + + /** + * @notice RLP encodes a string. + * + * @param _in The string to encode. + * + * @return The RLP encoded string in bytes. + */ + function writeString(string memory _in) internal pure returns (bytes memory) { + return writeBytes(bytes(_in)); + } + + /** + * @notice RLP encodes an address. + * + * @param _in The address to encode. + * + * @return The RLP encoded address in bytes. + */ + function writeAddress(address _in) internal pure returns (bytes memory) { + return writeBytes(abi.encodePacked(_in)); + } + + /** + * @notice RLP encodes a uint. + * + * @param _in The uint256 to encode. + * + * @return The RLP encoded uint256 in bytes. + */ + function writeUint(uint256 _in) internal pure returns (bytes memory) { + return writeBytes(_toBinary(_in)); + } + + /** + * @notice RLP encodes a bool. + * + * @param _in The bool to encode. + * + * @return The RLP encoded bool in bytes. + */ + function writeBool(bool _in) internal pure returns (bytes memory) { + bytes memory encoded = new bytes(1); + encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80)); + return encoded; + } + + /** + * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55. + * + * @param _len The length of the string or the payload. + * @param _offset 128 if item is string, 192 if item is list. + * + * @return RLP encoded bytes. + */ + function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) { + bytes memory encoded; + + if (_len < 56) { + encoded = new bytes(1); + encoded[0] = bytes1(uint8(_len) + uint8(_offset)); + } else { + uint256 lenLen; + uint256 i = 1; + while (_len / i != 0) { + lenLen++; + i *= 256; + } + + encoded = new bytes(lenLen + 1); + encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55); + for (i = 1; i <= lenLen; i++) { + encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256)); + } + } + + return encoded; + } + + /** + * @notice Encode integer in big endian binary form with no leading zeroes. + * + * @param _x The integer to encode. + * + * @return RLP encoded bytes. + */ + function _toBinary(uint256 _x) private pure returns (bytes memory) { + bytes memory b = abi.encodePacked(_x); + + uint256 i = 0; + for (; i < 32; i++) { + if (b[i] != 0) { + break; + } + } + + bytes memory res = new bytes(32 - i); + for (uint256 j = 0; j < res.length; j++) { + res[j] = b[i++]; + } + + return res; + } + + /** + * @custom:attribution https://github.com/Arachnid/solidity-stringutils + * @notice Copies a piece of memory to another location. + * + * @param _dest Destination location. + * @param _src Source location. + * @param _len Length of memory to copy. + */ + function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure { + uint256 dest = _dest; + uint256 src = _src; + uint256 len = _len; + + for (; len >= 32; len -= 32) { + assembly { + mstore(dest, mload(src)) + } + dest += 32; + src += 32; + } + + uint256 mask; + unchecked { + mask = 256 ** (32 - len) - 1; + } + assembly { + let srcpart := and(mload(src), not(mask)) + let destpart := and(mload(dest), mask) + mstore(dest, or(destpart, srcpart)) + } + } + + /** + * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder + * @notice Flattens a list of byte strings into one byte string. + * + * @param _list List of byte strings to flatten. + * + * @return The flattened byte string. + */ + function _flatten(bytes[] memory _list) private pure returns (bytes memory) { + if (_list.length == 0) { + return new bytes(0); + } + + uint256 len; + uint256 i = 0; + for (; i < _list.length; i++) { + len += _list[i].length; + } + + bytes memory flattened = new bytes(len); + uint256 flattenedPtr; + assembly { + flattenedPtr := add(flattened, 0x20) + } + + for (i = 0; i < _list.length; i++) { + bytes memory item = _list[i]; + + uint256 listPtr; + assembly { + listPtr := add(item, 0x20) + } + + _memcpy(flattenedPtr, listPtr, item.length); + flattenedPtr += _list[i].length; + } + + return flattened; + } +} \ No newline at end of file diff --git a/contracts/libraries/Suave.sol b/contracts/libraries/Suave.sol index 2b83e9d..e6a5b83 100644 --- a/contracts/libraries/Suave.sol +++ b/contracts/libraries/Suave.sol @@ -4,6 +4,11 @@ pragma solidity ^0.8.8; library Suave { error PeekerReverted(address, bytes); + enum CryptoSignature { + SECP256, + BLS + } + type DataId is bytes16; struct BuildBlockArgs { @@ -34,6 +39,20 @@ library Suave { string method; string[] headers; bytes body; + bool withFlashbotsSignature; + } + + struct SimulateTransactionResult { + uint64 egp; + SimulatedLog[] logs; + bool success; + string error; + } + + struct SimulatedLog { + bytes data; + address addr; + bytes32[] topics; } struct Withdrawal { @@ -57,7 +76,7 @@ library Suave { address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002; - address public constant ETHCALL = 0x0000000000000000000000000000000042100003; + address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003; address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037; @@ -65,15 +84,23 @@ library Suave { address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001; + address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001; + address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000; + address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003; + address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001; + address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003; + address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000; + address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002; + address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001; - address public constant SUBMIT_ETH_BLOCK_BID_TO_RELAY = 0x0000000000000000000000000000000042100002; + address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002; // Returns whether execution is off- or on-chain function isConfidential() internal view returns (bool b) { @@ -120,8 +147,8 @@ library Suave { return data; } - function confidentialStore(DataId dataId, string memory key, bytes memory data1) internal view { - (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, data1)); + function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view { + (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value)); if (!success) { revert PeekerReverted(CONFIDENTIAL_STORE, data); } @@ -136,10 +163,10 @@ library Suave { return abi.decode(data, (bytes)); } - function ethcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) { - (bool success, bytes memory data) = ETHCALL.staticcall(abi.encode(contractAddr, input1)); + function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) { + (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1)); if (!success) { - revert PeekerReverted(ETHCALL, data); + revert PeekerReverted(ETHstaticcall, data); } return abi.decode(data, (bytes)); @@ -174,6 +201,15 @@ library Suave { return data; } + function newBuilder() internal view returns (string memory) { + (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode()); + if (!success) { + revert PeekerReverted(NEW_BUILDER, data); + } + + return abi.decode(data, (string)); + } + function newDataRecord( uint64 decryptionCondition, address[] memory allowedPeekers, @@ -189,6 +225,15 @@ library Suave { return abi.decode(data, (DataRecord)); } + function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) { + (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto)); + if (!success) { + revert PeekerReverted(PRIVATE_KEY_GEN, data); + } + + return abi.decode(data, (string)); + } + function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey) internal view @@ -202,6 +247,20 @@ library Suave { return abi.decode(data, (bytes)); } + function signMessage(bytes memory digest, CryptoSignature crypto, string memory signingKey) + internal + view + returns (bytes memory) + { + require(isConfidential()); + (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, crypto, signingKey)); + if (!success) { + revert PeekerReverted(SIGN_MESSAGE, data); + } + + return abi.decode(data, (bytes)); + } + function simulateBundle(bytes memory bundleData) internal view returns (uint64) { (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData)); if (!success) { @@ -211,6 +270,19 @@ library Suave { return abi.decode(data, (uint64)); } + function simulateTransaction(string memory sessionid, bytes memory txn) + internal + view + returns (SimulateTransactionResult memory) + { + (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn)); + if (!success) { + revert PeekerReverted(SIMULATE_TRANSACTION, data); + } + + return abi.decode(data, (SimulateTransactionResult)); + } + function submitBundleJsonRPC(string memory url, string memory method, bytes memory params) internal view @@ -225,15 +297,11 @@ library Suave { return data; } - function submitEthBlockBidToRelay(string memory relayUrl, bytes memory builderBid) - internal - view - returns (bytes memory) - { + function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) { require(isConfidential()); - (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_BID_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid)); + (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid)); if (!success) { - revert PeekerReverted(SUBMIT_ETH_BLOCK_BID_TO_RELAY, data); + revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data); } return data; diff --git a/contracts/libraries/Transactions.sol b/contracts/libraries/Transactions.sol new file mode 100644 index 0000000..2d31bf3 --- /dev/null +++ b/contracts/libraries/Transactions.sol @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.13; + +import "./RLPWriter.sol"; +import "./Suave.sol"; +import "solidity-rlp/contracts/RLPReader.sol"; + +library Transactions { + using RLPReader for RLPReader.RLPItem; + using RLPReader for RLPReader.Iterator; + using RLPReader for bytes; + + struct EIP155 { + address to; + uint256 gas; + uint256 gasPrice; + uint256 value; + uint256 nonce; + bytes data; + uint256 chainId; + bytes32 r; + bytes32 s; + uint64 v; + } + + struct EIP155Request { + address to; + uint256 gas; + uint256 gasPrice; + uint256 value; + uint256 nonce; + bytes data; + uint256 chainId; + } + + struct EIP1559 { + address to; + uint64 gas; + uint64 maxFeePerGas; + uint64 maxPriorityFeePerGas; + uint64 value; + uint64 nonce; + bytes data; + uint64 chainId; + bytes accessList; + bytes32 r; + bytes32 s; + uint64 v; + } + + struct EIP1559Request { + address to; + uint64 gas; + uint64 maxFeePerGas; + uint64 maxPriorityFeePerGas; + uint64 value; + uint64 nonce; + bytes data; + uint64 chainId; + bytes accessList; + } + + function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) { + bytes[] memory items = new bytes[](9); + + items[0] = RLPWriter.writeUint(txStruct.nonce); + items[1] = RLPWriter.writeUint(txStruct.gasPrice); + items[2] = RLPWriter.writeUint(txStruct.gas); + + if (txStruct.to == address(0)) { + items[3] = RLPWriter.writeBytes(bytes("")); + } else { + items[3] = RLPWriter.writeAddress(txStruct.to); + } + items[4] = RLPWriter.writeUint(txStruct.value); + items[5] = RLPWriter.writeBytes(txStruct.data); + items[6] = RLPWriter.writeUint(uint256(txStruct.v)); + items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r)); + items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s)); + + return RLPWriter.writeList(items); + } + + function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) { + bytes[] memory items = new bytes[](9); + + items[0] = RLPWriter.writeUint(txStruct.nonce); + items[1] = RLPWriter.writeUint(txStruct.gasPrice); + items[2] = RLPWriter.writeUint(txStruct.gas); + + if (txStruct.to == address(0)) { + items[3] = RLPWriter.writeBytes(bytes("")); + } else { + items[3] = RLPWriter.writeAddress(txStruct.to); + } + items[4] = RLPWriter.writeUint(txStruct.value); + items[5] = RLPWriter.writeBytes(txStruct.data); + items[6] = RLPWriter.writeUint(txStruct.chainId); + items[7] = RLPWriter.writeBytes(""); + items[8] = RLPWriter.writeBytes(""); + + return RLPWriter.writeList(items); + } + + function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) { + bytes[] memory items = new bytes[](12); + + items[0] = RLPWriter.writeUint(txStruct.chainId); + items[1] = RLPWriter.writeUint(txStruct.nonce); + items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas); + items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas); + items[4] = RLPWriter.writeUint(txStruct.gas); + + if (txStruct.to == address(0)) { + items[5] = RLPWriter.writeBytes(bytes("")); + } else { + items[5] = RLPWriter.writeAddress(txStruct.to); + } + + items[6] = RLPWriter.writeUint(txStruct.value); + items[7] = RLPWriter.writeBytes(txStruct.data); + + if (txStruct.accessList.length == 0) { + items[8] = hex"c0"; // Empty list encoding + } else { + items[8] = RLPWriter.writeBytes(txStruct.accessList); + } + + items[9] = RLPWriter.writeUint(uint256(txStruct.v)); + items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r)); + items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s)); + + bytes memory rlpTxn = RLPWriter.writeList(items); + + bytes memory txn = new bytes(1 + rlpTxn.length); + txn[0] = 0x02; + + for (uint256 i = 0; i < rlpTxn.length; ++i) { + txn[i + 1] = rlpTxn[i]; + } + + return txn; + } + + function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) { + bytes[] memory items = new bytes[](9); + + items[0] = RLPWriter.writeUint(txStruct.chainId); + items[1] = RLPWriter.writeUint(txStruct.nonce); + items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas); + items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas); + items[4] = RLPWriter.writeUint(txStruct.gas); + + if (txStruct.to == address(0)) { + items[5] = RLPWriter.writeBytes(bytes("")); + } else { + items[5] = RLPWriter.writeAddress(txStruct.to); + } + + items[6] = RLPWriter.writeUint(txStruct.value); + items[7] = RLPWriter.writeBytes(txStruct.data); + + if (txStruct.accessList.length == 0) { + items[8] = hex"c0"; // Empty list encoding + } else { + items[8] = RLPWriter.writeBytes(txStruct.accessList); + } + + bytes memory rlpTxn = RLPWriter.writeList(items); + + bytes memory txn = new bytes(1 + rlpTxn.length); + txn[0] = 0x02; + + for (uint256 i = 0; i < rlpTxn.length; ++i) { + txn[i + 1] = rlpTxn[i]; + } + + return txn; + } + + function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) { + EIP155 memory txStruct; + + RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList(); + require(ls.length == 9, "invalid transaction"); + + txStruct.nonce = uint64(ls[0].toUint()); + txStruct.gasPrice = uint64(ls[1].toUint()); + txStruct.gas = uint64(ls[2].toUint()); + + if (ls[3].toRlpBytes().length == 1) { + txStruct.to = address(0); + } else { + txStruct.to = ls[3].toAddress(); + } + + txStruct.value = uint64(ls[4].toUint()); + txStruct.data = ls[5].toBytes(); + txStruct.v = uint64(ls[6].toUint()); + txStruct.r = bytesToBytes32(ls[7].toBytes()); + txStruct.s = bytesToBytes32(ls[8].toBytes()); + + return txStruct; + } + + function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) { + EIP155Request memory txStruct; + + RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList(); + require(ls.length == 9, "invalid transaction"); + + txStruct.nonce = ls[0].toUint(); + txStruct.gasPrice = ls[1].toUint(); + txStruct.gas = ls[2].toUint(); + + if (ls[3].toRlpBytes().length == 1) { + txStruct.to = address(0); + } else { + txStruct.to = ls[3].toAddress(); + } + + txStruct.value = ls[4].toUint(); + txStruct.data = ls[5].toBytes(); + txStruct.chainId = uint64(ls[6].toUint()); + + return txStruct; + } + + function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) { + EIP1559 memory txStruct; + + bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1); + + for (uint256 i = 0; i < rlp.length - 1; ++i) { + rlpWithoutPrefix[i] = rlp[i + 1]; + } + + RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList(); + require(ls.length == 12, "invalid transaction"); + + txStruct.chainId = uint64(ls[0].toUint()); + txStruct.nonce = uint64(ls[1].toUint()); + txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint()); + txStruct.maxFeePerGas = uint64(ls[3].toUint()); + txStruct.gas = uint64(ls[4].toUint()); + + if (ls[5].toRlpBytes().length == 1) { + txStruct.to = address(0); + } else { + txStruct.to = ls[5].toAddress(); + } + + txStruct.value = uint64(ls[6].toUint()); + txStruct.data = ls[7].toBytes(); + txStruct.accessList = ls[8].toBytes(); + txStruct.v = uint64(ls[9].toUint()); + txStruct.r = bytesToBytes32(ls[10].toBytes()); + txStruct.s = bytesToBytes32(ls[11].toBytes()); + + return txStruct; + } + + function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) { + EIP1559Request memory txStruct; + + bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1); + + for (uint256 i = 0; i < rlp.length - 1; ++i) { + rlpWithoutPrefix[i] = rlp[i + 1]; + } + + RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList(); + require(ls.length == 8, "invalid transaction"); + + txStruct.chainId = uint64(ls[0].toUint()); + txStruct.nonce = uint64(ls[1].toUint()); + txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint()); + txStruct.maxFeePerGas = uint64(ls[3].toUint()); + txStruct.gas = uint64(ls[4].toUint()); + + if (ls[5].toRlpBytes().length == 1) { + txStruct.to = address(0); + } else { + txStruct.to = ls[5].toAddress(); + } + + txStruct.value = uint64(ls[6].toUint()); + txStruct.data = ls[7].toBytes(); + + return txStruct; + } + + function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) { + require(inBytes.length == 32, "bytesToBytes32: invalid input length"); + assembly { + out := mload(add(inBytes, 32)) + } + } + + function signTxn(Transactions.EIP1559Request memory request, string memory signingKey) + internal + view + returns (Transactions.EIP1559 memory response) + { + bytes memory rlp = Transactions.encodeRLP(request); + bytes memory hash = abi.encodePacked(keccak256(rlp)); + bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey); + (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature); + + response.to = request.to; + response.gas = request.gas; + response.maxFeePerGas = request.maxFeePerGas; + response.maxPriorityFeePerGas = request.maxPriorityFeePerGas; + response.value = request.value; + response.nonce = request.nonce; + response.data = request.data; + response.chainId = request.chainId; + response.accessList = request.accessList; + response.v = v; + response.r = r; + response.s = s; + + return response; + } + + function signTxn(Transactions.EIP155Request memory request, string memory signingKey) + internal + view + returns (Transactions.EIP155 memory response) + { + bytes memory rlp = Transactions.encodeRLP(request); + bytes memory hash = abi.encodePacked(keccak256(rlp)); + bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey); + + // TODO: check overflow + uint64 chainIdMul = uint64(request.chainId) * 2; + (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature); + + uint64 v64 = uint64(v) + 35; + v64 += chainIdMul; + + response.to = request.to; + response.gas = request.gas; + response.gasPrice = request.gasPrice; + response.value = request.value; + response.nonce = request.nonce; + response.data = request.data; + response.chainId = request.chainId; + response.v = v64; + response.r = r; + response.s = s; + + return response; + } + + function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) { + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + } +} \ No newline at end of file diff --git a/contracts/oracle/BinanceOracle.sol b/contracts/oracle/BinanceOracle.sol new file mode 100644 index 0000000..d05a175 --- /dev/null +++ b/contracts/oracle/BinanceOracle.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +// Author: Miha Lotric (halo3mic) + +pragma solidity ^0.8.13; + +import { AnyBundleContract, Suave } from "../standard_peekers/bids.sol"; +import { SuaveContract } from "../blockad/lib/SuaveContract.sol"; +import "../../node_modules/solady/src/utils/JSONParserLib.sol"; +import "../libraries/Transactions.sol"; +import "../libraries/Bundle.sol"; +import "solady/src/utils/LibString.sol"; + + +contract BinanceOracle is SuaveContract { + using JSONParserLib for *; + + uint public constant GOERLI_CHAINID = 5; + string public constant GOERLI_CHAINID_STR = "0x5"; + uint8 public constant DECIMALS = 4; + string public constant S_NAMESPACE = "oracle:v0:pksecret"; + string public constant INFURA_GOERLI_RPC = "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"; + string public constant URL_PARTIAL = "https://data-api.binance.vision/api/v3/ticker/price?symbol="; + string public constant GOERLI_BUNDLE_ENDPOINT = "https://relay-goerli.flashbots.net"; + + bool isInitialized; + Suave.DataId public pkBidId; + address public controller; + address public settlementContract; + + event PriceSubmission(string ticker, uint price); + + // ⛓️ EVM Methods + + function confidentialConstructorCallback( + Suave.DataId _pkBidId, + address pkAddress + ) public { + crequire(!isInitialized, "Already initialized"); + pkBidId = _pkBidId; + controller = pkAddress; + isInitialized = true; + } + + function registerCallback(address _settlementContract) public { + require(_settlementContract == settlementContract || settlementContract == address(0), "Already registered"); + settlementContract = _settlementContract; + } + + // ! Warning: This method is not restricted and emitted events should not be relied upon + function queryAndSubmitCallback(string memory ticker, uint price) public { + emit PriceSubmission(ticker, price); + } + + fallback() external payable { + // Needed to accept MEVM calls with no callbacks + } + + // 🤐 MEVM Methods + + function confidentialConstructor() external view onlyConfidential returns (bytes memory) { + crequire(!isInitialized, "Already initialized"); + + string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256); + address pkAddress = getAddressForPk(pk); + Suave.DataId bidId = storePK(bytes(pk)); + + return abi.encodeWithSelector( + this.confidentialConstructorCallback.selector, + bidId, + pkAddress + ); + } + + function registerSettlementContract( + address _settlementContract + ) external view onlyConfidential() returns (bytes memory) { + require(settlementContract == address(0), "Already registered"); + bytes memory signedTx = createRegisterTx(_settlementContract); + sendRawTx(signedTx); + return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract); + } + + function queryAndSubmit( + string memory ticker, + uint nonce, + uint gasPrice, + uint64 settlementBlockNum, + bool privateSubmission + ) external view onlyConfidential returns (bytes memory) { + uint price = queryLatestPrice(ticker); + submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum, privateSubmission); + return abi.encodeWithSelector(this.queryAndSubmitCallback.selector, ticker, price); + } + + function queryLatestPrice(string memory ticker) public view returns (uint price) { + bytes memory response = doBinanceQuery(ticker); + JSONParserLib.Item memory parsedRes = string(response).parse(); + // solhint-disable-next-line + string memory priceStr = string(parsedRes.at('"price"').value()); + price = floatToInt(trimStrEdges(priceStr), DECIMALS); + } + + function submitPriceUpdate( + string memory ticker, + uint price, + uint nonce, + uint gasPrice, + uint64 settlementBlockNum, + bool privateSubmission + ) internal view { + bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice); + if (privateSubmission) { + sendBundle(signedTx, settlementBlockNum); + } else { + sendRawTx(signedTx); + } + } + + function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) { + Transactions.EIP155 memory transaction = Transactions.EIP155({ + nonce: 0, + gasPrice: 100 gwei, + gas: 100_000, + to: _settlementContract, + value: 0, + data: abi.encodeWithSignature("register()"), + chainId: GOERLI_CHAINID, + v: 27, + r: hex"1111111111111111111111111111111111111111111111111111111111111111", + s: hex"1111111111111111111111111111111111111111111111111111111111111111" + }); + bytes memory txRlp = Transactions.encodeRLP(transaction); + string memory pk = retreivePK(); + txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk); + } + + function createPriceUpdateTx( + string memory ticker, + uint price, + uint nonce, + uint gasPrice + ) internal view returns (bytes memory txSigned) { + Transactions.EIP155 memory transaction = Transactions.EIP155({ + nonce: nonce, + gasPrice: gasPrice, + gas: 100_000, + to: settlementContract, + value: 0, + data: abi.encodeWithSignature("updatePrice(string,uint256)", ticker, price), + chainId: GOERLI_CHAINID, + v: 27, + r: hex"1111111111111111111111111111111111111111111111111111111111111111", + s: hex"1111111111111111111111111111111111111111111111111111111111111111" + }); + bytes memory txRlp = Transactions.encodeRLP(transaction); + string memory pk = retreivePK(); + txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk); + } + + function sendRawTx(bytes memory txSigned) public view returns (bytes memory) { + /* solhint-disable */ + bytes memory body = abi.encodePacked( + '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["', + LibString.toHexString(txSigned), + '"],"id":1}' + ); + /* solhint-enable */ + Suave.HttpRequest memory request; + request.method = "POST"; + request.body = body; + request.headers = new string[](1); + request.headers[0] = "Content-Type: application/json"; + request.withFlashbotsSignature = false; + request.url = INFURA_GOERLI_RPC; + return doHttpRequest(request); + } + + function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view { + simulateTx(txSigned); + sendTxViaBundle(txSigned, settlementBlockNum); + } + + function simulateTx(bytes memory signedTx) internal view { + // solhint-disable-next-line + bytes memory bundle = abi.encodePacked('{"txs": ["', LibString.toHexString(signedTx), '"]}'); + (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle)); + crequire(successSim, string(abi.encodePacked("BundleSimulationFailed: ", string(data)))); + } + + function doBinanceQuery(string memory ticker) internal view returns (bytes memory) { + string[] memory headers = new string[](1); + headers[0] = "Content-Type: application/json"; + Suave.HttpRequest memory request = Suave.HttpRequest({ + url: string(abi.encodePacked(URL_PARTIAL, ticker)), + method: "GET", + headers: headers, + body: new bytes(0), + withFlashbotsSignature: false + }); + return doHttpRequest(request); + } + + function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) { + (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request)); + crequire(success, string(data)); + return abi.decode(data, (bytes)); + } + + function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view { + bytes[] memory txns = new bytes[](1); + txns[0] = txSigned; + bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum); + (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode( + GOERLI_BUNDLE_ENDPOINT, + "eth_sendBundle", + bundleReqParams + )); + crequire(successReq, string(abi.encodePacked("BundleSubmissionFailed: ", string(dataReq)))); + } + + function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) { + // solhint-disable-next-line + bytes memory params = abi.encodePacked('{"blockNumber": "', LibString.toHexString(blockNumber), '", "txs": ['); + for (uint256 i = 0; i < txns.length; i++) { + // solhint-disable-next-line + params = abi.encodePacked(params, '"', LibString.toHexString(txns[i]), '"'); + if (i < txns.length - 1) { + params = abi.encodePacked(params, ","); + } else { + params = abi.encodePacked(params, "]"); + } + } + params = abi.encodePacked(params, "}"); + + return params; + } + + function storePK(bytes memory pk) internal view returns (Suave.DataId) { + address[] memory peekers = new address[](3); + peekers[0] = address(this); + peekers[1] = Suave.FETCH_DATA_RECORDS; + peekers[2] = Suave.CONFIDENTIAL_RETRIEVE; + Suave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE); + Suave.confidentialStore(secretBid.id, S_NAMESPACE, pk); + return secretBid.id; + } + + function retreivePK() internal view returns (string memory) { + bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE); + return string(pkBytes); + } + +} + +// 🔧 Utils + +function floatToInt(string memory floatString, uint8 decimals) pure returns (uint) { + bytes memory stringBytes = bytes(floatString); + uint dotPosition; + + // Find the position of the dot + for (uint i = 0; i < stringBytes.length; i++) { + if (stringBytes[i] == 0x2E) { + dotPosition = i; + break; + } + } + + uint integerPart = 0; + uint decimalPart = 0; + uint tenPower = 1; + + // Convert integer part + for (uint i = dotPosition; i > 0; i--) { + integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower; + tenPower *= 10; + } + // Reset power of ten + tenPower = 1; + // Convert decimal part + for (uint i = dotPosition+decimals; i > dotPosition; i--) { + decimalPart += (uint8(stringBytes[i]) - 48) * tenPower; + tenPower *= 10; + } + // Combine integer and decimal parts + return integerPart * (10**decimals) + decimalPart; +} + +function trimStrEdges(string memory _input) pure returns (string memory) { + bytes memory input = bytes(_input); + require(input.length > 2, "Input too short"); + + uint newLength = input.length - 2; + bytes memory result = new bytes(newLength); + + assembly { + let inputPtr := add(input, 0x21) + let resultPtr := add(result, 0x20) + let length := mload(input) + mstore(resultPtr, mload(inputPtr)) + mstore(result, newLength) + } + return string(result); +} + +function getAddressForPk(string memory pk) view returns (address) { + bytes32 digest = keccak256(abi.encode("yo")); + bytes memory sig = Suave.signMessage(abi.encodePacked(digest), Suave.CryptoSignature.SECP256, pk); + return recoverSigner(digest, sig); +} + +function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) { + (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature); + return ecrecover(_ethSignedMessageHash, v, r, s); +} + +function splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) { + require(sig.length == 65, "invalid signature length"); + assembly { + r := mload(add(sig, 32)) + s := mload(add(sig, 64)) + v := byte(0, mload(add(sig, 96))) + } + if (v < 27) { + v += 27; + } +} \ No newline at end of file diff --git a/contracts/oracle/SettlementContract.sol b/contracts/oracle/SettlementContract.sol new file mode 100644 index 0000000..1d0d88a --- /dev/null +++ b/contracts/oracle/SettlementContract.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.13; + + +contract OracleSettlementContract { + + struct PriceUpdate { + uint price; + uint blockNumber; + } + + event PriceUpdated(string ticker, uint price); + + mapping(string => PriceUpdate) public latestPriceUpdate; + address public controller; + + function register() external { + require(controller == address(0), "Already registered"); + controller = msg.sender; + } + + function updatePrice(string memory ticker, uint price) external { + require(msg.sender == controller, "Only controller"); + latestPriceUpdate[ticker] = PriceUpdate(price, block.number); + emit PriceUpdated(ticker, price); + } + +} \ No newline at end of file diff --git a/contracts/standard_peekers/bids.sol b/contracts/standard_peekers/bids.sol index 297f8dc..aff8a76 100644 --- a/contracts/standard_peekers/bids.sol +++ b/contracts/standard_peekers/bids.sol @@ -358,7 +358,7 @@ contract EthBlockBidSenderContract is EthBlockContract { (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) = this.doBuild(blockArgs, blockHeight, dataRecords, namespace); - Suave.submitEthBlockBidToRelay(boostRelayUrl, builderBid); + Suave.submitEthBlockToRelay(boostRelayUrl, builderBid); emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers); return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord)); diff --git a/deploy/deploy-utils.ts b/deploy/deploy-utils.ts index 773a972..e790d72 100644 --- a/deploy/deploy-utils.ts +++ b/deploy/deploy-utils.ts @@ -4,17 +4,32 @@ export interface DeployOptions { contractName: string, args: Array, tags: Array, - optionalArgs?: Map + optionalArgs?: Record } -export function makeDeployCallback(deployOptions: DeployOptions): any { - const exportEnv = _makeDeployCallback(deployOptions) +export function makeDeployCallback( + deployOptions: DeployOptions, + preDeployCallback?: any, + postDeployCallback?: any +): any { + const exportEnv = _makeDeployCallback( + deployOptions, + preDeployCallback, + postDeployCallback + ) exportEnv.tags = deployOptions.tags return exportEnv } -function _makeDeployCallback(deployOptions: DeployOptions): any { +function _makeDeployCallback( + deployOptions: DeployOptions, + preDeployCallback?: any, + postDeployCallback?: any +): any { return async ({ getNamedAccounts, deployments }) => { + if (preDeployCallback) + await preDeployCallback(deployments) + const { deploy, log } = deployments const { deployer } = await getNamedAccounts() @@ -24,7 +39,7 @@ function _makeDeployCallback(deployOptions: DeployOptions): any { contract: deployOptions.contractName, args: deployOptions.args, gas: 1.5e5, - skipIfAlreadyDeployed: false, + skipIfAlreadyDeployed: false, ...deployOptions.optionalArgs }) @@ -33,5 +48,7 @@ function _makeDeployCallback(deployOptions: DeployOptions): any { } else { log(`- Deployment skipped, using previous deployment at: ${deployResult.address}`) } + if (postDeployCallback) + await postDeployCallback(deployments, deployResult) } } \ No newline at end of file diff --git a/deploy/suave-demo/binance-oracle.ts b/deploy/suave-demo/binance-oracle.ts new file mode 100644 index 0000000..c70c82b --- /dev/null +++ b/deploy/suave-demo/binance-oracle.ts @@ -0,0 +1,74 @@ +import { SuaveProvider, SuaveWallet, SuaveContract } from 'ethers-suave' +import { ethers } from 'hardhat' +import * as hh from 'hardhat' +import { makeDeployCallback, DeployOptions } from '../deploy-utils' +import { getEnvValSafe } from '../../src/utils' + +const deployOptions: DeployOptions = { + name: 'BinanceOracle', + contractName: 'BinanceOracle', + args: [ ], + tags: [ 'binance-oracle' ] +} + +const beforeCallback = async () => { + const isSettlementDeployed = !!(await (hh.companionNetworks['goerli'] as any) + .deployments.getOrNull('OracleSettlementContract')) + if (!isSettlementDeployed) { + throw new Error('OracleSettlementContract must be deployed first') + } +} + +const afterCallaback = async (deployments: any, deployResult: any) => { + const goerliProvider = new ethers.providers.JsonRpcProvider(getEnvValSafe('GOERLI_RPC')) + const goerliSigner = new ethers.Wallet(getEnvValSafe('GOERLI_PK'), goerliProvider) + + const networkConfig: any = hh.network.config + const suaveProvider = new SuaveProvider( + networkConfig.url, + getEnvValSafe('EXECUTION_NODE') // todo: make variable (now needs to be changed in .env) + ) + const suaveWallet = new SuaveWallet(networkConfig.accounts[0], suaveProvider) + const OracleContract = new SuaveContract(deployResult.address, deployResult.abi, suaveWallet) + + // 1. Init the Oracle + deployments.log('\t1.) Initalizing OracleContract') + const initRes = await OracleContract.confidentialConstructor + .sendConfidentialRequest({}) + const receipt = await initRes.wait() + if (receipt.status == 0) + throw new Error('ConfidentialInit callback failed') + + // 2. Pay the controller for gas on the settlement chain + deployments.log('\t2.) Sending controller funds for gas') + const controllerAddress = await OracleContract.controller() + await goerliSigner.sendTransaction({ + to: controllerAddress, + value: ethers.utils.parseEther('0.02') + }) + .then(tx => tx.wait()) + .then(receipt => { + if (!receipt.status) { + throw new Error('Failed to send gas to controller') + } + }) + + // 3. Register the settlement contract + deployments.log('\t3.) Registering settlement contract') + const OracleSettlementContract = await (hh.companionNetworks['goerli'] as any) + .deployments.get('OracleSettlementContract') + const registerRes = await OracleContract.registerSettlementContract + .sendConfidentialRequest(OracleSettlementContract.address) + const registerReceipt = await registerRes.wait() + if (registerReceipt.status == 0) + throw new Error('ConfidentialInit callback failed') + + console.log(`Controller: ${controllerAddress} | SettlementContract: ${OracleSettlementContract.address}`) + console.log('Complete 🎉') +} + + +module.exports = makeDeployCallback(deployOptions, beforeCallback, afterCallaback) + + + diff --git a/deploy/suave-demo/oracle-settlement.ts b/deploy/suave-demo/oracle-settlement.ts new file mode 100644 index 0000000..203004e --- /dev/null +++ b/deploy/suave-demo/oracle-settlement.ts @@ -0,0 +1,10 @@ +import { makeDeployCallback, DeployOptions } from '../deploy-utils' + +const deployOptions: DeployOptions = { + name: 'OracleSettlementContract', + contractName: 'OracleSettlementContract', + args: [], + tags: [ 'oracle-settlement' ] +} + +module.exports = makeDeployCallback(deployOptions) diff --git a/deploy/suave-demo/oracle.ts b/deploy/suave-demo/oracle.ts new file mode 100644 index 0000000..20aea57 --- /dev/null +++ b/deploy/suave-demo/oracle.ts @@ -0,0 +1,11 @@ +import { makeDeployCallback, DeployOptions } from '../deploy-utils' + + +const deployOptions: DeployOptions = { + name: 'BinanceOracle', + contractName: 'BinanceOracle', + args: [ ], + tags: [ 'oracle' ] +} + +module.exports = makeDeployCallback(deployOptions) diff --git a/deployments/goerli/.chainId b/deployments/goerli/.chainId new file mode 100644 index 0000000..7813681 --- /dev/null +++ b/deployments/goerli/.chainId @@ -0,0 +1 @@ +5 \ No newline at end of file diff --git a/deployments/goerli/OracleSettlementContract.json b/deployments/goerli/OracleSettlementContract.json new file mode 100644 index 0000000..2a52f26 --- /dev/null +++ b/deployments/goerli/OracleSettlementContract.json @@ -0,0 +1,185 @@ +{ + "address": "0x04841Bd5F6f1f0BAb87A06EA3F584e9f9Af18556", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "PriceUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "controller", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "name": "latestPriceUpdate", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "blockNumber", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "register", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "updatePrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "transactionHash": "0xd035c7bc3b77861c8624194bdc4c95d0b4b4a184a3bec7ce195de76b50da40f4", + "receipt": { + "to": null, + "from": "0x16f2Aa8dF055b6e672b93Ded41FecCCabAB565B0", + "contractAddress": "0x04841Bd5F6f1f0BAb87A06EA3F584e9f9Af18556", + "transactionIndex": 25, + "gasUsed": "491233", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x5c5242edde583527c1306296af94476c57fa2a14c45a23e25ced7ef4145ffefd", + "transactionHash": "0xd035c7bc3b77861c8624194bdc4c95d0b4b4a184a3bec7ce195de76b50da40f4", + "logs": [], + "blockNumber": 10595815, + "cumulativeGasUsed": "16352977", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "62774477dfdbdfcb4315093cb081bd94", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"PriceUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"latestPriceUpdate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"updatePrice\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/oracle/SettlementContract.sol\":\"OracleSettlementContract\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/oracle/SettlementContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.13;\\n\\n\\ncontract OracleSettlementContract {\\n\\n struct PriceUpdate {\\n uint price;\\n uint blockNumber;\\n }\\n\\n event PriceUpdated(string ticker, uint price);\\n\\n mapping(string => PriceUpdate) public latestPriceUpdate;\\n address public controller;\\n\\n function register() external {\\n require(controller == address(0), \\\"Already registered\\\");\\n controller = msg.sender;\\n }\\n\\n function updatePrice(string memory ticker, uint price) external {\\n require(msg.sender == controller, \\\"Only controller\\\");\\n latestPriceUpdate[ticker] = PriceUpdate(price, block.number);\\n emit PriceUpdated(ticker, price);\\n }\\n\\n}\",\"keccak256\":\"0x671aa4224e2da17aed478072fe7a5416b52bbb8d8e84cccd37a58262d8abd536\",\"license\":\"MIT\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506107f3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631aa3a008146100515780634a432a461461005b5780634d4c8bf114610077578063f77c4791146100a8575b600080fd5b6100596100c6565b005b610075600480360381019061007091906104a1565b61019a565b005b610091600480360381019061008c91906104fd565b6102b1565b60405161009f929190610555565b60405180910390f35b6100b06102eb565b6040516100bd91906105bf565b60405180910390f35b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014e90610637565b60405180910390fd5b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461022a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610221906106a3565b60405180910390fd5b60405180604001604052808281526020014381525060008360405161024f919061073d565b908152602001604051809103902060008201518160000155602082015181600101559050507f159e83f4712ba2552e68be9d848e49bf6dd35c24f19564ffd523b6549450a2f482826040516102a592919061078d565b60405180910390a15050565b6000818051602081018201805184825260208301602085012081835280955050505050506000915090508060000154908060010154905082565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6103788261032f565b810181811067ffffffffffffffff8211171561039757610396610340565b5b80604052505050565b60006103aa610311565b90506103b6828261036f565b919050565b600067ffffffffffffffff8211156103d6576103d5610340565b5b6103df8261032f565b9050602081019050919050565b82818337600083830152505050565b600061040e610409846103bb565b6103a0565b90508281526020810184848401111561042a5761042961032a565b5b6104358482856103ec565b509392505050565b600082601f83011261045257610451610325565b5b81356104628482602086016103fb565b91505092915050565b6000819050919050565b61047e8161046b565b811461048957600080fd5b50565b60008135905061049b81610475565b92915050565b600080604083850312156104b8576104b761031b565b5b600083013567ffffffffffffffff8111156104d6576104d5610320565b5b6104e28582860161043d565b92505060206104f38582860161048c565b9150509250929050565b6000602082840312156105135761051261031b565b5b600082013567ffffffffffffffff81111561053157610530610320565b5b61053d8482850161043d565b91505092915050565b61054f8161046b565b82525050565b600060408201905061056a6000830185610546565b6105776020830184610546565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a98261057e565b9050919050565b6105b98161059e565b82525050565b60006020820190506105d460008301846105b0565b92915050565b600082825260208201905092915050565b7f416c726561647920726567697374657265640000000000000000000000000000600082015250565b60006106216012836105da565b915061062c826105eb565b602082019050919050565b6000602082019050818103600083015261065081610614565b9050919050565b7f4f6e6c7920636f6e74726f6c6c65720000000000000000000000000000000000600082015250565b600061068d600f836105da565b915061069882610657565b602082019050919050565b600060208201905081810360008301526106bc81610680565b9050919050565b600081519050919050565b600081905092915050565b60005b838110156106f75780820151818401526020810190506106dc565b83811115610706576000848401525b50505050565b6000610717826106c3565b61072181856106ce565b93506107318185602086016106d9565b80840191505092915050565b6000610749828461070c565b915081905092915050565b600061075f826106c3565b61076981856105da565b93506107798185602086016106d9565b6107828161032f565b840191505092915050565b600060408201905081810360008301526107a78185610754565b90506107b66020830184610546565b939250505056fea2646970667358221220b155c039efe094d26cee6a0152b7aa7870a6534434a49ef0bda933fd6a61801e64736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80631aa3a008146100515780634a432a461461005b5780634d4c8bf114610077578063f77c4791146100a8575b600080fd5b6100596100c6565b005b610075600480360381019061007091906104a1565b61019a565b005b610091600480360381019061008c91906104fd565b6102b1565b60405161009f929190610555565b60405180910390f35b6100b06102eb565b6040516100bd91906105bf565b60405180910390f35b600073ffffffffffffffffffffffffffffffffffffffff16600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610157576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161014e90610637565b60405180910390fd5b33600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461022a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610221906106a3565b60405180910390fd5b60405180604001604052808281526020014381525060008360405161024f919061073d565b908152602001604051809103902060008201518160000155602082015181600101559050507f159e83f4712ba2552e68be9d848e49bf6dd35c24f19564ffd523b6549450a2f482826040516102a592919061078d565b60405180910390a15050565b6000818051602081018201805184825260208301602085012081835280955050505050506000915090508060000154908060010154905082565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6103788261032f565b810181811067ffffffffffffffff8211171561039757610396610340565b5b80604052505050565b60006103aa610311565b90506103b6828261036f565b919050565b600067ffffffffffffffff8211156103d6576103d5610340565b5b6103df8261032f565b9050602081019050919050565b82818337600083830152505050565b600061040e610409846103bb565b6103a0565b90508281526020810184848401111561042a5761042961032a565b5b6104358482856103ec565b509392505050565b600082601f83011261045257610451610325565b5b81356104628482602086016103fb565b91505092915050565b6000819050919050565b61047e8161046b565b811461048957600080fd5b50565b60008135905061049b81610475565b92915050565b600080604083850312156104b8576104b761031b565b5b600083013567ffffffffffffffff8111156104d6576104d5610320565b5b6104e28582860161043d565b92505060206104f38582860161048c565b9150509250929050565b6000602082840312156105135761051261031b565b5b600082013567ffffffffffffffff81111561053157610530610320565b5b61053d8482850161043d565b91505092915050565b61054f8161046b565b82525050565b600060408201905061056a6000830185610546565b6105776020830184610546565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a98261057e565b9050919050565b6105b98161059e565b82525050565b60006020820190506105d460008301846105b0565b92915050565b600082825260208201905092915050565b7f416c726561647920726567697374657265640000000000000000000000000000600082015250565b60006106216012836105da565b915061062c826105eb565b602082019050919050565b6000602082019050818103600083015261065081610614565b9050919050565b7f4f6e6c7920636f6e74726f6c6c65720000000000000000000000000000000000600082015250565b600061068d600f836105da565b915061069882610657565b602082019050919050565b600060208201905081810360008301526106bc81610680565b9050919050565b600081519050919050565b600081905092915050565b60005b838110156106f75780820151818401526020810190506106dc565b83811115610706576000848401525b50505050565b6000610717826106c3565b61072181856106ce565b93506107318185602086016106d9565b80840191505092915050565b6000610749828461070c565b915081905092915050565b600061075f826106c3565b61076981856105da565b93506107798185602086016106d9565b6107828161032f565b840191505092915050565b600060408201905081810360008301526107a78185610754565b90506107b66020830184610546565b939250505056fea2646970667358221220b155c039efe094d26cee6a0152b7aa7870a6534434a49ef0bda933fd6a61801e64736f6c634300080d0033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 4408, + "contract": "contracts/oracle/SettlementContract.sol:OracleSettlementContract", + "label": "latestPriceUpdate", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_string_memory_ptr,t_struct(PriceUpdate)4397_storage)" + }, + { + "astId": 4410, + "contract": "contracts/oracle/SettlementContract.sol:OracleSettlementContract", + "label": "controller", + "offset": 0, + "slot": "1", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_mapping(t_string_memory_ptr,t_struct(PriceUpdate)4397_storage)": { + "encoding": "mapping", + "key": "t_string_memory_ptr", + "label": "mapping(string => struct OracleSettlementContract.PriceUpdate)", + "numberOfBytes": "32", + "value": "t_struct(PriceUpdate)4397_storage" + }, + "t_string_memory_ptr": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(PriceUpdate)4397_storage": { + "encoding": "inplace", + "label": "struct OracleSettlementContract.PriceUpdate", + "members": [ + { + "astId": 4394, + "contract": "contracts/oracle/SettlementContract.sol:OracleSettlementContract", + "label": "price", + "offset": 0, + "slot": "0", + "type": "t_uint256" + }, + { + "astId": 4396, + "contract": "contracts/oracle/SettlementContract.sol:OracleSettlementContract", + "label": "blockNumber", + "offset": 0, + "slot": "1", + "type": "t_uint256" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "encoding": "inplace", + "label": "uint256", + "numberOfBytes": "32" + } + } + } +} \ No newline at end of file diff --git a/deployments/goerli/solcInputs/62774477dfdbdfcb4315093cb081bd94.json b/deployments/goerli/solcInputs/62774477dfdbdfcb4315093cb081bd94.json new file mode 100644 index 0000000..47a6248 --- /dev/null +++ b/deployments/goerli/solcInputs/62774477dfdbdfcb4315093cb081bd94.json @@ -0,0 +1,68 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen() internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, string memory signingKey) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "/**\nTODO:\n* Settlement contract\n* Optional Backrunning\n* Coinbase API\n */\n\n// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport { floatToInt, trimStrEdges, getAddressForPk } from \"./lib/Utils.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress,\n address _settlementContract\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n settlementContract = _settlementContract;\n isInitialized = true;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor(address _settlementContract) external onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen();\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress,\n _settlementContract\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n }\n\n function queryAndSubmit(\n string memory ticker, \n uint nonce, \n uint64 settlementBlockNum\n ) external onlyConfidential returns (uint) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(price, nonce, settlementBlockNum);\n return price;\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n uint price, \n uint nonce,\n uint64 settlementBlockNum\n ) internal {\n bytes memory signedTx = createPriceUpdateTx(price, nonce);\n sendBundle(signedTx, settlementBlockNum);\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 80 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(uint price, uint nonce) internal returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: address(0),\n value: 0,\n data: abi.encode(price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}" + }, + "contracts/oracle/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\n// 🚨 THIS IS UNTESTED DEMO CODE - DONT USE IN PRODUCTION 🚨\n\n\npragma solidity ^0.8.8;\n\nimport '../../libraries/Suave.sol';\n\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Reset power of ten\n tenPower = 1;\n \n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/oracle/SettlementContract.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\n\ncontract OracleSettlementContract {\n\n struct PriceUpdate {\n uint price;\n uint blockNumber;\n }\n\n event PriceUpdated(string ticker, uint price);\n\n mapping(string => PriceUpdate) public latestPriceUpdate;\n address public controller;\n\n function register() external {\n require(controller == address(0), \"Already registered\");\n controller = msg.sender;\n }\n\n function updatePrice(string memory ticker, uint price) external {\n require(msg.sender == controller, \"Only controller\");\n latestPriceUpdate[ticker] = PriceUpdate(price, block.number);\n emit PriceUpdated(ticker, price);\n }\n\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/rigil/BinanceOracle.json b/deployments/rigil/BinanceOracle.json new file mode 100644 index 0000000..0eb806e --- /dev/null +++ b/deployments/rigil/BinanceOracle.json @@ -0,0 +1,444 @@ +{ + "address": "0x5BC1D5aDb1d2df84f2F92C61242Db34fa0194bc2", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "PeekerReverted", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "message", + "type": "string" + } + ], + "name": "SuaveError", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "message", + "type": "string" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "SuaveErrorWithData", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "PriceSubmission", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "DECIMALS", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_BUNDLE_ENDPOINT", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_CHAINID", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOERLI_CHAINID_STR", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "INFURA_GOERLI_RPC", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "S_NAMESPACE", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "URL_PARTIAL", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "confidentialConstructor", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Suave.DataId", + "name": "_pkBidId", + "type": "bytes16" + }, + { + "internalType": "address", + "name": "pkAddress", + "type": "address" + } + ], + "name": "confidentialConstructorCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "controller", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pkBidId", + "outputs": [ + { + "internalType": "Suave.DataId", + "name": "", + "type": "bytes16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPrice", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "settlementBlockNum", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "privateSubmission", + "type": "bool" + } + ], + "name": "queryAndSubmit", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "queryAndSubmitCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "ticker", + "type": "string" + } + ], + "name": "queryLatestPrice", + "outputs": [ + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_settlementContract", + "type": "address" + } + ], + "name": "registerCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_settlementContract", + "type": "address" + } + ], + "name": "registerSettlementContract", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "txSigned", + "type": "bytes" + } + ], + "name": "sendRawTx", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "settlementContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x34b5e032d0b7cfb88d10b442b2264eaad12b82cb147b198755ef792cfcf7e707", + "receipt": { + "to": null, + "from": "0x16f2Aa8dF055b6e672b93Ded41FecCCabAB565B0", + "contractAddress": "0x5BC1D5aDb1d2df84f2F92C61242Db34fa0194bc2", + "transactionIndex": 0, + "gasUsed": "4941539", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x6df6148fbcf41c55994f923eda5bda71e282bef0f2732566e973b9f552bad3bb", + "transactionHash": "0x34b5e032d0b7cfb88d10b442b2264eaad12b82cb147b198755ef792cfcf7e707", + "logs": [], + "blockNumber": 2331912, + "cumulativeGasUsed": "4941539", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "c30c35cbf6d4ade5bd1ec6169afebb51", + "metadata": "{\"compiler\":{\"version\":\"0.8.13+commit.abaa5c0e\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"PeekerReverted\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"SuaveError\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"SuaveErrorWithData\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"PriceSubmission\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"DECIMALS\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOERLI_BUNDLE_ENDPOINT\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOERLI_CHAINID\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"GOERLI_CHAINID_STR\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INFURA_GOERLI_RPC\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"S_NAMESPACE\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"URL_PARTIAL\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"confidentialConstructor\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"Suave.DataId\",\"name\":\"_pkBidId\",\"type\":\"bytes16\"},{\"internalType\":\"address\",\"name\":\"pkAddress\",\"type\":\"address\"}],\"name\":\"confidentialConstructorCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pkBidId\",\"outputs\":[{\"internalType\":\"Suave.DataId\",\"name\":\"\",\"type\":\"bytes16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasPrice\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"settlementBlockNum\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"privateSubmission\",\"type\":\"bool\"}],\"name\":\"queryAndSubmit\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"name\":\"queryAndSubmitCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"ticker\",\"type\":\"string\"}],\"name\":\"queryLatestPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"price\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_settlementContract\",\"type\":\"address\"}],\"name\":\"registerCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_settlementContract\",\"type\":\"address\"}],\"name\":\"registerSettlementContract\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"txSigned\",\"type\":\"bytes\"}],\"name\":\"sendRawTx\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"settlementContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/oracle/BinanceOracle.sol\":\"BinanceOracle\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"contracts/blockad/lib/SuaveContract.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Author: Miha Lotric (halo3mic)\\n\\npragma solidity ^0.8.8;\\n\\nimport { Suave } from \\\"../../standard_peekers/bids.sol\\\";\\n\\n\\nabstract contract SuaveContract {\\n\\terror SuaveError(string message);\\n\\terror SuaveErrorWithData(string message, bytes data);\\n\\n\\tmodifier onlyConfidential() {\\n\\t\\tcrequire(Suave.isConfidential(), \\\"Not confidential\\\");\\n\\t\\t_;\\n\\t}\\n\\n\\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\\n\\t\\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\\n\\t\\tcrequire(!doRevert || success, string(d));\\n\\t\\tif (success) {\\n\\t\\t\\treturn (true, abi.decode(d, (uint64)));\\n\\t\\t}\\n\\t}\\n\\n\\tfunction crequire(bool condition, string memory message) internal pure {\\n\\t\\tif (!condition) {\\n\\t\\t\\trevert SuaveError(message);\\n\\t\\t}\\n\\t}\\n}\\n\",\"keccak256\":\"0x64eb01469afe18f29050571acd52ee35faca1da2c00a87e01d5ea0fdbcdf4bec\",\"license\":\"MIT\"},\"contracts/libraries/Bundle.sol\":{\"content\":\"// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\\n\\n\\n// SPDX-License-Identifier: Unlicense\\npragma solidity ^0.8.13;\\n\\nimport \\\"./Suave.sol\\\";\\nimport \\\"solady/src/utils/LibString.sol\\\";\\n\\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\\nlibrary Bundle {\\n struct BundleObj {\\n uint64 blockNumber;\\n uint64 minTimestamp;\\n uint64 maxTimestamp;\\n bytes[] txns;\\n }\\n\\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\\n Suave.HttpRequest memory request = encodeBundle(bundle);\\n request.url = url;\\n return Suave.doHTTPRequest(request);\\n }\\n\\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\\n require(args.txns.length > 0, \\\"Bundle: no txns\\\");\\n\\n bytes memory params =\\n abi.encodePacked('{\\\"blockNumber\\\": \\\"', LibString.toHexString(args.blockNumber), '\\\", \\\"txs\\\": [');\\n for (uint256 i = 0; i < args.txns.length; i++) {\\n params = abi.encodePacked(params, '\\\"', LibString.toHexString(args.txns[i]), '\\\"');\\n if (i < args.txns.length - 1) {\\n params = abi.encodePacked(params, \\\",\\\");\\n } else {\\n params = abi.encodePacked(params, \\\"]\\\");\\n }\\n }\\n if (args.minTimestamp > 0) {\\n params = abi.encodePacked(params, ', \\\"minTimestamp\\\": ', LibString.toString(args.minTimestamp));\\n }\\n if (args.maxTimestamp > 0) {\\n params = abi.encodePacked(params, ', \\\"maxTimestamp\\\": ', LibString.toString(args.maxTimestamp));\\n }\\n params = abi.encodePacked(params, ', \\\"maxTimestamp\\\": ', LibString.toString(args.maxTimestamp));\\n params = abi.encodePacked(params, \\\"}\\\");\\n\\n bytes memory body =\\n abi.encodePacked('{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"eth_sendBundle\\\",\\\"params\\\":[', params, '],\\\"id\\\":1}');\\n\\n Suave.HttpRequest memory request;\\n request.method = \\\"POST\\\";\\n request.body = body;\\n request.headers = new string[](1);\\n request.headers[0] = \\\"Content-Type: application/json\\\";\\n request.withFlashbotsSignature = true;\\n\\n return request;\\n }\\n}\",\"keccak256\":\"0xf5cf91af6fe20a45a901fa5187886f7ebfaf30dc6f7f83471fa697ed93acc684\",\"license\":\"Unlicense\"},\"contracts/libraries/RLPWriter.sol\":{\"content\":\"// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\\n\\n// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.0;\\n\\n/**\\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\\n * @title RLPWriter\\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\\n * modifications to improve legibility.\\n */\\nlibrary RLPWriter {\\n /**\\n * @notice RLP encodes a byte string.\\n *\\n * @param _in The byte string to encode.\\n *\\n * @return The RLP encoded string in bytes.\\n */\\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\\n bytes memory encoded;\\n\\n if (_in.length == 1 && uint8(_in[0]) < 128) {\\n encoded = _in;\\n } else {\\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\\n }\\n\\n return encoded;\\n }\\n\\n /**\\n * @notice RLP encodes a list of RLP encoded byte byte strings.\\n *\\n * @param _in The list of RLP encoded byte strings.\\n *\\n * @return The RLP encoded list of items in bytes.\\n */\\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\\n bytes memory list = _flatten(_in);\\n return abi.encodePacked(_writeLength(list.length, 192), list);\\n }\\n\\n /**\\n * @notice RLP encodes a string.\\n *\\n * @param _in The string to encode.\\n *\\n * @return The RLP encoded string in bytes.\\n */\\n function writeString(string memory _in) internal pure returns (bytes memory) {\\n return writeBytes(bytes(_in));\\n }\\n\\n /**\\n * @notice RLP encodes an address.\\n *\\n * @param _in The address to encode.\\n *\\n * @return The RLP encoded address in bytes.\\n */\\n function writeAddress(address _in) internal pure returns (bytes memory) {\\n return writeBytes(abi.encodePacked(_in));\\n }\\n\\n /**\\n * @notice RLP encodes a uint.\\n *\\n * @param _in The uint256 to encode.\\n *\\n * @return The RLP encoded uint256 in bytes.\\n */\\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\\n return writeBytes(_toBinary(_in));\\n }\\n\\n /**\\n * @notice RLP encodes a bool.\\n *\\n * @param _in The bool to encode.\\n *\\n * @return The RLP encoded bool in bytes.\\n */\\n function writeBool(bool _in) internal pure returns (bytes memory) {\\n bytes memory encoded = new bytes(1);\\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\\n return encoded;\\n }\\n\\n /**\\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\\n *\\n * @param _len The length of the string or the payload.\\n * @param _offset 128 if item is string, 192 if item is list.\\n *\\n * @return RLP encoded bytes.\\n */\\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\\n bytes memory encoded;\\n\\n if (_len < 56) {\\n encoded = new bytes(1);\\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\\n } else {\\n uint256 lenLen;\\n uint256 i = 1;\\n while (_len / i != 0) {\\n lenLen++;\\n i *= 256;\\n }\\n\\n encoded = new bytes(lenLen + 1);\\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\\n for (i = 1; i <= lenLen; i++) {\\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\\n }\\n }\\n\\n return encoded;\\n }\\n\\n /**\\n * @notice Encode integer in big endian binary form with no leading zeroes.\\n *\\n * @param _x The integer to encode.\\n *\\n * @return RLP encoded bytes.\\n */\\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\\n bytes memory b = abi.encodePacked(_x);\\n\\n uint256 i = 0;\\n for (; i < 32; i++) {\\n if (b[i] != 0) {\\n break;\\n }\\n }\\n\\n bytes memory res = new bytes(32 - i);\\n for (uint256 j = 0; j < res.length; j++) {\\n res[j] = b[i++];\\n }\\n\\n return res;\\n }\\n\\n /**\\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\\n * @notice Copies a piece of memory to another location.\\n *\\n * @param _dest Destination location.\\n * @param _src Source location.\\n * @param _len Length of memory to copy.\\n */\\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\\n uint256 dest = _dest;\\n uint256 src = _src;\\n uint256 len = _len;\\n\\n for (; len >= 32; len -= 32) {\\n assembly {\\n mstore(dest, mload(src))\\n }\\n dest += 32;\\n src += 32;\\n }\\n\\n uint256 mask;\\n unchecked {\\n mask = 256 ** (32 - len) - 1;\\n }\\n assembly {\\n let srcpart := and(mload(src), not(mask))\\n let destpart := and(mload(dest), mask)\\n mstore(dest, or(destpart, srcpart))\\n }\\n }\\n\\n /**\\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\\n * @notice Flattens a list of byte strings into one byte string.\\n *\\n * @param _list List of byte strings to flatten.\\n *\\n * @return The flattened byte string.\\n */\\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\\n if (_list.length == 0) {\\n return new bytes(0);\\n }\\n\\n uint256 len;\\n uint256 i = 0;\\n for (; i < _list.length; i++) {\\n len += _list[i].length;\\n }\\n\\n bytes memory flattened = new bytes(len);\\n uint256 flattenedPtr;\\n assembly {\\n flattenedPtr := add(flattened, 0x20)\\n }\\n\\n for (i = 0; i < _list.length; i++) {\\n bytes memory item = _list[i];\\n\\n uint256 listPtr;\\n assembly {\\n listPtr := add(item, 0x20)\\n }\\n\\n _memcpy(flattenedPtr, listPtr, item.length);\\n flattenedPtr += _list[i].length;\\n }\\n\\n return flattened;\\n }\\n}\",\"keccak256\":\"0x56651ebc297bf3681217d96f035f3f1fdd3027ae64f55087095182c90307f703\",\"license\":\"MIT\"},\"contracts/libraries/Suave.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.8;\\n\\nlibrary Suave {\\n error PeekerReverted(address, bytes);\\n\\n enum CryptoSignature {\\n SECP256,\\n BLS\\n }\\n\\n type DataId is bytes16;\\n\\n struct BuildBlockArgs {\\n uint64 slot;\\n bytes proposerPubkey;\\n bytes32 parent;\\n uint64 timestamp;\\n address feeRecipient;\\n uint64 gasLimit;\\n bytes32 random;\\n Withdrawal[] withdrawals;\\n bytes extra;\\n bytes32 beaconRoot;\\n bool fillPending;\\n }\\n\\n struct DataRecord {\\n DataId id;\\n DataId salt;\\n uint64 decryptionCondition;\\n address[] allowedPeekers;\\n address[] allowedStores;\\n string version;\\n }\\n\\n struct HttpRequest {\\n string url;\\n string method;\\n string[] headers;\\n bytes body;\\n bool withFlashbotsSignature;\\n }\\n\\n struct SimulateTransactionResult {\\n uint64 egp;\\n SimulatedLog[] logs;\\n bool success;\\n string error;\\n }\\n\\n struct SimulatedLog {\\n bytes data;\\n address addr;\\n bytes32[] topics;\\n }\\n\\n struct Withdrawal {\\n uint64 index;\\n uint64 validator;\\n address Address;\\n uint64 amount;\\n }\\n\\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\\n\\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\\n\\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\\n\\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\\n\\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\\n\\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\\n\\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\\n\\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\\n\\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\\n\\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\\n\\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\\n\\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\\n\\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\\n\\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\\n\\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\\n\\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\\n\\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\\n\\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\\n\\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\\n\\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\\n\\n // Returns whether execution is off- or on-chain\\n function isConfidential() internal view returns (bool b) {\\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\\\"\\\");\\n if (!success) {\\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\\n }\\n assembly {\\n // Load the length of data (first 32 bytes)\\n let len := mload(isConfidentialBytes)\\n // Load the data after 32 bytes, so add 0x20\\n b := mload(add(isConfidentialBytes, 0x20))\\n }\\n }\\n\\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\\n internal\\n view\\n returns (bytes memory, bytes memory)\\n {\\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\\n if (!success) {\\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\\n }\\n\\n return abi.decode(data, (bytes, bytes));\\n }\\n\\n function confidentialInputs() internal view returns (bytes memory) {\\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\\n if (!success) {\\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\\n }\\n\\n return data;\\n }\\n\\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\\n if (!success) {\\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\\n }\\n\\n return data;\\n }\\n\\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\\n if (!success) {\\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\\n }\\n }\\n\\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\\n if (!success) {\\n revert PeekerReverted(DO_HTTPREQUEST, data);\\n }\\n\\n return abi.decode(data, (bytes));\\n }\\n\\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\\n if (!success) {\\n revert PeekerReverted(ETHstaticcall, data);\\n }\\n\\n return abi.decode(data, (bytes));\\n }\\n\\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\\n require(isConfidential());\\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\\n if (!success) {\\n revert PeekerReverted(EXTRACT_HINT, data);\\n }\\n\\n return data;\\n }\\n\\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\\n if (!success) {\\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\\n }\\n\\n return abi.decode(data, (DataRecord[]));\\n }\\n\\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\\n require(isConfidential());\\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\\n if (!success) {\\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\\n }\\n\\n return data;\\n }\\n\\n function newBuilder() internal view returns (string memory) {\\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\\n if (!success) {\\n revert PeekerReverted(NEW_BUILDER, data);\\n }\\n\\n return abi.decode(data, (string));\\n }\\n\\n function newDataRecord(\\n uint64 decryptionCondition,\\n address[] memory allowedPeekers,\\n address[] memory allowedStores,\\n string memory dataType\\n ) internal view returns (DataRecord memory) {\\n (bool success, bytes memory data) =\\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\\n if (!success) {\\n revert PeekerReverted(NEW_DATA_RECORD, data);\\n }\\n\\n return abi.decode(data, (DataRecord));\\n }\\n\\n function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) {\\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto));\\n if (!success) {\\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\\n }\\n\\n return abi.decode(data, (string));\\n }\\n\\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\\n internal\\n view\\n returns (bytes memory)\\n {\\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\\n if (!success) {\\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\\n }\\n\\n return abi.decode(data, (bytes));\\n }\\n\\n function signMessage(bytes memory digest, CryptoSignature crypto, string memory signingKey)\\n internal\\n view\\n returns (bytes memory)\\n {\\n require(isConfidential());\\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, crypto, signingKey));\\n if (!success) {\\n revert PeekerReverted(SIGN_MESSAGE, data);\\n }\\n\\n return abi.decode(data, (bytes));\\n }\\n\\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\\n if (!success) {\\n revert PeekerReverted(SIMULATE_BUNDLE, data);\\n }\\n\\n return abi.decode(data, (uint64));\\n }\\n\\n function simulateTransaction(string memory sessionid, bytes memory txn)\\n internal\\n view\\n returns (SimulateTransactionResult memory)\\n {\\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\\n if (!success) {\\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\\n }\\n\\n return abi.decode(data, (SimulateTransactionResult));\\n }\\n\\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\\n internal\\n view\\n returns (bytes memory)\\n {\\n require(isConfidential());\\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\\n if (!success) {\\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\\n }\\n\\n return data;\\n }\\n\\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\\n require(isConfidential());\\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\\n if (!success) {\\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\\n }\\n\\n return data;\\n }\\n}\\n\",\"keccak256\":\"0xba5616842f1a7157233b135a3d1fb50fec7e00bea8e6acbc2e959271bd273fcd\",\"license\":\"UNLICENSED\"},\"contracts/libraries/Transactions.sol\":{\"content\":\"// SPDX-License-Identifier: Unlicense\\npragma solidity ^0.8.13;\\n\\nimport \\\"./RLPWriter.sol\\\";\\nimport \\\"./Suave.sol\\\";\\nimport \\\"solidity-rlp/contracts/RLPReader.sol\\\";\\n\\nlibrary Transactions {\\n using RLPReader for RLPReader.RLPItem;\\n using RLPReader for RLPReader.Iterator;\\n using RLPReader for bytes;\\n\\n struct EIP155 {\\n address to;\\n uint256 gas;\\n uint256 gasPrice;\\n uint256 value;\\n uint256 nonce;\\n bytes data;\\n uint256 chainId;\\n bytes32 r;\\n bytes32 s;\\n uint64 v;\\n }\\n\\n struct EIP155Request {\\n address to;\\n uint256 gas;\\n uint256 gasPrice;\\n uint256 value;\\n uint256 nonce;\\n bytes data;\\n uint256 chainId;\\n }\\n\\n struct EIP1559 {\\n address to;\\n uint64 gas;\\n uint64 maxFeePerGas;\\n uint64 maxPriorityFeePerGas;\\n uint64 value;\\n uint64 nonce;\\n bytes data;\\n uint64 chainId;\\n bytes accessList;\\n bytes32 r;\\n bytes32 s;\\n uint64 v;\\n }\\n\\n struct EIP1559Request {\\n address to;\\n uint64 gas;\\n uint64 maxFeePerGas;\\n uint64 maxPriorityFeePerGas;\\n uint64 value;\\n uint64 nonce;\\n bytes data;\\n uint64 chainId;\\n bytes accessList;\\n }\\n\\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\\n bytes[] memory items = new bytes[](9);\\n\\n items[0] = RLPWriter.writeUint(txStruct.nonce);\\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\\n items[2] = RLPWriter.writeUint(txStruct.gas);\\n\\n if (txStruct.to == address(0)) {\\n items[3] = RLPWriter.writeBytes(bytes(\\\"\\\"));\\n } else {\\n items[3] = RLPWriter.writeAddress(txStruct.to);\\n }\\n items[4] = RLPWriter.writeUint(txStruct.value);\\n items[5] = RLPWriter.writeBytes(txStruct.data);\\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\\n\\n return RLPWriter.writeList(items);\\n }\\n\\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\\n bytes[] memory items = new bytes[](9);\\n\\n items[0] = RLPWriter.writeUint(txStruct.nonce);\\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\\n items[2] = RLPWriter.writeUint(txStruct.gas);\\n\\n if (txStruct.to == address(0)) {\\n items[3] = RLPWriter.writeBytes(bytes(\\\"\\\"));\\n } else {\\n items[3] = RLPWriter.writeAddress(txStruct.to);\\n }\\n items[4] = RLPWriter.writeUint(txStruct.value);\\n items[5] = RLPWriter.writeBytes(txStruct.data);\\n items[6] = RLPWriter.writeUint(txStruct.chainId);\\n items[7] = RLPWriter.writeBytes(\\\"\\\");\\n items[8] = RLPWriter.writeBytes(\\\"\\\");\\n\\n return RLPWriter.writeList(items);\\n }\\n\\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\\n bytes[] memory items = new bytes[](12);\\n\\n items[0] = RLPWriter.writeUint(txStruct.chainId);\\n items[1] = RLPWriter.writeUint(txStruct.nonce);\\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\\n items[4] = RLPWriter.writeUint(txStruct.gas);\\n\\n if (txStruct.to == address(0)) {\\n items[5] = RLPWriter.writeBytes(bytes(\\\"\\\"));\\n } else {\\n items[5] = RLPWriter.writeAddress(txStruct.to);\\n }\\n\\n items[6] = RLPWriter.writeUint(txStruct.value);\\n items[7] = RLPWriter.writeBytes(txStruct.data);\\n\\n if (txStruct.accessList.length == 0) {\\n items[8] = hex\\\"c0\\\"; // Empty list encoding\\n } else {\\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\\n }\\n\\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\\n\\n bytes memory rlpTxn = RLPWriter.writeList(items);\\n\\n bytes memory txn = new bytes(1 + rlpTxn.length);\\n txn[0] = 0x02;\\n\\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\\n txn[i + 1] = rlpTxn[i];\\n }\\n\\n return txn;\\n }\\n\\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\\n bytes[] memory items = new bytes[](9);\\n\\n items[0] = RLPWriter.writeUint(txStruct.chainId);\\n items[1] = RLPWriter.writeUint(txStruct.nonce);\\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\\n items[4] = RLPWriter.writeUint(txStruct.gas);\\n\\n if (txStruct.to == address(0)) {\\n items[5] = RLPWriter.writeBytes(bytes(\\\"\\\"));\\n } else {\\n items[5] = RLPWriter.writeAddress(txStruct.to);\\n }\\n\\n items[6] = RLPWriter.writeUint(txStruct.value);\\n items[7] = RLPWriter.writeBytes(txStruct.data);\\n\\n if (txStruct.accessList.length == 0) {\\n items[8] = hex\\\"c0\\\"; // Empty list encoding\\n } else {\\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\\n }\\n\\n bytes memory rlpTxn = RLPWriter.writeList(items);\\n\\n bytes memory txn = new bytes(1 + rlpTxn.length);\\n txn[0] = 0x02;\\n\\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\\n txn[i + 1] = rlpTxn[i];\\n }\\n\\n return txn;\\n }\\n\\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\\n EIP155 memory txStruct;\\n\\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\\n require(ls.length == 9, \\\"invalid transaction\\\");\\n\\n txStruct.nonce = uint64(ls[0].toUint());\\n txStruct.gasPrice = uint64(ls[1].toUint());\\n txStruct.gas = uint64(ls[2].toUint());\\n\\n if (ls[3].toRlpBytes().length == 1) {\\n txStruct.to = address(0);\\n } else {\\n txStruct.to = ls[3].toAddress();\\n }\\n\\n txStruct.value = uint64(ls[4].toUint());\\n txStruct.data = ls[5].toBytes();\\n txStruct.v = uint64(ls[6].toUint());\\n txStruct.r = bytesToBytes32(ls[7].toBytes());\\n txStruct.s = bytesToBytes32(ls[8].toBytes());\\n\\n return txStruct;\\n }\\n\\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\\n EIP155Request memory txStruct;\\n\\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\\n require(ls.length == 9, \\\"invalid transaction\\\");\\n\\n txStruct.nonce = ls[0].toUint();\\n txStruct.gasPrice = ls[1].toUint();\\n txStruct.gas = ls[2].toUint();\\n\\n if (ls[3].toRlpBytes().length == 1) {\\n txStruct.to = address(0);\\n } else {\\n txStruct.to = ls[3].toAddress();\\n }\\n\\n txStruct.value = ls[4].toUint();\\n txStruct.data = ls[5].toBytes();\\n txStruct.chainId = uint64(ls[6].toUint());\\n\\n return txStruct;\\n }\\n\\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\\n EIP1559 memory txStruct;\\n\\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\\n\\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\\n rlpWithoutPrefix[i] = rlp[i + 1];\\n }\\n\\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\\n require(ls.length == 12, \\\"invalid transaction\\\");\\n\\n txStruct.chainId = uint64(ls[0].toUint());\\n txStruct.nonce = uint64(ls[1].toUint());\\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\\n txStruct.gas = uint64(ls[4].toUint());\\n\\n if (ls[5].toRlpBytes().length == 1) {\\n txStruct.to = address(0);\\n } else {\\n txStruct.to = ls[5].toAddress();\\n }\\n\\n txStruct.value = uint64(ls[6].toUint());\\n txStruct.data = ls[7].toBytes();\\n txStruct.accessList = ls[8].toBytes();\\n txStruct.v = uint64(ls[9].toUint());\\n txStruct.r = bytesToBytes32(ls[10].toBytes());\\n txStruct.s = bytesToBytes32(ls[11].toBytes());\\n\\n return txStruct;\\n }\\n\\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\\n EIP1559Request memory txStruct;\\n\\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\\n\\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\\n rlpWithoutPrefix[i] = rlp[i + 1];\\n }\\n\\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\\n require(ls.length == 8, \\\"invalid transaction\\\");\\n\\n txStruct.chainId = uint64(ls[0].toUint());\\n txStruct.nonce = uint64(ls[1].toUint());\\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\\n txStruct.gas = uint64(ls[4].toUint());\\n\\n if (ls[5].toRlpBytes().length == 1) {\\n txStruct.to = address(0);\\n } else {\\n txStruct.to = ls[5].toAddress();\\n }\\n\\n txStruct.value = uint64(ls[6].toUint());\\n txStruct.data = ls[7].toBytes();\\n\\n return txStruct;\\n }\\n\\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\\n require(inBytes.length == 32, \\\"bytesToBytes32: invalid input length\\\");\\n assembly {\\n out := mload(add(inBytes, 32))\\n }\\n }\\n\\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\\n internal\\n view\\n returns (Transactions.EIP1559 memory response)\\n {\\n bytes memory rlp = Transactions.encodeRLP(request);\\n bytes memory hash = abi.encodePacked(keccak256(rlp));\\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\\n\\n response.to = request.to;\\n response.gas = request.gas;\\n response.maxFeePerGas = request.maxFeePerGas;\\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\\n response.value = request.value;\\n response.nonce = request.nonce;\\n response.data = request.data;\\n response.chainId = request.chainId;\\n response.accessList = request.accessList;\\n response.v = v;\\n response.r = r;\\n response.s = s;\\n\\n return response;\\n }\\n\\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\\n internal\\n view\\n returns (Transactions.EIP155 memory response)\\n {\\n bytes memory rlp = Transactions.encodeRLP(request);\\n bytes memory hash = abi.encodePacked(keccak256(rlp));\\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\\n\\n // TODO: check overflow\\n uint64 chainIdMul = uint64(request.chainId) * 2;\\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\\n\\n uint64 v64 = uint64(v) + 35;\\n v64 += chainIdMul;\\n\\n response.to = request.to;\\n response.gas = request.gas;\\n response.gasPrice = request.gasPrice;\\n response.value = request.value;\\n response.nonce = request.nonce;\\n response.data = request.data;\\n response.chainId = request.chainId;\\n response.v = v64;\\n response.r = r;\\n response.s = s;\\n\\n return response;\\n }\\n\\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\\n assembly {\\n r := mload(add(signature, 0x20))\\n s := mload(add(signature, 0x40))\\n v := byte(0, mload(add(signature, 0x60)))\\n }\\n }\\n}\",\"keccak256\":\"0xf38128cc64664516ee19211e45c79832aff166734a462670d715a05a41b59148\",\"license\":\"Unlicense\"},\"contracts/oracle/BinanceOracle.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// Author: Miha Lotric (halo3mic)\\n\\npragma solidity ^0.8.13;\\n\\nimport { AnyBundleContract, Suave } from \\\"../standard_peekers/bids.sol\\\";\\nimport { SuaveContract } from \\\"../blockad/lib/SuaveContract.sol\\\";\\nimport \\\"../../node_modules/solady/src/utils/JSONParserLib.sol\\\";\\nimport \\\"../libraries/Transactions.sol\\\";\\nimport \\\"../libraries/Bundle.sol\\\";\\nimport \\\"solady/src/utils/LibString.sol\\\";\\n\\n\\ncontract BinanceOracle is SuaveContract {\\n using JSONParserLib for *;\\n\\n uint public constant GOERLI_CHAINID = 5;\\n string public constant GOERLI_CHAINID_STR = \\\"0x5\\\";\\n uint8 public constant DECIMALS = 4;\\n string public constant S_NAMESPACE = \\\"oracle:v0:pksecret\\\";\\n string public constant INFURA_GOERLI_RPC = \\\"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\\\"; // Change when settlement node API is exposed\\n string public constant URL_PARTIAL = \\\"https://data-api.binance.vision/api/v3/ticker/price?symbol=\\\";\\n string public constant GOERLI_BUNDLE_ENDPOINT = \\\"https://relay-goerli.flashbots.net\\\";\\n \\n bool isInitialized;\\n Suave.DataId public pkBidId;\\n address public controller;\\n address public settlementContract;\\n\\n event PriceSubmission(string ticker, uint price);\\n\\n // \\u26d3\\ufe0f EVM Methods\\n\\n function confidentialConstructorCallback(\\n Suave.DataId _pkBidId, \\n address pkAddress\\n ) public {\\n crequire(!isInitialized, \\\"Already initialized\\\");\\n pkBidId = _pkBidId;\\n controller = pkAddress;\\n isInitialized = true;\\n }\\n\\n function registerCallback(address _settlementContract) public {\\n require(_settlementContract == settlementContract || settlementContract == address(0), \\\"Already registered\\\");\\n settlementContract = _settlementContract;\\n }\\n\\n // ! Warning: This method is not restricted and emitted events should not be relied upon\\n function queryAndSubmitCallback(string memory ticker, uint price) public {\\n emit PriceSubmission(ticker, price);\\n }\\n\\n fallback() external payable {\\n // Needed to accept MEVM calls with no callbacks\\n }\\n\\n // \\ud83e\\udd10 MEVM Methods\\n\\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\\n crequire(!isInitialized, \\\"Already initialized\\\");\\n\\n string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);\\n address pkAddress = getAddressForPk(pk);\\n\\t\\tSuave.DataId bidId = storePK(bytes(pk));\\n\\n return abi.encodeWithSelector(\\n this.confidentialConstructorCallback.selector, \\n bidId, \\n pkAddress\\n );\\n }\\n\\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\\n require(settlementContract == address(0), \\\"Already registered\\\");\\n bytes memory signedTx = createRegisterTx(_settlementContract);\\n sendRawTx(signedTx);\\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\\n }\\n\\n function queryAndSubmit(\\n string memory ticker,\\n uint nonce,\\n uint gasPrice,\\n uint64 settlementBlockNum,\\n bool privateSubmission\\n ) external view onlyConfidential returns (bytes memory) {\\n uint price = queryLatestPrice(ticker);\\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum, privateSubmission);\\n return abi.encodeWithSelector(this.queryAndSubmitCallback.selector, ticker, price);\\n }\\n\\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\\n bytes memory response = doBinanceQuery(ticker);\\n JSONParserLib.Item memory parsedRes = string(response).parse();\\n string memory priceStr = string(parsedRes.at('\\\"price\\\"').value());\\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\\n }\\n\\n function submitPriceUpdate(\\n string memory ticker,\\n uint price, \\n uint nonce,\\n uint gasPrice,\\n uint64 settlementBlockNum,\\n bool privateSubmission\\n ) internal view {\\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\\n if (privateSubmission) {\\n sendBundle(signedTx, settlementBlockNum);\\n } else {\\n sendRawTx(signedTx);\\n }\\n }\\n\\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\\n Transactions.EIP155 memory transaction = Transactions.EIP155({\\n nonce: 0,\\n gasPrice: 100 gwei,\\n gas: 100_000,\\n to: _settlementContract,\\n value: 0,\\n data: abi.encodeWithSignature(\\\"register()\\\"),\\n chainId: GOERLI_CHAINID,\\n v: 27,\\n r: hex\\\"1111111111111111111111111111111111111111111111111111111111111111\\\",\\n s: hex\\\"1111111111111111111111111111111111111111111111111111111111111111\\\"\\n });\\n bytes memory txRlp = Transactions.encodeRLP(transaction);\\n string memory pk = retreivePK();\\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\\n }\\n\\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\\n Transactions.EIP155 memory transaction = Transactions.EIP155({\\n nonce: nonce,\\n gasPrice: gasPrice,\\n gas: 100_000,\\n to: settlementContract,\\n value: 0,\\n data: abi.encodeWithSignature(\\\"updatePrice(string,uint256)\\\", ticker, price),\\n chainId: GOERLI_CHAINID,\\n v: 27,\\n r: hex\\\"1111111111111111111111111111111111111111111111111111111111111111\\\",\\n s: hex\\\"1111111111111111111111111111111111111111111111111111111111111111\\\"\\n });\\n bytes memory txRlp = Transactions.encodeRLP(transaction);\\n string memory pk = retreivePK();\\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\\n }\\n\\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\\n bytes memory body =\\n abi.encodePacked('{\\\"jsonrpc\\\":\\\"2.0\\\",\\\"method\\\":\\\"eth_sendRawTransaction\\\",\\\"params\\\":[\\\"', LibString.toHexString(txSigned), '\\\"],\\\"id\\\":1}');\\n Suave.HttpRequest memory request;\\n request.method = \\\"POST\\\";\\n request.body = body;\\n request.headers = new string[](1);\\n request.headers[0] = \\\"Content-Type: application/json\\\";\\n request.withFlashbotsSignature = false;\\n request.url = INFURA_GOERLI_RPC;\\n return doHttpRequest(request);\\n }\\n\\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\\n simulateTx(txSigned);\\n sendTxViaBundle(txSigned, settlementBlockNum);\\n }\\n\\n function simulateTx(bytes memory signedTx) internal view {\\n bytes memory bundle = abi.encodePacked('{\\\"txs\\\": [\\\"', LibString.toHexString(signedTx), '\\\"]}');\\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\\n crequire(successSim, string(abi.encodePacked(\\\"BundleSimulationFailed: \\\", string(data))));\\n }\\n\\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\\n string[] memory headers = new string[](1);\\n headers[0] = \\\"Content-Type: application/json\\\";\\n Suave.HttpRequest memory request = Suave.HttpRequest({\\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\\n method: 'GET',\\n headers: headers,\\n body: new bytes(0),\\n withFlashbotsSignature: false\\n });\\n return doHttpRequest(request);\\n }\\n\\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\\n crequire(success, string(data));\\n return abi.decode(data, (bytes));\\n }\\n\\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\\n bytes[] memory txns = new bytes[](1);\\n txns[0] = txSigned;\\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\\n GOERLI_BUNDLE_ENDPOINT, \\n \\\"eth_sendBundle\\\", \\n bundleReqParams\\n ));\\n crequire(successReq, string(abi.encodePacked(\\\"BundleSubmissionFailed: \\\", string(dataReq))));\\n }\\n\\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\\n bytes memory params =\\n abi.encodePacked('{\\\"blockNumber\\\": \\\"', LibString.toHexString(blockNumber), '\\\", \\\"txs\\\": [');\\n for (uint256 i = 0; i < txns.length; i++) {\\n params = abi.encodePacked(params, '\\\"', LibString.toHexString(txns[i]), '\\\"');\\n if (i < txns.length - 1) {\\n params = abi.encodePacked(params, \\\",\\\");\\n } else {\\n params = abi.encodePacked(params, \\\"]\\\");\\n }\\n }\\n params = abi.encodePacked(params, \\\"}\\\");\\n\\n return params;\\n }\\n\\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\\n\\t\\taddress[] memory peekers = new address[](3);\\n\\t\\tpeekers[0] = address(this);\\n\\t\\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\\n\\t\\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\\n\\t\\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\\n\\t\\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\\n\\t\\treturn secretBid.id;\\n\\t}\\n\\n function retreivePK() internal view returns (string memory) {\\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\\n return string(pkBytes);\\n }\\n\\n}\\n\\n// \\ud83d\\udd27 Utils\\n\\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\\n bytes memory stringBytes = bytes(floatString);\\n uint dotPosition;\\n \\n // Find the position of the dot\\n for (uint i = 0; i < stringBytes.length; i++) {\\n if (stringBytes[i] == 0x2E) {\\n dotPosition = i;\\n break;\\n }\\n }\\n \\n uint integerPart = 0;\\n uint decimalPart = 0;\\n uint tenPower = 1;\\n \\n // Convert integer part\\n for (uint i = dotPosition; i > 0; i--) {\\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\\n tenPower *= 10;\\n }\\n // Reset power of ten\\n tenPower = 1;\\n // Convert decimal part\\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\\n tenPower *= 10;\\n }\\n // Combine integer and decimal parts\\n return integerPart * (10**decimals) + decimalPart;\\n}\\n\\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\\n bytes memory input = bytes(_input);\\n require(input.length > 2, \\\"Input too short\\\");\\n\\n uint newLength = input.length - 2;\\n bytes memory result = new bytes(newLength);\\n\\n assembly {\\n let inputPtr := add(input, 0x21)\\n let resultPtr := add(result, 0x20)\\n let length := mload(input)\\n mstore(resultPtr, mload(inputPtr))\\n mstore(result, newLength)\\n }\\n return string(result);\\n}\\n\\nfunction getAddressForPk(string memory pk) view returns (address) {\\n bytes32 digest = keccak256(abi.encode(\\\"yo\\\"));\\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), Suave.CryptoSignature.SECP256, pk);\\n return recoverSigner(digest, sig);\\n}\\n\\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\\n return ecrecover(_ethSignedMessageHash, v, r, s);\\n}\\n\\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\\n require(sig.length == 65, \\\"invalid signature length\\\");\\n assembly {\\n r := mload(add(sig, 32))\\n s := mload(add(sig, 64))\\n v := byte(0, mload(add(sig, 96)))\\n }\\n if (v < 27) {\\n v += 27;\\n }\\n}\",\"keccak256\":\"0x33a1b78052f4ddc3337198c2bd124d6ffc9a3870ef58ffb75ca5b266d4354b2a\",\"license\":\"MIT\"},\"contracts/standard_peekers/bids.sol\":{\"content\":\"pragma solidity ^0.8.8;\\n\\nimport \\\"../libraries/Suave.sol\\\";\\n\\ncontract AnyBundleContract {\\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\\n\\n function fetchConfidentialBundleData() public returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n bytes memory confidentialInputs = Suave.confidentialInputs();\\n return abi.decode(confidentialInputs, (bytes));\\n }\\n\\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n }\\n}\\n\\ncontract BundleContract is AnyBundleContract {\\n function newBundle(\\n uint64 decryptionCondition,\\n address[] memory dataAllowedPeekers,\\n address[] memory dataAllowedStores\\n ) external payable returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n bytes memory bundleData = this.fetchConfidentialBundleData();\\n\\n uint64 egp = Suave.simulateBundle(bundleData);\\n\\n Suave.DataRecord memory dataRecord =\\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \\\"default:v0:ethBundles\\\");\\n\\n Suave.confidentialStore(dataRecord.id, \\\"default:v0:ethBundles\\\", bundleData);\\n Suave.confidentialStore(dataRecord.id, \\\"default:v0:ethBundleSimResults\\\", abi.encode(egp));\\n\\n return emitAndReturn(dataRecord, bundleData);\\n }\\n\\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\\n }\\n}\\n\\ncontract EthBundleSenderContract is BundleContract {\\n string[] public builderUrls;\\n\\n constructor(string[] memory builderUrls_) {\\n builderUrls = builderUrls_;\\n }\\n\\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\\n internal\\n virtual\\n override\\n returns (bytes memory)\\n {\\n for (uint256 i = 0; i < builderUrls.length; i++) {\\n Suave.submitBundleJsonRPC(builderUrls[i], \\\"eth_sendBundle\\\", bundleData);\\n }\\n\\n return BundleContract.emitAndReturn(dataRecord, bundleData);\\n }\\n}\\n\\ncontract MevShareContract is AnyBundleContract {\\n event HintEvent(Suave.DataId dataId, bytes hint);\\n\\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\\n\\n function newTransaction(\\n uint64 decryptionCondition,\\n address[] memory dataAllowedPeekers,\\n address[] memory dataAllowedStores\\n ) external payable returns (bytes memory) {\\n // 0. check confidential execution\\n require(Suave.isConfidential());\\n\\n // 1. fetch bundle data\\n bytes memory bundleData = this.fetchConfidentialBundleData();\\n\\n // 2. sim bundle\\n uint64 egp = Suave.simulateBundle(bundleData);\\n\\n // 3. extract hint\\n bytes memory hint = Suave.extractHint(bundleData);\\n\\n // // 4. store bundle and sim results\\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \\\"mevshare:v0:unmatchedBundles\\\"\\n );\\n Suave.confidentialStore(dataRecord.id, \\\"mevshare:v0:ethBundles\\\", bundleData);\\n Suave.confidentialStore(dataRecord.id, \\\"mevshare:v0:ethBundleSimResults\\\", abi.encode(egp));\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n emit HintEvent(dataRecord.id, hint);\\n\\n // // 5. return \\\"callback\\\" to emit hint onchain\\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\\n }\\n\\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n emit HintEvent(dataRecord.id, hint);\\n }\\n\\n function newMatch(\\n uint64 decryptionCondition,\\n address[] memory dataAllowedPeekers,\\n address[] memory dataAllowedStores,\\n Suave.DataId sharedataId\\n ) external payable returns (bytes memory) {\\n // WARNING : this function will copy the original mev share bid\\n // into a new key with potentially different permsissions\\n\\n require(Suave.isConfidential());\\n // 1. fetch confidential data\\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\\n\\n // 2. sim match alone for validity\\n uint64 egp = Suave.simulateBundle(matchBundleData);\\n\\n // 3. extract hint\\n bytes memory matchHint = Suave.extractHint(matchBundleData);\\n\\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \\\"mevshare:v0:matchDataRecords\\\"\\n );\\n Suave.confidentialStore(dataRecord.id, \\\"mevshare:v0:ethBundles\\\", matchBundleData);\\n Suave.confidentialStore(dataRecord.id, \\\"mevshare:v0:ethBundleSimResults\\\", abi.encode(0));\\n\\n //4. merge data records\\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\\n dataRecords[0] = sharedataId;\\n dataRecords[1] = dataRecord.id;\\n Suave.confidentialStore(dataRecord.id, \\\"mevshare:v0:mergedDataRecords\\\", abi.encode(dataRecords));\\n\\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\\n }\\n\\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\\n internal\\n virtual\\n returns (bytes memory)\\n {\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n emit MatchEvent(dataRecord.id, matchHint);\\n\\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\\n }\\n}\\n\\ncontract MevShareBundleSenderContract is MevShareContract {\\n string[] public builderUrls;\\n\\n constructor(string[] memory builderUrls_) {\\n builderUrls = builderUrls_;\\n }\\n\\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\\n internal\\n virtual\\n override\\n returns (bytes memory)\\n {\\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\\n for (uint256 i = 0; i < builderUrls.length; i++) {\\n Suave.submitBundleJsonRPC(builderUrls[i], \\\"mev_sendBundle\\\", bundleData);\\n }\\n\\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\\n }\\n}\\n\\n/* Not tested or implemented on the precompile side */\\nstruct EgpRecordPair {\\n uint64 egp; // in wei, beware overflow\\n Suave.DataId dataId;\\n}\\n\\ncontract EthBlockContract is AnyBundleContract {\\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\\n\\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\\n bytes memory l = abi.encodePacked(_l);\\n bytes memory r = abi.encodePacked(_r);\\n for (uint256 i = 0; i < l.length; i++) {\\n if (bytes(l)[i] != r[i]) {\\n return false;\\n }\\n }\\n\\n return true;\\n }\\n\\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n Suave.DataRecord[] memory allShareMatchDataRecords =\\n Suave.fetchDataRecords(blockHeight, \\\"mevshare:v0:matchDataRecords\\\");\\n Suave.DataRecord[] memory allShareUserDataRecords =\\n Suave.fetchDataRecords(blockHeight, \\\"mevshare:v0:unmatchedBundles\\\");\\n\\n if (allShareUserDataRecords.length == 0) {\\n revert Suave.PeekerReverted(address(this), \\\"no data records\\\");\\n }\\n\\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\\n // TODO: sort matches by egp first!\\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\\n // TODO: should be done once at the start and sorted\\n Suave.DataId[] memory mergeddataIds = abi.decode(\\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \\\"mevshare:v0:mergedDataRecords\\\"),\\n (Suave.DataId[])\\n );\\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\\n dataRecordToInsert = allShareMatchDataRecords[j];\\n break;\\n }\\n }\\n allRecords[i] = dataRecordToInsert;\\n }\\n\\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\\n for (uint256 i = 0; i < allRecords.length; i++) {\\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \\\"mevshare:v0:ethBundleSimResults\\\");\\n uint64 egp = abi.decode(simResults, (uint64));\\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\\n }\\n\\n // Bubble sort, cause why not\\n uint256 n = bidsByEGP.length;\\n for (uint256 i = 0; i < n - 1; i++) {\\n for (uint256 j = i + 1; j < n; j++) {\\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\\n EgpRecordPair memory temp = bidsByEGP[i];\\n bidsByEGP[i] = bidsByEGP[j];\\n bidsByEGP[j] = temp;\\n }\\n }\\n }\\n\\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\\n alldataIds[i] = bidsByEGP[i].dataId;\\n }\\n\\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \\\"mevshare:v0\\\");\\n }\\n\\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \\\"default:v0:ethBundles\\\");\\n if (allRecords.length == 0) {\\n revert Suave.PeekerReverted(address(this), \\\"no data records\\\");\\n }\\n\\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\\n for (uint256 i = 0; i < allRecords.length; i++) {\\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \\\"default:v0:ethBundleSimResults\\\");\\n uint64 egp = abi.decode(simResults, (uint64));\\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\\n }\\n\\n // Bubble sort, cause why not\\n uint256 n = bidsByEGP.length;\\n for (uint256 i = 0; i < n - 1; i++) {\\n for (uint256 j = i + 1; j < n; j++) {\\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\\n EgpRecordPair memory temp = bidsByEGP[i];\\n bidsByEGP[i] = bidsByEGP[j];\\n bidsByEGP[j] = temp;\\n }\\n }\\n }\\n\\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\\n alldataIds[i] = bidsByEGP[i].dataId;\\n }\\n\\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \\\"\\\");\\n }\\n\\n function buildAndEmit(\\n Suave.BuildBlockArgs memory blockArgs,\\n uint64 blockHeight,\\n Suave.DataId[] memory records,\\n string memory namespace\\n ) public virtual returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\\n this.doBuild(blockArgs, blockHeight, records, namespace);\\n\\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\\n }\\n\\n function doBuild(\\n Suave.BuildBlockArgs memory blockArgs,\\n uint64 blockHeight,\\n Suave.DataId[] memory records,\\n string memory namespace\\n ) public view returns (Suave.DataRecord memory, bytes memory) {\\n address[] memory allowedPeekers = new address[](2);\\n allowedPeekers[0] = address(this);\\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\\n\\n Suave.DataRecord memory blockBid =\\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \\\"default:v0:mergedDataRecords\\\");\\n Suave.confidentialStore(blockBid.id, \\\"default:v0:mergedDataRecords\\\", abi.encode(records));\\n\\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\\n Suave.confidentialStore(blockBid.id, \\\"default:v0:builderPayload\\\", payload); // only through this.unlock\\n\\n return (blockBid, builderBid);\\n }\\n\\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\\n public\\n returns (Suave.DataRecord memory, bytes memory)\\n {\\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\\n return (dataRecord, builderBid);\\n }\\n\\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n // TODO: verify the header is correct\\n // TODO: incorporate protocol name\\n bytes memory payload = Suave.confidentialRetrieve(dataId, \\\"default:v0:builderPayload\\\");\\n return payload;\\n }\\n}\\n\\ncontract EthBlockBidSenderContract is EthBlockContract {\\n string boostRelayUrl;\\n\\n constructor(string memory boostRelayUrl_) {\\n boostRelayUrl = boostRelayUrl_;\\n }\\n\\n function buildAndEmit(\\n Suave.BuildBlockArgs memory blockArgs,\\n uint64 blockHeight,\\n Suave.DataId[] memory dataRecords,\\n string memory namespace\\n ) public virtual override returns (bytes memory) {\\n require(Suave.isConfidential());\\n\\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\\n\\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\\n }\\n}\\n\",\"keccak256\":\"0x69d1971b3f0841d3cc7c28122a240b06f1d28d71510bce6a7f915ee392f47918\"},\"node_modules/solady/src/utils/JSONParserLib.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/// @notice Library for parsing JSONs.\\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\\nlibrary JSONParserLib {\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* CUSTOM ERRORS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev The input is invalid.\\n error ParsingFailed();\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* CONSTANTS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n // There are 6 types of variables in JSON (excluding undefined).\\n\\n /// @dev For denoting that an item has not been initialized.\\n /// A item returned from `parse` will never be of an undefined type.\\n /// Parsing a invalid JSON string will simply revert.\\n uint8 internal constant TYPE_UNDEFINED = 0;\\n\\n /// @dev Type representing an array (e.g. `[1,2,3]`).\\n uint8 internal constant TYPE_ARRAY = 1;\\n\\n /// @dev Type representing an object (e.g. `{\\\"a\\\":\\\"A\\\",\\\"b\\\":\\\"B\\\"}`).\\n uint8 internal constant TYPE_OBJECT = 2;\\n\\n /// @dev Type representing a number (e.g. `-1.23e+21`).\\n uint8 internal constant TYPE_NUMBER = 3;\\n\\n /// @dev Type representing a string (e.g. `\\\"hello\\\"`).\\n uint8 internal constant TYPE_STRING = 4;\\n\\n /// @dev Type representing a boolean (i.e. `true` or `false`).\\n uint8 internal constant TYPE_BOOLEAN = 5;\\n\\n /// @dev Type representing null (i.e. `null`).\\n uint8 internal constant TYPE_NULL = 6;\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* STRUCTS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev A pointer to a parsed JSON node.\\n struct Item {\\n // Do NOT modify the `_data` directly.\\n uint256 _data;\\n }\\n\\n // Private constants for packing `_data`.\\n\\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\\n uint256 private constant _BITMASK_TYPE = 7;\\n uint256 private constant _KEY_INITED = 1 << 3;\\n uint256 private constant _VALUE_INITED = 1 << 4;\\n uint256 private constant _CHILDREN_INITED = 1 << 5;\\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* JSON PARSING OPERATION */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Parses the JSON string `s`, and returns the root.\\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\\n /// in the same order which they appear in the JSON string.\\n ///\\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\\n /// The parsed tree WILL contain offsets to `s`.\\n /// Do NOT pass in a string that WILL be modified later on.\\n function parse(string memory s) internal pure returns (Item memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x40, result) // We will use our own allocation instead.\\n }\\n bytes32 r = _query(_toInput(s), 255);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := r\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* JSON ITEM OPERATIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n // Note:\\n // - An item is a node in the JSON tree.\\n // - The value of a string item WILL be double-quoted, JSON encoded.\\n // - We make a distinction between `index` and `key`.\\n // - Items in arrays are located by `index` (uint256).\\n // - Items in objects are located by `key` (string).\\n // - Keys are always strings, double-quoted, JSON encoded.\\n //\\n // These design choices are made to balance between efficiency and ease-of-use.\\n\\n /// @dev Returns the string value of the item.\\n /// This is its exact string representation in the original JSON string.\\n /// The returned string WILL have leading and trailing whitespace trimmed.\\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\\n ///\\n /// Note: This function lazily instantiates and caches the returned string.\\n /// Do NOT modify the returned string.\\n function value(Item memory item) internal pure returns (string memory result) {\\n bytes32 r = _query(_toInput(item), 0);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := r\\n }\\n }\\n\\n /// @dev Returns the index of the item in the array.\\n /// It the item's parent is not an array, returns 0.\\n function index(Item memory item) internal pure returns (uint256 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n if and(mload(item), _PARENT_IS_ARRAY) {\\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\\n }\\n }\\n }\\n\\n /// @dev Returns the key of the item in the object.\\n /// It the item's parent is not an object, returns an empty string.\\n /// The returned string WILL be double-quoted, JSON encoded.\\n ///\\n /// Note: This function lazily instantiates and caches the returned string.\\n /// Do NOT modify the returned string.\\n function key(Item memory item) internal pure returns (string memory result) {\\n if (item._data & _PARENT_IS_OBJECT != 0) {\\n bytes32 r = _query(_toInput(item), 1);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := r\\n }\\n }\\n }\\n\\n /// @dev Returns the key of the item in the object.\\n /// It the item is neither an array nor object, returns an empty array.\\n ///\\n /// Note: This function lazily instantiates and caches the returned array.\\n /// Do NOT modify the returned array.\\n function children(Item memory item) internal pure returns (Item[] memory result) {\\n bytes32 r = _query(_toInput(item), 3);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := r\\n }\\n }\\n\\n /// @dev Returns the number of children.\\n /// It the item is neither an array nor object, returns zero.\\n function size(Item memory item) internal pure returns (uint256 result) {\\n bytes32 r = _query(_toInput(item), 3);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := mload(r)\\n }\\n }\\n\\n /// @dev Returns the item at index `i` for (array).\\n /// If `item` is not an array, the result's type WILL be undefined.\\n /// If there is no item with the index, the result's type WILL be undefined.\\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\\n }\\n bytes32 r = _query(_toInput(item), 3);\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := mload(add(add(r, 0x20), shl(5, i)))\\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\\n result := 0x60 // Reset to the zero pointer.\\n }\\n }\\n }\\n\\n /// @dev Returns the item at key `k` for (object).\\n /// If `item` is not an object, the result's type WILL be undefined.\\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\\n /// - Correct : `item.at('\\\"k\\\"')`.\\n /// - Wrong : `item.at(\\\"k\\\")`.\\n /// For duplicated keys, the last item with the key WILL be returned.\\n /// If there is no item with the key, the result's type WILL be undefined.\\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\\n result := 0x60 // Initialize to the zero pointer.\\n }\\n if (isObject(item)) {\\n bytes32 kHash = keccak256(bytes(k));\\n Item[] memory r = children(item);\\n // We'll just do a linear search. The alternatives are very bloated.\\n for (uint256 i = r.length << 5; i != 0;) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n item := mload(add(r, i))\\n i := sub(i, 0x20)\\n }\\n if (keccak256(bytes(key(item))) != kHash) continue;\\n result = item;\\n break;\\n }\\n }\\n }\\n\\n /// @dev Returns the item's type.\\n function getType(Item memory item) internal pure returns (uint8 result) {\\n result = uint8(item._data & _BITMASK_TYPE);\\n }\\n\\n /// Note: All types are mutually exclusive.\\n\\n /// @dev Returns whether the item is of type undefined.\\n function isUndefined(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\\n }\\n\\n /// @dev Returns whether the item is of type array.\\n function isArray(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\\n }\\n\\n /// @dev Returns whether the item is of type object.\\n function isObject(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\\n }\\n\\n /// @dev Returns whether the item is of type number.\\n function isNumber(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\\n }\\n\\n /// @dev Returns whether the item is of type string.\\n function isString(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\\n }\\n\\n /// @dev Returns whether the item is of type boolean.\\n function isBoolean(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\\n }\\n\\n /// @dev Returns whether the item is of type null.\\n function isNull(Item memory item) internal pure returns (bool result) {\\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\\n }\\n\\n /// @dev Returns the item's parent.\\n /// If the item does not have a parent, the result's type will be undefined.\\n function parent(Item memory item) internal pure returns (Item memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n mstore(0x40, result) // Free the default allocation. We've already allocated.\\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* UTILITY FUNCTIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\\n /// or if the parsed number is too big for a uint256.\\n function parseUint(string memory s) internal pure returns (uint256 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let n := mload(s)\\n let preMulOverflowThres := div(not(0), 10)\\n for { let i := 0 } 1 {} {\\n i := add(i, 1)\\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\\n let mulOverflowed := gt(result, preMulOverflowThres)\\n let product := mul(10, result)\\n result := add(product, digit)\\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\\n if iszero(lt(i, n)) { break }\\n }\\n if iszero(n) {\\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\\n revert(0x1c, 0x04)\\n }\\n }\\n }\\n\\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\\n function parseInt(string memory s) internal pure returns (int256 result) {\\n uint256 n = bytes(s).length;\\n uint256 sign;\\n uint256 isNegative;\\n /// @solidity memory-safe-assembly\\n assembly {\\n if n {\\n let c := and(mload(add(s, 1)), 0xff)\\n isNegative := eq(c, 45)\\n if or(eq(c, 43), isNegative) {\\n sign := c\\n s := add(s, 1)\\n mstore(s, sub(n, 1))\\n }\\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\\n }\\n }\\n uint256 x = parseUint(s);\\n /// @solidity memory-safe-assembly\\n assembly {\\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\\n revert(0x1c, 0x04)\\n }\\n if sign {\\n mstore(s, sign)\\n s := sub(s, 1)\\n mstore(s, n)\\n }\\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\\n }\\n }\\n\\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let n := mload(s)\\n // Skip two if starts with '0x' or '0X'.\\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\\n for {} 1 {} {\\n i := add(i, 1)\\n let c :=\\n byte(\\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\\n 0x3010a071000000b0104040208000c05090d060e0f\\n )\\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\\n result := add(shl(4, result), sub(c, 1))\\n if iszero(lt(i, n)) { break }\\n }\\n if iszero(n) {\\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\\n revert(0x1c, 0x04)\\n }\\n }\\n }\\n\\n /// @dev Decodes a JSON encoded string.\\n /// The string MUST be double-quoted, JSON encoded.\\n /// Reverts if the string is invalid.\\n /// As you can see, it's pretty complex for a deceptively simple looking task.\\n function decodeString(string memory s) internal pure returns (string memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n function fail() {\\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\\n revert(0x1c, 0x04)\\n }\\n\\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\\n _pOut := add(pIn_, 4)\\n let b_ := iszero(gt(_pOut, end_))\\n let t_ := mload(pIn_) // Load the whole word.\\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\\n let c_ := sub(byte(i_, t_), 48)\\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\\n _unicode := add(shl(4, _unicode), c_)\\n }\\n }\\n\\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\\n let t_ := mload(_pOut) // Load the whole word.\\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\\\\\u'.\\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\\n }\\n }\\n\\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\\n if iszero(gt(c_, 0x7f)) {\\n mstore8(pIn_, c_)\\n _pOut := add(pIn_, 1)\\n leave\\n }\\n mstore8(0x1f, c_)\\n mstore8(0x1e, shr(6, c_))\\n if iszero(gt(c_, 0x7ff)) {\\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\\n _pOut := add(pIn_, 2)\\n leave\\n }\\n mstore8(0x1d, shr(12, c_))\\n if iszero(gt(c_, 0xffff)) {\\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\\n _pOut := add(pIn_, 3)\\n leave\\n }\\n mstore8(0x1c, shr(18, c_))\\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\\n }\\n\\n function chr(p_) -> _c {\\n _c := byte(0, mload(p_))\\n }\\n\\n let n := mload(s)\\n let end := add(add(s, n), 0x1f)\\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\\n fail() // Fail if not double-quoted.\\n }\\n let out := add(mload(0x40), 0x20)\\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\\n let c := chr(curr)\\n curr := add(curr, 1)\\n // Not '\\\\\\\\'.\\n if iszero(eq(c, 92)) {\\n // Not '\\\"'.\\n if iszero(eq(c, 34)) {\\n mstore8(out, c)\\n out := add(out, 1)\\n continue\\n }\\n curr := end\\n }\\n if iszero(eq(curr, end)) {\\n let escape := chr(curr)\\n curr := add(curr, 1)\\n // '\\\"', '/', '\\\\\\\\'.\\n if and(shr(escape, 0x100000000000800400000000), 1) {\\n mstore8(out, escape)\\n out := add(out, 1)\\n continue\\n }\\n // 'u'.\\n if eq(escape, 117) {\\n escape, curr := decodeUnicodeCodePoint(curr, end)\\n out := appendCodePointAsUTF8(out, escape)\\n continue\\n }\\n // `{'b':'\\\\b', 'f':'\\\\f', 'n':'\\\\n', 'r':'\\\\r', 't':'\\\\t'}`.\\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\\n if escape {\\n mstore8(out, escape)\\n out := add(out, 1)\\n continue\\n }\\n }\\n fail()\\n break\\n }\\n mstore(out, 0) // Zeroize the last slot.\\n result := mload(0x40)\\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* PRIVATE HELPERS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Performs a query on the input with the given mode.\\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n function fail() {\\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\\n revert(0x1c, 0x04)\\n }\\n\\n function chr(p_) -> _c {\\n _c := byte(0, mload(p_))\\n }\\n\\n function skipWhitespace(pIn_, end_) -> _pOut {\\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\\\n\\\\r\\\\t'.\\n }\\n }\\n\\n function setP(packed_, bitpos_, p_) -> _packed {\\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\\n }\\n\\n function getP(packed_, bitpos_) -> _p {\\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\\n }\\n\\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\\n _item := mload(0x40)\\n // forgefmt: disable-next-item\\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\\n mstore(_item, or(packed_, type_))\\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\\n }\\n\\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\\n _pOut := skipWhitespace(pIn_, end_)\\n if iszero(lt(_pOut, end_)) { leave }\\n for { let c_ := chr(_pOut) } 1 {} {\\n // If starts with '\\\"'.\\n if eq(c_, 34) {\\n let pStart_ := _pOut\\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\\n break\\n }\\n // If starts with '['.\\n if eq(c_, 91) {\\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\\n break\\n }\\n // If starts with '{'.\\n if eq(c_, 123) {\\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\\n break\\n }\\n // If starts with any in '0123456789-'.\\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\\n break\\n }\\n if iszero(gt(add(_pOut, 4), end_)) {\\n let pStart_ := _pOut\\n let w_ := shr(224, mload(_pOut))\\n // 'true' in hex format.\\n if eq(w_, 0x74727565) {\\n _pOut := add(_pOut, 4)\\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\\n break\\n }\\n // 'null' in hex format.\\n if eq(w_, 0x6e756c6c) {\\n _pOut := add(_pOut, 4)\\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\\n break\\n }\\n }\\n if iszero(gt(add(_pOut, 5), end_)) {\\n let pStart_ := _pOut\\n let w_ := shr(216, mload(_pOut))\\n // 'false' in hex format.\\n if eq(w_, 0x66616c7365) {\\n _pOut := add(_pOut, 5)\\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\\n break\\n }\\n }\\n fail()\\n break\\n }\\n _pOut := skipWhitespace(_pOut, end_)\\n }\\n\\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\\n let j_ := 0\\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\\n if iszero(lt(_pOut, end_)) { fail() }\\n if iszero(_item) {\\n _pOut := skipWhitespace(_pOut, end_)\\n if eq(chr(_pOut), 93) { break } // ']'.\\n }\\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\\n if _item {\\n // forgefmt: disable-next-item\\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\\n _BITPOS_KEY, j_))\\n j_ := add(j_, 1)\\n let c_ := chr(_pOut)\\n if eq(c_, 93) { break } // ']'.\\n if eq(c_, 44) { continue } // ','.\\n }\\n _pOut := end_\\n }\\n _pOut := add(_pOut, 1)\\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\\n }\\n\\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\\n if iszero(lt(_pOut, end_)) { fail() }\\n if iszero(_item) {\\n _pOut := skipWhitespace(_pOut, end_)\\n if eq(chr(_pOut), 125) { break } // '}'.\\n }\\n _pOut := skipWhitespace(_pOut, end_)\\n let pKeyStart_ := _pOut\\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\\n _pOut := skipWhitespace(pKeyEnd_, end_)\\n // If ':'.\\n if eq(chr(_pOut), 58) {\\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\\n if _item {\\n // forgefmt: disable-next-item\\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\\n let c_ := chr(_pOut)\\n if eq(c_, 125) { break } // '}'.\\n if eq(c_, 44) { continue } // ','.\\n }\\n }\\n _pOut := end_\\n }\\n _pOut := add(_pOut, 1)\\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\\n }\\n\\n function checkStringU(p_, o_) {\\n // If not in '0123456789abcdefABCDEF', revert.\\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\\n }\\n\\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\\n if iszero(lt(pIn_, end_)) { fail() }\\n for { _pOut := add(pIn_, 1) } 1 {} {\\n let c_ := chr(_pOut)\\n if eq(c_, 34) { break } // '\\\"'.\\n // Not '\\\\'.\\n if iszero(eq(c_, 92)) {\\n _pOut := add(_pOut, 1)\\n continue\\n }\\n c_ := chr(add(_pOut, 1))\\n // '\\\"', '\\\\', '//', 'b', 'f', 'n', 'r', 't'.\\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\\n _pOut := add(_pOut, 2)\\n continue\\n }\\n // 'u'.\\n if eq(c_, 117) {\\n checkStringU(_pOut, 2)\\n _pOut := add(_pOut, 6)\\n continue\\n }\\n _pOut := end_\\n break\\n }\\n if iszero(lt(_pOut, end_)) { fail() }\\n _pOut := add(_pOut, 1)\\n }\\n\\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\\n }\\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\\n }\\n\\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\\n _pOut := pIn_\\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\\n let c_ := chr(_pOut)\\n _pOut := add(_pOut, 1)\\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\\n let t_ := mload(_pOut)\\n // 'E', 'e'.\\n if eq(or(0x20, byte(0, t_)), 101) {\\n // forgefmt: disable-next-item\\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\\n add(_pOut, 1)), end_, 1)\\n }\\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\\n }\\n\\n function copyStr(s_, offset_, len_) -> _sCopy {\\n _sCopy := mload(0x40)\\n s_ := add(s_, offset_)\\n let w_ := not(0x1f)\\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\\n if iszero(i_) { break }\\n }\\n mstore(_sCopy, len_) // Copy the length.\\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\\n }\\n\\n function value(item_) -> _value {\\n let packed_ := mload(item_)\\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\\n if iszero(and(_VALUE_INITED, packed_)) {\\n let s_ := getP(packed_, _BITPOS_STRING)\\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\\n mstore(s_, or(_VALUE_INITED, packed_))\\n }\\n }\\n\\n function children(item_) -> _arr {\\n _arr := 0x60 // Initialize to the zero pointer.\\n let packed_ := mload(item_)\\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\\n if or(iszero(packed_), iszero(item_)) { break }\\n if and(packed_, _CHILDREN_INITED) {\\n _arr := getP(packed_, _BITPOS_CHILD)\\n break\\n }\\n _arr := mload(0x40)\\n let o_ := add(_arr, 0x20)\\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\\n mstore(o_, h_)\\n let q_ := mload(h_)\\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\\n h_ := y_\\n o_ := add(o_, 0x20)\\n }\\n let w_ := not(0x1f)\\n let n_ := add(w_, sub(o_, _arr))\\n mstore(_arr, shr(5, n_))\\n mstore(0x40, o_) // Allocate memory.\\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\\n mstore(item_, or(_CHILDREN_INITED, packed_))\\n // Reverse the array.\\n if iszero(lt(n_, 0x40)) {\\n let lo_ := add(_arr, 0x20)\\n let hi_ := add(_arr, n_)\\n for {} 1 {} {\\n let temp_ := mload(lo_)\\n mstore(lo_, mload(hi_))\\n mstore(hi_, temp_)\\n hi_ := add(hi_, w_)\\n lo_ := add(lo_, 0x20)\\n if iszero(lt(lo_, hi_)) { break }\\n }\\n }\\n break\\n }\\n }\\n\\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\\n _result := 0x60 // Initialize to the zero pointer.\\n let packed_ := mload(item_)\\n if or(iszero(item_), iszero(packed_)) { leave }\\n _result := getP(packed_, bitpos_)\\n if iszero(and(bitmaskInited_, packed_)) {\\n let s_ := getP(packed_, _BITPOS_STRING)\\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\\n }\\n }\\n\\n switch mode\\n // Get value.\\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\\n // Get key.\\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\\n // Get children.\\n case 3 { result := children(input) }\\n // Parse.\\n default {\\n let p := add(input, 0x20)\\n let e := add(p, mload(input))\\n if iszero(eq(p, e)) {\\n let c := chr(e)\\n mstore8(e, 34) // Place a '\\\"' at the end to speed up parsing.\\n // The `34 << 248` makes `mallocItem` preserve '\\\"' at the end.\\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\\n result, p := parseValue(input, 0, p, e)\\n mstore8(e, c) // Restore the original char at the end.\\n }\\n if or(lt(p, e), iszero(result)) { fail() }\\n }\\n }\\n }\\n\\n /// @dev Casts the input to a bytes32.\\n function _toInput(string memory input) private pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := input\\n }\\n }\\n\\n /// @dev Casts the input to a bytes32.\\n function _toInput(Item memory input) private pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := input\\n }\\n }\\n}\\n\",\"keccak256\":\"0x24ddc4015b10af1bcf9eb4fd69d1e03a575698b0104b9ecc60c0c25464cd4d03\",\"license\":\"MIT\"},\"solady/src/utils/LibString.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.4;\\n\\n/// @notice Library for converting numbers into strings and other string operations.\\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\\n///\\n/// Note:\\n/// For performance and bytecode compactness, most of the string operations are restricted to\\n/// byte strings (7-bit ASCII), except where otherwise specified.\\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\\n/// can lead to undefined behavior.\\nlibrary LibString {\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* CUSTOM ERRORS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev The length of the output is too small to contain all the hex digits.\\n error HexLengthInsufficient();\\n\\n /// @dev The length of the string is more than 32 bytes.\\n error TooBigForSmallString();\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* CONSTANTS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev The constant returned when the `search` is not found in the string.\\n uint256 internal constant NOT_FOUND = type(uint256).max;\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* DECIMAL OPERATIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Returns the base 10 decimal representation of `value`.\\n function toString(uint256 value) internal pure returns (string memory str) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\\n // and 3 words for a maximum of 78 digits.\\n str := add(mload(0x40), 0x80)\\n // Update the free memory pointer to allocate.\\n mstore(0x40, add(str, 0x20))\\n // Zeroize the slot after the string.\\n mstore(str, 0)\\n\\n // Cache the end of the memory to calculate the length later.\\n let end := str\\n\\n let w := not(0) // Tsk.\\n // We write the string from rightmost digit to leftmost digit.\\n // The following is essentially a do-while loop that also handles the zero case.\\n for { let temp := value } 1 {} {\\n str := add(str, w) // `sub(str, 1)`.\\n // Write the character to the pointer.\\n // The ASCII index of the '0' character is 48.\\n mstore8(str, add(48, mod(temp, 10)))\\n // Keep dividing `temp` until zero.\\n temp := div(temp, 10)\\n if iszero(temp) { break }\\n }\\n\\n let length := sub(end, str)\\n // Move the pointer 32 bytes leftwards to make room for the length.\\n str := sub(str, 0x20)\\n // Store the length.\\n mstore(str, length)\\n }\\n }\\n\\n /// @dev Returns the base 10 decimal representation of `value`.\\n function toString(int256 value) internal pure returns (string memory str) {\\n if (value >= 0) {\\n return toString(uint256(value));\\n }\\n unchecked {\\n str = toString(~uint256(value) + 1);\\n }\\n /// @solidity memory-safe-assembly\\n assembly {\\n // We still have some spare memory space on the left,\\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\\n let length := mload(str) // Load the string length.\\n mstore(str, 0x2d) // Store the '-' character.\\n str := sub(str, 1) // Move back the string pointer by a byte.\\n mstore(str, add(length, 1)) // Update the string length.\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* HEXADECIMAL OPERATIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Returns the hexadecimal representation of `value`,\\n /// left-padded to an input length of `length` bytes.\\n /// The output is prefixed with \\\"0x\\\" encoded using 2 hexadecimal digits per byte,\\n /// giving a total length of `length * 2 + 2` bytes.\\n /// Reverts if `length` is too small for the output to contain all the digits.\\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(value, length);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let strLength := add(mload(str), 2) // Compute the length.\\n mstore(str, 0x3078) // Write the \\\"0x\\\" prefix.\\n str := sub(str, 2) // Move the pointer.\\n mstore(str, strLength) // Write the length.\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`,\\n /// left-padded to an input length of `length` bytes.\\n /// The output is prefixed with \\\"0x\\\" encoded using 2 hexadecimal digits per byte,\\n /// giving a total length of `length * 2` bytes.\\n /// Reverts if `length` is too small for the output to contain all the digits.\\n function toHexStringNoPrefix(uint256 value, uint256 length)\\n internal\\n pure\\n returns (string memory str)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\\n // We add 0x20 to the total and round down to a multiple of 0x20.\\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\\n // Allocate the memory.\\n mstore(0x40, add(str, 0x20))\\n // Zeroize the slot after the string.\\n mstore(str, 0)\\n\\n // Cache the end to calculate the length later.\\n let end := str\\n // Store \\\"0123456789abcdef\\\" in scratch space.\\n mstore(0x0f, 0x30313233343536373839616263646566)\\n\\n let start := sub(str, add(length, length))\\n let w := not(1) // Tsk.\\n let temp := value\\n // We write the string from rightmost digit to leftmost digit.\\n // The following is essentially a do-while loop that also handles the zero case.\\n for {} 1 {} {\\n str := add(str, w) // `sub(str, 2)`.\\n mstore8(add(str, 1), mload(and(temp, 15)))\\n mstore8(str, mload(and(shr(4, temp), 15)))\\n temp := shr(8, temp)\\n if iszero(xor(str, start)) { break }\\n }\\n\\n if temp {\\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\\n revert(0x1c, 0x04)\\n }\\n\\n // Compute the string's length.\\n let strLength := sub(end, str)\\n // Move the pointer and write the length.\\n str := sub(str, 0x20)\\n mstore(str, strLength)\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is prefixed with \\\"0x\\\" and encoded using 2 hexadecimal digits per byte.\\n /// As address are 20 bytes long, the output will left-padded to have\\n /// a length of `20 * 2 + 2` bytes.\\n function toHexString(uint256 value) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(value);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let strLength := add(mload(str), 2) // Compute the length.\\n mstore(str, 0x3078) // Write the \\\"0x\\\" prefix.\\n str := sub(str, 2) // Move the pointer.\\n mstore(str, strLength) // Write the length.\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is prefixed with \\\"0x\\\".\\n /// The output excludes leading \\\"0\\\" from the `toHexString` output.\\n /// `0x00: \\\"0x0\\\", 0x01: \\\"0x1\\\", 0x12: \\\"0x12\\\", 0x123: \\\"0x123\\\"`.\\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(value);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\\n let strLength := add(mload(str), 2) // Compute the length.\\n mstore(add(str, o), 0x3078) // Write the \\\"0x\\\" prefix, accounting for leading zero.\\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output excludes leading \\\"0\\\" from the `toHexStringNoPrefix` output.\\n /// `0x00: \\\"0\\\", 0x01: \\\"1\\\", 0x12: \\\"12\\\", 0x123: \\\"123\\\"`.\\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(value);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\\n let strLength := mload(str) // Get the length.\\n str := add(str, o) // Move the pointer, accounting for leading zero.\\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is encoded using 2 hexadecimal digits per byte.\\n /// As address are 20 bytes long, the output will left-padded to have\\n /// a length of `20 * 2` bytes.\\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\\n str := add(mload(0x40), 0x80)\\n // Allocate the memory.\\n mstore(0x40, add(str, 0x20))\\n // Zeroize the slot after the string.\\n mstore(str, 0)\\n\\n // Cache the end to calculate the length later.\\n let end := str\\n // Store \\\"0123456789abcdef\\\" in scratch space.\\n mstore(0x0f, 0x30313233343536373839616263646566)\\n\\n let w := not(1) // Tsk.\\n // We write the string from rightmost digit to leftmost digit.\\n // The following is essentially a do-while loop that also handles the zero case.\\n for { let temp := value } 1 {} {\\n str := add(str, w) // `sub(str, 2)`.\\n mstore8(add(str, 1), mload(and(temp, 15)))\\n mstore8(str, mload(and(shr(4, temp), 15)))\\n temp := shr(8, temp)\\n if iszero(temp) { break }\\n }\\n\\n // Compute the string's length.\\n let strLength := sub(end, str)\\n // Move the pointer and write the length.\\n str := sub(str, 0x20)\\n mstore(str, strLength)\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is prefixed with \\\"0x\\\", encoded using 2 hexadecimal digits per byte,\\n /// and the alphabets are capitalized conditionally according to\\n /// https://eips.ethereum.org/EIPS/eip-55\\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\\n str = toHexString(value);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\\n let o := add(str, 0x22)\\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\\n let t := shl(240, 136) // `0b10001000 << 240`\\n for { let i := 0 } 1 {} {\\n mstore(add(i, i), mul(t, byte(i, hashed)))\\n i := add(i, 1)\\n if eq(i, 20) { break }\\n }\\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\\n o := add(o, 0x20)\\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is prefixed with \\\"0x\\\" and encoded using 2 hexadecimal digits per byte.\\n function toHexString(address value) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(value);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let strLength := add(mload(str), 2) // Compute the length.\\n mstore(str, 0x3078) // Write the \\\"0x\\\" prefix.\\n str := sub(str, 2) // Move the pointer.\\n mstore(str, strLength) // Write the length.\\n }\\n }\\n\\n /// @dev Returns the hexadecimal representation of `value`.\\n /// The output is encoded using 2 hexadecimal digits per byte.\\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n str := mload(0x40)\\n\\n // Allocate the memory.\\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\\n mstore(0x40, add(str, 0x80))\\n\\n // Store \\\"0123456789abcdef\\\" in scratch space.\\n mstore(0x0f, 0x30313233343536373839616263646566)\\n\\n str := add(str, 2)\\n mstore(str, 40)\\n\\n let o := add(str, 0x20)\\n mstore(add(o, 40), 0)\\n\\n value := shl(96, value)\\n\\n // We write the string from rightmost digit to leftmost digit.\\n // The following is essentially a do-while loop that also handles the zero case.\\n for { let i := 0 } 1 {} {\\n let p := add(o, add(i, i))\\n let temp := byte(i, value)\\n mstore8(add(p, 1), mload(and(temp, 15)))\\n mstore8(p, mload(shr(4, temp)))\\n i := add(i, 1)\\n if eq(i, 20) { break }\\n }\\n }\\n }\\n\\n /// @dev Returns the hex encoded string from the raw bytes.\\n /// The output is encoded using 2 hexadecimal digits per byte.\\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\\n str = toHexStringNoPrefix(raw);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let strLength := add(mload(str), 2) // Compute the length.\\n mstore(str, 0x3078) // Write the \\\"0x\\\" prefix.\\n str := sub(str, 2) // Move the pointer.\\n mstore(str, strLength) // Write the length.\\n }\\n }\\n\\n /// @dev Returns the hex encoded string from the raw bytes.\\n /// The output is encoded using 2 hexadecimal digits per byte.\\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let length := mload(raw)\\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\\n mstore(str, add(length, length)) // Store the length of the output.\\n\\n // Store \\\"0123456789abcdef\\\" in scratch space.\\n mstore(0x0f, 0x30313233343536373839616263646566)\\n\\n let o := add(str, 0x20)\\n let end := add(raw, length)\\n\\n for {} iszero(eq(raw, end)) {} {\\n raw := add(raw, 1)\\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\\n o := add(o, 2)\\n }\\n mstore(o, 0) // Zeroize the slot after the string.\\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* RUNE STRING OPERATIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n /// @dev Returns the number of UTF characters in the string.\\n function runeCount(string memory s) internal pure returns (uint256 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n if mload(s) {\\n mstore(0x00, div(not(0), 255))\\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\\n let o := add(s, 0x20)\\n let end := add(o, mload(s))\\n for { result := 1 } 1 { result := add(result, 1) } {\\n o := add(o, byte(0, mload(shr(250, mload(o)))))\\n if iszero(lt(o, end)) { break }\\n }\\n }\\n }\\n }\\n\\n /// @dev Returns if this string is a 7-bit ASCII string.\\n /// (i.e. all characters codes are in [0..127])\\n function is7BitASCII(string memory s) internal pure returns (bool result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let mask := shl(7, div(not(0), 255))\\n result := 1\\n let n := mload(s)\\n if n {\\n let o := add(s, 0x20)\\n let end := add(o, n)\\n let last := mload(end)\\n mstore(end, 0)\\n for {} 1 {} {\\n if and(mask, mload(o)) {\\n result := 0\\n break\\n }\\n o := add(o, 0x20)\\n if iszero(lt(o, end)) { break }\\n }\\n mstore(end, last)\\n }\\n }\\n }\\n\\n /*\\u00b4:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0\\u2022.*\\u2022\\u00b4.*:\\u02da.\\u00b0*.\\u02da\\u2022\\u00b4.\\u00b0:\\u00b0\\u2022.\\u00b0+.*\\u2022\\u00b4.*:*/\\n /* BYTE STRING OPERATIONS */\\n /*.\\u2022\\u00b0:\\u00b0.\\u00b4+\\u02da.*\\u00b0.\\u02da:*.\\u00b4\\u2022*.+\\u00b0.\\u2022\\u00b0:\\u00b4*.\\u00b4\\u2022*.\\u2022\\u00b0.\\u2022\\u00b0:\\u00b0.\\u00b4:\\u2022\\u02da\\u00b0.*\\u00b0.\\u02da:*.\\u00b4+\\u00b0.\\u2022*/\\n\\n // For performance and bytecode compactness, byte string operations are restricted\\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\\n // Usage of byte string operations on charsets with runes spanning two or more bytes\\n // can lead to undefined behavior.\\n\\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\\n function replace(string memory subject, string memory search, string memory replacement)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let subjectLength := mload(subject)\\n let searchLength := mload(search)\\n let replacementLength := mload(replacement)\\n\\n subject := add(subject, 0x20)\\n search := add(search, 0x20)\\n replacement := add(replacement, 0x20)\\n result := add(mload(0x40), 0x20)\\n\\n let subjectEnd := add(subject, subjectLength)\\n if iszero(gt(searchLength, subjectLength)) {\\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\\n let h := 0\\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\\n let s := mload(search)\\n for {} 1 {} {\\n let t := mload(subject)\\n // Whether the first `searchLength % 32` bytes of\\n // `subject` and `search` matches.\\n if iszero(shr(m, xor(t, s))) {\\n if h {\\n if iszero(eq(keccak256(subject, searchLength), h)) {\\n mstore(result, t)\\n result := add(result, 1)\\n subject := add(subject, 1)\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n continue\\n }\\n }\\n // Copy the `replacement` one word at a time.\\n for { let o := 0 } 1 {} {\\n mstore(add(result, o), mload(add(replacement, o)))\\n o := add(o, 0x20)\\n if iszero(lt(o, replacementLength)) { break }\\n }\\n result := add(result, replacementLength)\\n subject := add(subject, searchLength)\\n if searchLength {\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n continue\\n }\\n }\\n mstore(result, t)\\n result := add(result, 1)\\n subject := add(subject, 1)\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n }\\n }\\n\\n let resultRemainder := result\\n result := add(mload(0x40), 0x20)\\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\\n // Copy the rest of the string one word at a time.\\n for {} lt(subject, subjectEnd) {} {\\n mstore(resultRemainder, mload(subject))\\n resultRemainder := add(resultRemainder, 0x20)\\n subject := add(subject, 0x20)\\n }\\n result := sub(result, 0x20)\\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\\n mstore(last, 0)\\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\\n mstore(result, k) // Store the length.\\n }\\n }\\n\\n /// @dev Returns the byte index of the first location of `search` in `subject`,\\n /// searching from left to right, starting from `from`.\\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\\n function indexOf(string memory subject, string memory search, uint256 from)\\n internal\\n pure\\n returns (uint256 result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n for { let subjectLength := mload(subject) } 1 {} {\\n if iszero(mload(search)) {\\n if iszero(gt(from, subjectLength)) {\\n result := from\\n break\\n }\\n result := subjectLength\\n break\\n }\\n let searchLength := mload(search)\\n let subjectStart := add(subject, 0x20)\\n\\n result := not(0) // Initialize to `NOT_FOUND`.\\n\\n subject := add(subjectStart, from)\\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\\n\\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\\n let s := mload(add(search, 0x20))\\n\\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\\n\\n if iszero(lt(searchLength, 0x20)) {\\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\\n if iszero(shr(m, xor(mload(subject), s))) {\\n if eq(keccak256(subject, searchLength), h) {\\n result := sub(subject, subjectStart)\\n break\\n }\\n }\\n subject := add(subject, 1)\\n if iszero(lt(subject, end)) { break }\\n }\\n break\\n }\\n for {} 1 {} {\\n if iszero(shr(m, xor(mload(subject), s))) {\\n result := sub(subject, subjectStart)\\n break\\n }\\n subject := add(subject, 1)\\n if iszero(lt(subject, end)) { break }\\n }\\n break\\n }\\n }\\n }\\n\\n /// @dev Returns the byte index of the first location of `search` in `subject`,\\n /// searching from left to right.\\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\\n function indexOf(string memory subject, string memory search)\\n internal\\n pure\\n returns (uint256 result)\\n {\\n result = indexOf(subject, search, 0);\\n }\\n\\n /// @dev Returns the byte index of the first location of `search` in `subject`,\\n /// searching from right to left, starting from `from`.\\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\\n function lastIndexOf(string memory subject, string memory search, uint256 from)\\n internal\\n pure\\n returns (uint256 result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n for {} 1 {} {\\n result := not(0) // Initialize to `NOT_FOUND`.\\n let searchLength := mload(search)\\n if gt(searchLength, mload(subject)) { break }\\n let w := result\\n\\n let fromMax := sub(mload(subject), searchLength)\\n if iszero(gt(fromMax, from)) { from := fromMax }\\n\\n let end := add(add(subject, 0x20), w)\\n subject := add(add(subject, 0x20), from)\\n if iszero(gt(subject, end)) { break }\\n // As this function is not too often used,\\n // we shall simply use keccak256 for smaller bytecode size.\\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\\n if eq(keccak256(subject, searchLength), h) {\\n result := sub(subject, add(end, 1))\\n break\\n }\\n subject := add(subject, w) // `sub(subject, 1)`.\\n if iszero(gt(subject, end)) { break }\\n }\\n break\\n }\\n }\\n }\\n\\n /// @dev Returns the byte index of the first location of `search` in `subject`,\\n /// searching from right to left.\\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\\n function lastIndexOf(string memory subject, string memory search)\\n internal\\n pure\\n returns (uint256 result)\\n {\\n result = lastIndexOf(subject, search, uint256(int256(-1)));\\n }\\n\\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\\n function contains(string memory subject, string memory search) internal pure returns (bool) {\\n return indexOf(subject, search) != NOT_FOUND;\\n }\\n\\n /// @dev Returns whether `subject` starts with `search`.\\n function startsWith(string memory subject, string memory search)\\n internal\\n pure\\n returns (bool result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let searchLength := mload(search)\\n // Just using keccak256 directly is actually cheaper.\\n // forgefmt: disable-next-item\\n result := and(\\n iszero(gt(searchLength, mload(subject))),\\n eq(\\n keccak256(add(subject, 0x20), searchLength),\\n keccak256(add(search, 0x20), searchLength)\\n )\\n )\\n }\\n }\\n\\n /// @dev Returns whether `subject` ends with `search`.\\n function endsWith(string memory subject, string memory search)\\n internal\\n pure\\n returns (bool result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let searchLength := mload(search)\\n let subjectLength := mload(subject)\\n // Whether `search` is not longer than `subject`.\\n let withinRange := iszero(gt(searchLength, subjectLength))\\n // Just using keccak256 directly is actually cheaper.\\n // forgefmt: disable-next-item\\n result := and(\\n withinRange,\\n eq(\\n keccak256(\\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\\n searchLength\\n ),\\n keccak256(add(search, 0x20), searchLength)\\n )\\n )\\n }\\n }\\n\\n /// @dev Returns `subject` repeated `times`.\\n function repeat(string memory subject, uint256 times)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let subjectLength := mload(subject)\\n if iszero(or(iszero(times), iszero(subjectLength))) {\\n subject := add(subject, 0x20)\\n result := mload(0x40)\\n let output := add(result, 0x20)\\n for {} 1 {} {\\n // Copy the `subject` one word at a time.\\n for { let o := 0 } 1 {} {\\n mstore(add(output, o), mload(add(subject, o)))\\n o := add(o, 0x20)\\n if iszero(lt(o, subjectLength)) { break }\\n }\\n output := add(output, subjectLength)\\n times := sub(times, 1)\\n if iszero(times) { break }\\n }\\n mstore(output, 0) // Zeroize the slot after the string.\\n let resultLength := sub(output, add(result, 0x20))\\n mstore(result, resultLength) // Store the length.\\n // Allocate the memory.\\n mstore(0x40, add(result, add(resultLength, 0x20)))\\n }\\n }\\n }\\n\\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\\n /// `start` and `end` are byte offsets.\\n function slice(string memory subject, uint256 start, uint256 end)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let subjectLength := mload(subject)\\n if iszero(gt(subjectLength, end)) { end := subjectLength }\\n if iszero(gt(subjectLength, start)) { start := subjectLength }\\n if lt(start, end) {\\n result := mload(0x40)\\n let resultLength := sub(end, start)\\n mstore(result, resultLength)\\n subject := add(subject, start)\\n let w := not(0x1f)\\n // Copy the `subject` one word at a time, backwards.\\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\\n mstore(add(result, o), mload(add(subject, o)))\\n o := add(o, w) // `sub(o, 0x20)`.\\n if iszero(o) { break }\\n }\\n // Zeroize the slot after the string.\\n mstore(add(add(result, 0x20), resultLength), 0)\\n // Allocate memory for the length and the bytes,\\n // rounded up to a multiple of 32.\\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\\n }\\n }\\n }\\n\\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\\n /// `start` is a byte offset.\\n function slice(string memory subject, uint256 start)\\n internal\\n pure\\n returns (string memory result)\\n {\\n result = slice(subject, start, uint256(int256(-1)));\\n }\\n\\n /// @dev Returns all the indices of `search` in `subject`.\\n /// The indices are byte offsets.\\n function indicesOf(string memory subject, string memory search)\\n internal\\n pure\\n returns (uint256[] memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let subjectLength := mload(subject)\\n let searchLength := mload(search)\\n\\n if iszero(gt(searchLength, subjectLength)) {\\n subject := add(subject, 0x20)\\n search := add(search, 0x20)\\n result := add(mload(0x40), 0x20)\\n\\n let subjectStart := subject\\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\\n let h := 0\\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\\n let s := mload(search)\\n for {} 1 {} {\\n let t := mload(subject)\\n // Whether the first `searchLength % 32` bytes of\\n // `subject` and `search` matches.\\n if iszero(shr(m, xor(t, s))) {\\n if h {\\n if iszero(eq(keccak256(subject, searchLength), h)) {\\n subject := add(subject, 1)\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n continue\\n }\\n }\\n // Append to `result`.\\n mstore(result, sub(subject, subjectStart))\\n result := add(result, 0x20)\\n // Advance `subject` by `searchLength`.\\n subject := add(subject, searchLength)\\n if searchLength {\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n continue\\n }\\n }\\n subject := add(subject, 1)\\n if iszero(lt(subject, subjectSearchEnd)) { break }\\n }\\n let resultEnd := result\\n // Assign `result` to the free memory pointer.\\n result := mload(0x40)\\n // Store the length of `result`.\\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\\n // Allocate memory for result.\\n // We allocate one more word, so this array can be recycled for {split}.\\n mstore(0x40, add(resultEnd, 0x20))\\n }\\n }\\n }\\n\\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\\n function split(string memory subject, string memory delimiter)\\n internal\\n pure\\n returns (string[] memory result)\\n {\\n uint256[] memory indices = indicesOf(subject, delimiter);\\n /// @solidity memory-safe-assembly\\n assembly {\\n let w := not(0x1f)\\n let indexPtr := add(indices, 0x20)\\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\\n mstore(add(indicesEnd, w), mload(subject))\\n mstore(indices, add(mload(indices), 1))\\n let prevIndex := 0\\n for {} 1 {} {\\n let index := mload(indexPtr)\\n mstore(indexPtr, 0x60)\\n if iszero(eq(index, prevIndex)) {\\n let element := mload(0x40)\\n let elementLength := sub(index, prevIndex)\\n mstore(element, elementLength)\\n // Copy the `subject` one word at a time, backwards.\\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\\n o := add(o, w) // `sub(o, 0x20)`.\\n if iszero(o) { break }\\n }\\n // Zeroize the slot after the string.\\n mstore(add(add(element, 0x20), elementLength), 0)\\n // Allocate memory for the length and the bytes,\\n // rounded up to a multiple of 32.\\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\\n // Store the `element` into the array.\\n mstore(indexPtr, element)\\n }\\n prevIndex := add(index, mload(delimiter))\\n indexPtr := add(indexPtr, 0x20)\\n if iszero(lt(indexPtr, indicesEnd)) { break }\\n }\\n result := indices\\n if iszero(mload(delimiter)) {\\n result := add(indices, 0x20)\\n mstore(result, sub(mload(indices), 2))\\n }\\n }\\n }\\n\\n /// @dev Returns a concatenated string of `a` and `b`.\\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\\n function concat(string memory a, string memory b)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let w := not(0x1f)\\n result := mload(0x40)\\n let aLength := mload(a)\\n // Copy `a` one word at a time, backwards.\\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\\n mstore(add(result, o), mload(add(a, o)))\\n o := add(o, w) // `sub(o, 0x20)`.\\n if iszero(o) { break }\\n }\\n let bLength := mload(b)\\n let output := add(result, aLength)\\n // Copy `b` one word at a time, backwards.\\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\\n mstore(add(output, o), mload(add(b, o)))\\n o := add(o, w) // `sub(o, 0x20)`.\\n if iszero(o) { break }\\n }\\n let totalLength := add(aLength, bLength)\\n let last := add(add(result, 0x20), totalLength)\\n // Zeroize the slot after the string.\\n mstore(last, 0)\\n // Stores the length.\\n mstore(result, totalLength)\\n // Allocate memory for the length and the bytes,\\n // rounded up to a multiple of 32.\\n mstore(0x40, and(add(last, 0x1f), w))\\n }\\n }\\n\\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\\n function toCase(string memory subject, bool toUpper)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let length := mload(subject)\\n if length {\\n result := add(mload(0x40), 0x20)\\n subject := add(subject, 1)\\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\\n let w := not(0)\\n for { let o := length } 1 {} {\\n o := add(o, w)\\n let b := and(0xff, mload(add(subject, o)))\\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\\n if iszero(o) { break }\\n }\\n result := mload(0x40)\\n mstore(result, length) // Store the length.\\n let last := add(add(result, 0x20), length)\\n mstore(last, 0) // Zeroize the slot after the string.\\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\\n }\\n }\\n }\\n\\n /// @dev Returns a string from a small bytes32 string.\\n /// `s` must be null-terminated, or behavior will be undefined.\\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := mload(0x40)\\n let n := 0\\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\\\0'.\\n mstore(result, n)\\n let o := add(result, 0x20)\\n mstore(o, s)\\n mstore(add(o, n), 0)\\n mstore(0x40, add(result, 0x40))\\n }\\n }\\n\\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\\\0'.\\n mstore(0x00, s)\\n mstore(result, 0x00)\\n result := mload(0x00)\\n }\\n }\\n\\n /// @dev Returns the string as a normalized null-terminated small string.\\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := mload(s)\\n if iszero(lt(result, 33)) {\\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\\n revert(0x1c, 0x04)\\n }\\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\\n }\\n }\\n\\n /// @dev Returns a lowercased copy of the string.\\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\\n function lower(string memory subject) internal pure returns (string memory result) {\\n result = toCase(subject, false);\\n }\\n\\n /// @dev Returns an UPPERCASED copy of the string.\\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\\n function upper(string memory subject) internal pure returns (string memory result) {\\n result = toCase(subject, true);\\n }\\n\\n /// @dev Escapes the string to be used within HTML tags.\\n function escapeHTML(string memory s) internal pure returns (string memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let end := add(s, mload(s))\\n result := add(mload(0x40), 0x20)\\n // Store the bytes of the packed offsets and strides into the scratch space.\\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\\n mstore(0x1f, 0x900094)\\n mstore(0x08, 0xc0000000a6ab)\\n // Store \\\""&'<>\\\" into the scratch space.\\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\\n for {} iszero(eq(s, end)) {} {\\n s := add(s, 1)\\n let c := and(mload(s), 0xff)\\n // Not in `[\\\"\\\\\\\"\\\",\\\"'\\\",\\\"&\\\",\\\"<\\\",\\\">\\\"]`.\\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\\n mstore8(result, c)\\n result := add(result, 1)\\n continue\\n }\\n let t := shr(248, mload(c))\\n mstore(result, mload(and(t, 0x1f)))\\n result := add(result, shr(5, t))\\n }\\n let last := result\\n mstore(last, 0) // Zeroize the slot after the string.\\n result := mload(0x40)\\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\\n }\\n }\\n\\n /// @dev Escapes the string to be used within double-quotes in a JSON.\\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\\n function escapeJSON(string memory s, bool addDoubleQuotes)\\n internal\\n pure\\n returns (string memory result)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let end := add(s, mload(s))\\n result := add(mload(0x40), 0x20)\\n if addDoubleQuotes {\\n mstore8(result, 34)\\n result := add(1, result)\\n }\\n // Store \\\"\\\\\\\\u0000\\\" in scratch space.\\n // Store \\\"0123456789abcdef\\\" in scratch space.\\n // Also, store `{0x08:\\\"b\\\", 0x09:\\\"t\\\", 0x0a:\\\"n\\\", 0x0c:\\\"f\\\", 0x0d:\\\"r\\\"}`.\\n // into the scratch space.\\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\\n // Bitmask for detecting `[\\\"\\\\\\\"\\\",\\\"\\\\\\\\\\\"]`.\\n let e := or(shl(0x22, 1), shl(0x5c, 1))\\n for {} iszero(eq(s, end)) {} {\\n s := add(s, 1)\\n let c := and(mload(s), 0xff)\\n if iszero(lt(c, 0x20)) {\\n if iszero(and(shl(c, 1), e)) {\\n // Not in `[\\\"\\\\\\\"\\\",\\\"\\\\\\\\\\\"]`.\\n mstore8(result, c)\\n result := add(result, 1)\\n continue\\n }\\n mstore8(result, 0x5c) // \\\"\\\\\\\\\\\".\\n mstore8(add(result, 1), c)\\n result := add(result, 2)\\n continue\\n }\\n if iszero(and(shl(c, 1), 0x3700)) {\\n // Not in `[\\\"\\\\b\\\",\\\"\\\\t\\\",\\\"\\\\n\\\",\\\"\\\\f\\\",\\\"\\\\d\\\"]`.\\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\\n mstore(result, mload(0x19)) // \\\"\\\\\\\\u00XX\\\".\\n result := add(result, 6)\\n continue\\n }\\n mstore8(result, 0x5c) // \\\"\\\\\\\\\\\".\\n mstore8(add(result, 1), mload(add(c, 8)))\\n result := add(result, 2)\\n }\\n if addDoubleQuotes {\\n mstore8(result, 34)\\n result := add(1, result)\\n }\\n let last := result\\n mstore(last, 0) // Zeroize the slot after the string.\\n result := mload(0x40)\\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\\n }\\n }\\n\\n /// @dev Escapes the string to be used within double-quotes in a JSON.\\n function escapeJSON(string memory s) internal pure returns (string memory result) {\\n result = escapeJSON(s, false);\\n }\\n\\n /// @dev Returns whether `a` equals `b`.\\n function eq(string memory a, string memory b) internal pure returns (bool result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\\n }\\n }\\n\\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // These should be evaluated on compile time, as far as possible.\\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\\n let x := not(or(m, or(b, add(m, and(b, m)))))\\n let r := shl(7, iszero(iszero(shr(128, x))))\\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\\n r := or(r, shl(3, lt(0xff, shr(r, x))))\\n // forgefmt: disable-next-item\\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\\n }\\n }\\n\\n /// @dev Packs a single string with its length into a single word.\\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\\n function packOne(string memory a) internal pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // We don't need to zero right pad the string,\\n // since this is our own custom non-standard packing scheme.\\n result :=\\n mul(\\n // Load the length and the bytes.\\n mload(add(a, 0x1f)),\\n // `length != 0 && length < 32`. Abuses underflow.\\n // Assumes that the length is valid and within the block gas limit.\\n lt(sub(mload(a), 1), 0x1f)\\n )\\n }\\n }\\n\\n /// @dev Unpacks a string packed using {packOne}.\\n /// Returns the empty string if `packed` is `bytes32(0)`.\\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Grab the free memory pointer.\\n result := mload(0x40)\\n // Allocate 2 words (1 for the length, 1 for the bytes).\\n mstore(0x40, add(result, 0x40))\\n // Zeroize the length slot.\\n mstore(result, 0)\\n // Store the length and bytes.\\n mstore(add(result, 0x1f), packed)\\n // Right pad with zeroes.\\n mstore(add(add(result, 0x20), mload(result)), 0)\\n }\\n }\\n\\n /// @dev Packs two strings with their lengths into a single word.\\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n let aLength := mload(a)\\n // We don't need to zero right pad the strings,\\n // since this is our own custom non-standard packing scheme.\\n result :=\\n mul(\\n // Load the length and the bytes of `a` and `b`.\\n or(\\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\\n mload(sub(add(b, 0x1e), aLength))\\n ),\\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\\n // Assumes that the lengths are valid and within the block gas limit.\\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\\n )\\n }\\n }\\n\\n /// @dev Unpacks strings packed using {packTwo}.\\n /// Returns the empty strings if `packed` is `bytes32(0)`.\\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\\n function unpackTwo(bytes32 packed)\\n internal\\n pure\\n returns (string memory resultA, string memory resultB)\\n {\\n /// @solidity memory-safe-assembly\\n assembly {\\n // Grab the free memory pointer.\\n resultA := mload(0x40)\\n resultB := add(resultA, 0x40)\\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\\n mstore(0x40, add(resultB, 0x40))\\n // Zeroize the length slots.\\n mstore(resultA, 0)\\n mstore(resultB, 0)\\n // Store the lengths and bytes.\\n mstore(add(resultA, 0x1f), packed)\\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\\n // Right pad with zeroes.\\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\\n }\\n }\\n\\n /// @dev Directly returns `a` without copying.\\n function directReturn(string memory a) internal pure {\\n assembly {\\n // Assumes that the string does not start from the scratch space.\\n let retStart := sub(a, 0x20)\\n let retSize := add(mload(a), 0x40)\\n // Right pad with zeroes. Just in case the string is produced\\n // by a method that doesn't zero right pad.\\n mstore(add(retStart, retSize), 0)\\n // Store the return offset.\\n mstore(retStart, 0x20)\\n // End the transaction, returning the string.\\n return(retStart, retSize)\\n }\\n }\\n}\\n\",\"keccak256\":\"0xf9089e94e05f506f21357bc513c166d58f4d6a02d589741c72e8a7722cefeda2\",\"license\":\"MIT\"},\"solidity-rlp/contracts/RLPReader.sol\":{\"content\":\"// SPDX-License-Identifier: Apache-2.0\\n\\n/*\\n * @author Hamdi Allam hamdi.allam97@gmail.com\\n * Please reach out with any questions or concerns\\n */\\npragma solidity >=0.5.10 <0.9.0;\\n\\nlibrary RLPReader {\\n uint8 constant STRING_SHORT_START = 0x80;\\n uint8 constant STRING_LONG_START = 0xb8;\\n uint8 constant LIST_SHORT_START = 0xc0;\\n uint8 constant LIST_LONG_START = 0xf8;\\n uint8 constant WORD_SIZE = 32;\\n\\n struct RLPItem {\\n uint256 len;\\n uint256 memPtr;\\n }\\n\\n struct Iterator {\\n RLPItem item; // Item that's being iterated over.\\n uint256 nextPtr; // Position of the next item in the list.\\n }\\n\\n /*\\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\\n * @param self The iterator.\\n * @return The next element in the iteration.\\n */\\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\\n require(hasNext(self));\\n\\n uint256 ptr = self.nextPtr;\\n uint256 itemLength = _itemLength(ptr);\\n self.nextPtr = ptr + itemLength;\\n\\n return RLPItem(itemLength, ptr);\\n }\\n\\n /*\\n * @dev Returns true if the iteration has more elements.\\n * @param self The iterator.\\n * @return true if the iteration has more elements.\\n */\\n function hasNext(Iterator memory self) internal pure returns (bool) {\\n RLPItem memory item = self.item;\\n return self.nextPtr < item.memPtr + item.len;\\n }\\n\\n /*\\n * @param item RLP encoded bytes\\n */\\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\\n uint256 memPtr;\\n assembly {\\n memPtr := add(item, 0x20)\\n }\\n\\n return RLPItem(item.length, memPtr);\\n }\\n\\n /*\\n * @dev Create an iterator. Reverts if item is not a list.\\n * @param self The RLP item.\\n * @return An 'Iterator' over the item.\\n */\\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\\n require(isList(self));\\n\\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\\n return Iterator(self, ptr);\\n }\\n\\n /*\\n * @param the RLP item.\\n */\\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\\n return item.len;\\n }\\n\\n /*\\n * @param the RLP item.\\n * @return (memPtr, len) pair: location of the item's payload in memory.\\n */\\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\\n uint256 offset = _payloadOffset(item.memPtr);\\n uint256 memPtr = item.memPtr + offset;\\n uint256 len = item.len - offset; // data length\\n return (memPtr, len);\\n }\\n\\n /*\\n * @param the RLP item.\\n */\\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\\n (, uint256 len) = payloadLocation(item);\\n return len;\\n }\\n\\n /*\\n * @param the RLP item containing the encoded list.\\n */\\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\\n require(isList(item));\\n\\n uint256 items = numItems(item);\\n RLPItem[] memory result = new RLPItem[](items);\\n\\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\\n uint256 dataLen;\\n for (uint256 i = 0; i < items; i++) {\\n dataLen = _itemLength(memPtr);\\n result[i] = RLPItem(dataLen, memPtr);\\n memPtr = memPtr + dataLen;\\n }\\n\\n return result;\\n }\\n\\n // @return indicator whether encoded payload is a list. negate this function call for isData.\\n function isList(RLPItem memory item) internal pure returns (bool) {\\n if (item.len == 0) return false;\\n\\n uint8 byte0;\\n uint256 memPtr = item.memPtr;\\n assembly {\\n byte0 := byte(0, mload(memPtr))\\n }\\n\\n if (byte0 < LIST_SHORT_START) return false;\\n return true;\\n }\\n\\n /*\\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\\n * @return keccak256 hash of RLP encoded bytes.\\n */\\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\\n uint256 ptr = item.memPtr;\\n uint256 len = item.len;\\n bytes32 result;\\n assembly {\\n result := keccak256(ptr, len)\\n }\\n return result;\\n }\\n\\n /*\\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\\n * @return keccak256 hash of the item payload.\\n */\\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\\n (uint256 memPtr, uint256 len) = payloadLocation(item);\\n bytes32 result;\\n assembly {\\n result := keccak256(memPtr, len)\\n }\\n return result;\\n }\\n\\n /** RLPItem conversions into data types **/\\n\\n // @returns raw rlp encoding in bytes\\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\\n bytes memory result = new bytes(item.len);\\n if (result.length == 0) return result;\\n\\n uint256 ptr;\\n assembly {\\n ptr := add(0x20, result)\\n }\\n\\n copy(item.memPtr, ptr, item.len);\\n return result;\\n }\\n\\n // any non-zero byte except \\\"0x80\\\" is considered true\\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\\n require(item.len == 1);\\n uint256 result;\\n uint256 memPtr = item.memPtr;\\n assembly {\\n result := byte(0, mload(memPtr))\\n }\\n\\n // SEE Github Issue #5.\\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\\n // \\\"0\\\" as \\\"0x80\\\" instead of as \\\"0\\\". We handle this edge case explicitly\\n // here.\\n if (result == 0 || result == STRING_SHORT_START) {\\n return false;\\n } else {\\n return true;\\n }\\n }\\n\\n function toAddress(RLPItem memory item) internal pure returns (address) {\\n // 1 byte for the length prefix\\n require(item.len == 21);\\n\\n return address(uint160(toUint(item)));\\n }\\n\\n function toUint(RLPItem memory item) internal pure returns (uint256) {\\n require(item.len > 0 && item.len <= 33);\\n\\n (uint256 memPtr, uint256 len) = payloadLocation(item);\\n\\n uint256 result;\\n assembly {\\n result := mload(memPtr)\\n\\n // shift to the correct location if neccesary\\n if lt(len, 32) {\\n result := div(result, exp(256, sub(32, len)))\\n }\\n }\\n\\n return result;\\n }\\n\\n // enforces 32 byte length\\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\\n // one byte prefix\\n require(item.len == 33);\\n\\n uint256 result;\\n uint256 memPtr = item.memPtr + 1;\\n assembly {\\n result := mload(memPtr)\\n }\\n\\n return result;\\n }\\n\\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\\n require(item.len > 0);\\n\\n (uint256 memPtr, uint256 len) = payloadLocation(item);\\n bytes memory result = new bytes(len);\\n\\n uint256 destPtr;\\n assembly {\\n destPtr := add(0x20, result)\\n }\\n\\n copy(memPtr, destPtr, len);\\n return result;\\n }\\n\\n /*\\n * Private Helpers\\n */\\n\\n // @return number of payload items inside an encoded list.\\n function numItems(RLPItem memory item) private pure returns (uint256) {\\n if (item.len == 0) return 0;\\n\\n uint256 count = 0;\\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\\n uint256 endPtr = item.memPtr + item.len;\\n while (currPtr < endPtr) {\\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\\n count++;\\n }\\n\\n return count;\\n }\\n\\n // @return entire rlp item byte length\\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\\n uint256 itemLen;\\n uint256 byte0;\\n assembly {\\n byte0 := byte(0, mload(memPtr))\\n }\\n\\n if (byte0 < STRING_SHORT_START) {\\n itemLen = 1;\\n } else if (byte0 < STRING_LONG_START) {\\n itemLen = byte0 - STRING_SHORT_START + 1;\\n } else if (byte0 < LIST_SHORT_START) {\\n assembly {\\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\\n memPtr := add(memPtr, 1) // skip over the first byte\\n\\n /* 32 byte word size */\\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\\n itemLen := add(dataLen, add(byteLen, 1))\\n }\\n } else if (byte0 < LIST_LONG_START) {\\n itemLen = byte0 - LIST_SHORT_START + 1;\\n } else {\\n assembly {\\n let byteLen := sub(byte0, 0xf7)\\n memPtr := add(memPtr, 1)\\n\\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\\n itemLen := add(dataLen, add(byteLen, 1))\\n }\\n }\\n\\n return itemLen;\\n }\\n\\n // @return number of bytes until the data\\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\\n uint256 byte0;\\n assembly {\\n byte0 := byte(0, mload(memPtr))\\n }\\n\\n if (byte0 < STRING_SHORT_START) {\\n return 0;\\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\\n return 1;\\n } else if (byte0 < LIST_SHORT_START) {\\n // being explicit\\n return byte0 - (STRING_LONG_START - 1) + 1;\\n } else {\\n return byte0 - (LIST_LONG_START - 1) + 1;\\n }\\n }\\n\\n /*\\n * @param src Pointer to source\\n * @param dest Pointer to destination\\n * @param len Amount of memory to copy from the source\\n */\\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\\n if (len == 0) return;\\n\\n // copy as many word sizes as possible\\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\\n assembly {\\n mstore(dest, mload(src))\\n }\\n\\n src += WORD_SIZE;\\n dest += WORD_SIZE;\\n }\\n\\n if (len > 0) {\\n // left over bytes. Mask is used to remove unwanted bytes from the word\\n uint256 mask = 256**(WORD_SIZE - len) - 1;\\n assembly {\\n let srcpart := and(mload(src), not(mask)) // zero out src\\n let destpart := and(mload(dest), mask) // retrieve the bytes\\n mstore(dest, or(destpart, srcpart))\\n }\\n }\\n }\\n}\\n\",\"keccak256\":\"0x3a44f2de3c752fa4f926f3fd4cad8338dab742484150c0d7d2f785409ed8db4d\",\"license\":\"Apache-2.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b506158ad80620000216000396000f3fe60806040526004361061010d5760003560e01c80639e0f4f4511610095578063d3596e7f11610064578063d3596e7f14610385578063d40ec066146103b0578063e2411625146103d9578063ea42418b14610402578063f77c47911461042d5761010e565b80639e0f4f45146102db578063adb8b6d614610306578063b72a654014610331578063cf1b037c1461035c5761010e565b806350723553116100dc57806350723553146101e057806357e3c1b51461021d57806370c905a51461025a5780637e48532c146102855780639829ba42146102b05761010e565b80630de8cb93146101105780631d148b8d1461014d5780632e0f26251461018a5780633eb84396146101b55761010e565b5b005b34801561011c57600080fd5b5061013760048036038101906101329190613b69565b610458565b6040516101449190613c88565b60405180910390f35b34801561015957600080fd5b50610174600480360381019061016f9190613d4b565b61053f565b6040516101819190613c88565b60405180910390f35b34801561019657600080fd5b5061019f6106b0565b6040516101ac9190613db0565b60405180910390f35b3480156101c157600080fd5b506101ca6106b5565b6040516101d79190613dda565b60405180910390f35b3480156101ec57600080fd5b5061020760048036038101906102029190613df5565b6106ba565b6040516102149190613dda565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f9190613e9c565b610746565b6040516102519190613c88565b60405180910390f35b34801561026657600080fd5b5061026f6108b4565b60405161027c9190613f1e565b60405180910390f35b34801561029157600080fd5b5061029a6108d0565b6040516102a79190613c88565b60405180910390f35b3480156102bc57600080fd5b506102c5610a0d565b6040516102d29190613f1e565b60405180910390f35b3480156102e757600080fd5b506102f0610a46565b6040516102fd9190613f1e565b60405180910390f35b34801561031257600080fd5b5061031b610a62565b6040516103289190613f1e565b60405180910390f35b34801561033d57600080fd5b50610346610a9b565b6040516103539190613f1e565b60405180910390f35b34801561036857600080fd5b50610383600480360381019061037e9190613e9c565b610ab7565b005b34801561039157600080fd5b5061039a610be4565b6040516103a79190613f8d565b60405180910390f35b3480156103bc57600080fd5b506103d760048036038101906103d29190613fa8565b610bf7565b005b3480156103e557600080fd5b5061040060048036038101906103fb9190614030565b610c34565b005b34801561040e57600080fd5b50610417610d0a565b604051610424919061407f565b60405180910390f35b34801561043957600080fd5b50610442610d30565b60405161044f919061407f565b60405180910390f35b60606104a0610465610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b60006104ab876106ba565b90506104bb878288888888610e64565b63d40ec06660e01b87826040516024016104d692919061409a565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505095945050505050565b6060600061054c83610e9d565b60405160200161055c91906141c4565b60405160208183030381529060405290506105756138b7565b6040518060400160405280600481526020017f504f5354000000000000000000000000000000000000000000000000000000008152508160200181905250818160600181905250600167ffffffffffffffff8111156105d7576105d6613990565b5b60405190808252806020026020018201604052801561060a57816020015b60608152602001906001900390816105f55790505b5081604001819052506040518060400160405280601e81526020017f436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e00008152508160400151600081518110610661576106606141f1565b5b602002602001018190525060008160800190151590811515815250506040518060600160405280603c815260200161583c603c913981600001819052506106a781610ec3565b92505050919050565b600481565b600581565b6000806106c683610f7c565b905060006106d382611121565b905060006107276107226040518060400160405280600781526020017f22707269636522000000000000000000000000000000000000000000000000008152508461114d90919063ffffffff16565b6111d0565b905061073c610735826111f2565b60046112bf565b9350505050919050565b606061078e610753610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461081f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108169061426c565b60405180910390fd5b600061082a83611486565b90506108358161053f565b5063cf1b037c60e01b8360405160240161084f919061407f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050915050919050565b60405180606001604052806022815260200161581a6022913981565b60606109186108dd610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b61096560008054906101000a900460ff16156040518060400160405280601381526020017f416c726561647920696e697469616c697a656400000000000000000000000000815250610e1e565b60006109716000611623565b9050600061097e8261171a565b9050600061098b83611786565b905063e241162560e01b81836040516024016109a892919061428c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050935050505090565b6040518060400160405280601281526020017f6f7261636c653a76303a706b736563726574000000000000000000000000000081525081565b6040518060600160405280603c815260200161583c603c913981565b6040518060400160405280600381526020017f307835000000000000000000000000000000000000000000000000000000000081525081565b6040518060600160405280603b81526020016157df603b913981565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610b615750600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610ba0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b979061426c565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060019054906101000a900460801b81565b7ff61f2fd6ab65716facd3516c91d806d98dffa9670f127beac522f8cacfd1d8df8282604051610c2892919061409a565b60405180910390a15050565b610c8160008054906101000a900460ff16156040518060400160405280601381526020017f416c726561647920696e697469616c697a656400000000000000000000000000815250610e1e565b81600060016101000a8154816fffffffffffffffffffffffffffffffff021916908360801c021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016000806101000a81548160ff0219169083151502179055505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000634201000073ffffffffffffffffffffffffffffffffffffffff16604051610d82906142e6565b600060405180830381855afa9150503d8060008114610dbd576040519150601f19603f3d011682016040523d82523d6000602084013e610dc2565b606091505b509150915081610e0f576342010000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401610e069291906142fb565b60405180910390fd5b80516020820151935050505090565b81610e6057806040517f0c25cd98000000000000000000000000000000000000000000000000000000008152600401610e579190613f1e565b60405180910390fd5b5050565b6000610e7287878787611962565b90508115610e8957610e848184611b2b565b610e94565b610e928161053f565b505b50505050505050565b6060610ea882611b42565b90506002815101613078825260028203915080825250919050565b6060600080634320000273ffffffffffffffffffffffffffffffffffffffff1684604051602001610ef4919061451b565b604051602081830303815290604052604051610f10919061456e565b600060405180830381855afa9150503d8060008114610f4b576040519150601f19603f3d011682016040523d82523d6000602084013e610f50565b606091505b5091509150610f5f8282610e1e565b80806020019051810190610f7391906145f5565b92505050919050565b60606000600167ffffffffffffffff811115610f9b57610f9a613990565b5b604051908082528060200260200182016040528015610fce57816020015b6060815260200190600190039081610fb95790505b5090506040518060400160405280601e81526020017f436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e00008152508160008151811061101b5761101a6141f1565b5b602002602001018190525060006040518060a001604052806040518060600160405280603b81526020016157df603b91398660405160200161105e92919061463e565b60405160208183030381529060405281526020016040518060400160405280600381526020017f47455400000000000000000000000000000000000000000000000000000000008152508152602001838152602001600067ffffffffffffffff8111156110ce576110cd613990565b5b6040519080825280601f01601f1916602001820160405280156111005781602001600182028036833780820191505090505b50815260200160001515815250905061111881610ec3565b92505050919050565b6111296138e8565b80604052600061114261113b84611bb0565b60ff611bba565b905080915050919050565b6111556138e8565b80604052606090506111668361247e565b156111ca57600082805190602001209050600061118285612495565b9050600060058251901b90505b600081146111c657808201519550602081039050826111ad876124b7565b80519060200120036111c1578593506111c6565b61118f565b5050505b92915050565b606060006111e76111e0846124e9565b6000611bba565b905080915050919050565b60606000829050600281511161123d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611234906146ae565b60405180910390fd5b60006002825161124d91906146fd565b905060008167ffffffffffffffff81111561126b5761126a613990565b5b6040519080825280601f01601f19166020018201604052801561129d5781602001600182028036833780820191505090505b5090506021830160208201845182518252848452505050809350505050919050565b600080839050600080600090505b825181101561133b57602e60f81b8382815181106112ee576112ed6141f1565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036113285780915061133b565b808061133390614731565b9150506112cd565b5060008060006001905060008490505b60008111156113ca578160308760018461136591906146fd565b81518110611376576113756141f1565b5b602001015160f81c60f81b60f81c61138e9190614779565b60ff1661139b91906147ad565b846113a69190614807565b9350600a826113b591906147ad565b915080806113c29061485d565b91505061134b565b506001905060008760ff16856113e09190614807565b90505b8481111561145557816030878381518110611401576114006141f1565b5b602001015160f81c60f81b60f81c6114199190614779565b60ff1661142691906147ad565b836114319190614807565b9250600a8261144091906147ad565b9150808061144d9061485d565b9150506113e3565b508187600a61146491906149b9565b8461146f91906147ad565b6114799190614807565b9550505050505092915050565b606060006040518061014001604052808473ffffffffffffffffffffffffffffffffffffffff168152602001620186a0815260200164174876e800815260200160008152602001600081526020016040516024016040516020818303038152906040527f1aa3a008000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508152602001600581526020017f111111111111111111111111111111111111111111111111111111111111111181526020017f11111111111111111111111111111111111111111111111111111111111111118152602001601b67ffffffffffffffff16815250905060006115cb826124f3565b905060006115d76127a4565b9050611619826040518060400160405280600381526020017f3078350000000000000000000000000000000000000000000000000000000000815250836127ff565b9350505050919050565b6060600080635320000373ffffffffffffffffffffffffffffffffffffffff16846040516020016116549190614a7b565b604051602081830303815290604052604051611670919061456e565b600060405180830381855afa9150503d80600081146116ab576040519150601f19603f3d011682016040523d82523d6000602084013e6116b0565b606091505b5091509150816116fd576353200003816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016116f49291906142fb565b60405180910390fd5b808060200190518101906117119190614b06565b92505050919050565b60008060405160200161172c90614b9b565b60405160208183030381529060405280519060200120905060006117718260405160200161175a9190614be6565b6040516020818303038152906040526000866128fc565b905061177d8282612a0a565b92505050919050565b600080600367ffffffffffffffff8111156117a4576117a3613990565b5b6040519080825280602002602001820160405280156117d25781602001602082028036833780820191505090505b50905030816000815181106117ea576117e96141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505063420300018160018151811061183d5761183c6141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506342020001816002815181106118905761188f6141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600061190e600083846040518060400160405280601281526020017f6f7261636c653a76303a706b7365637265740000000000000000000000000000815250612a79565b905061195481600001516040518060400160405280601281526020017f6f7261636c653a76303a706b736563726574000000000000000000000000000081525086612b7f565b806000015192505050919050565b60606000604051806101400160405280600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001620186a081526020018481526020016000815260200185815260200187876040516024016119df92919061409a565b6040516020818303038152906040527f4a432a46000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508152602001600581526020017f111111111111111111111111111111111111111111111111111111111111111181526020017f11111111111111111111111111111111111111111111111111111111111111118152602001601b67ffffffffffffffff1681525090506000611ad0826124f3565b90506000611adc6127a4565b9050611b1e826040518060400160405280600381526020017f3078350000000000000000000000000000000000000000000000000000000000815250836127ff565b9350505050949350505050565b611b3482612c62565b611b3e8282612d4d565b5050565b60608151600260405101915080810182526f30313233343536373839616263646566600f52602082018184015b808514611b9d57600185019450600f855116516001830153600f855160041c16518253600282019150611b6f565b6000825260208201604052505050919050565b6000819050919050565b60006123c6565b63101827966000526004601cfd5b6000815160001a9050919050565b60008190505b600115611c0d576001640100002600611bfb83611bcf565b1c1615611c0e57600181019050611be3565b5b92915050565b600063ffffffff84113d3d3e83831b8263ffffffff851b19161790509392505050565b600081831c63ffffffff16905092915050565b60006040519050611c6f8486036078611c6a602086018803605888611c14565b611c14565b925085831781526020810160405295945050505050565b600080611c97846018600051611c14565b611ca18787611bdd565b9150868210611cb05750611e03565b611cb982611bcf565b600115611df45760228103611ced5782611cd589858589612045565b9350611ce560048583868a611c4a565b945050611df4565b605b8103611d0a57611d0188848488611e0c565b93509350611df4565b607b8103611d2757611d1e88848488611ee4565b93509350611df4565b6001611ff9602d1b821c1615611d4c57611d4388848488612154565b93509350611df4565b876004840111611daf5782835160e01c63747275658103611d8457600485019450611d7b60058684878b611c4a565b95505050611df4565b636e756c6c8103611dac57600485019450611da360068684878b611c4a565b95505050611df4565b50505b876005840111611deb5782835160d81c6466616c73658103611de857600585019450611ddf60058684878b611c4a565b95505050611df4565b50505b611df3611bc1565b5b50611dff8783611bdd565b9150505b94509492505050565b60008060006001860191505b600115611eb657868210611e2f57611e2e611bc1565b5b82611e5257611e3e8783611bdd565b9150605d611e4b83611bcf565b0315611eb6575b611e5e87838587611c86565b925092508215611ea757611e788160988551604017611c14565b8352600181019050611e8982611bcf565b605d8103611e975750611eb6565b602c8103611ea55750611eab565b505b8691505b600182019150611e18565b600182019150611ec883603887611c14565b9450611ed8600183888888611c4a565b92505094509492505050565b6000806001850190505b600115611fd757858110611f0557611f04611bc1565b5b81611f2857611f148682611bdd565b9050607d611f2182611bcf565b0315611fd7575b611f328682611bdd565b905080611f4187838587612045565b611f4b8882611bdd565b9250603a611f5884611bcf565b03611fc657611f6c88600185018688611c86565b935093508315611fc557611f986020860183036098611f9385850360b88951608017611c14565b611c14565b8452611fa383611bcf565b607d8103611fb357505050611fd7565b602c8103611fc357505050611fcc565b505b5b87925050505b600181019050611eee565b600181019050611fe982603886611c14565b9350611ff9600282878787611c4a565b915094509492505050565b6001667e0000007e03ff603061201b858501611bcf565b031c1661202b5761202a611bc1565b5b60058214612041576120406001830182612004565b5b5050565b600084841061205757612056611bc1565b5b6001840190505b6001156120f05761206e81611bcf565b6022810361207c57506120f0565b605c811461209057600182019150506120eb565b61209c60018301611bcf565b905060016a0510110400000000002001602283031c16156120c357600282019150506120eb565b607581036120e2576120d6600283612004565b600682019150506120eb565b859150506120f0565b61205e565b848110612100576120ff611bc1565b5b600181019050949350505050565b60008190505b60011561213a57600a603061212883611bcf565b03101561213a57600181019050612114565b80821484161561214d5761214c611bc1565b5b9392505050565b600080849050602d61216582611bcf565b03612171576001810190505b600a603061217e83611bcf565b031061218d5761218c611bc1565b5b61219681611bcf565b600182019150603081146121b3576121b06000888461210e565b91505b602e6121be83611bcf565b036121d5576121d26001886001850161210e565b91505b815160658160001a60201703612204576122016001896001860162010001600e8660011a031a0161210e565b92505b612212600384898989611c4a565b9350505094509492505050565b600060405190508282019150601f1980601f8601165b60011561224f578084015181840152818101905080612235575b50848252600085602084010152846040830101604052509392505050565b6000606090508151600281600716116123595782158115176123595760208116156122a45761229d603882611c37565b9150612359565b6040519150602082016122b8603883611c37565b5b80156122ed5780825280516122cf601882611c37565b6122db87601884611c14565b835280925060208401935050506122b9565b50601f1983820381018060051c85528260405261230c85603886611c14565b93508360201786526040811061235557602085018186015b60011561235257815181518352808252848201915060208301925081831061234c5750612352565b50612324565b50505b5050505b50919050565b600060609050815180158315171561237757506123be565b6123818482611c37565b91508086166123bc5761239560d882611c37565b6123a96123a28784611c37565b848361221f565b92506123b6838684611c14565b87178452505b505b949350505050565b816000811461243f5760018114612455576003811461246b576020840184518101808214612424576123f781611bcf565b6022825361240b8760d8602260f81b611c14565b60005261241b828460008a611c86565b93509450808253505b8315818310171561243857612437611bc1565b5b5050612477565b61244e6010607860588761235f565b9150612477565b612464600860b860988761235f565b9150612477565b6124748461226d565b91505b5092915050565b6000600260ff166007836000015116149050919050565b606060006124ac6124a5846124e9565b6003611bba565b905080915050919050565b606060006080836000015116146124e45760006124dd6124d6846124e9565b6001611bba565b9050809150505b919050565b6000819050919050565b60606000600967ffffffffffffffff81111561251257612511613990565b5b60405190808252806020026020018201604052801561254557816020015b60608152602001906001900390816125305790505b5090506125558360800151612eb3565b81600081518110612569576125686141f1565b5b60200260200101819052506125818360400151612eb3565b81600181518110612595576125946141f1565b5b60200260200101819052506125ad8360200151612eb3565b816002815181106125c1576125c06141f1565b5b6020026020010181905250600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036126405761261c60405180602001604052806000815250612ecd565b816003815181106126305761262f6141f1565b5b602002602001018190525061266d565b61264d8360000151612f4b565b81600381518110612661576126606141f1565b5b60200260200101819052505b61267a8360600151612eb3565b8160048151811061268e5761268d6141f1565b5b60200260200101819052506126a68360a00151612ecd565b816005815181106126ba576126b96141f1565b5b60200260200101819052506126dd83610120015167ffffffffffffffff16612eb3565b816006815181106126f1576126f06141f1565b5b60200260200101819052506127288360e001516040516020016127149190614be6565b604051602081830303815290604052612ecd565b8160078151811061273c5761273b6141f1565b5b60200260200101819052506127748361010001516040516020016127609190614be6565b604051602081830303815290604052612ecd565b81600881518110612788576127876141f1565b5b602002602001018190525061279c81612f7c565b915050919050565b606060006127f6600060019054906101000a900460801b6040518060400160405280601281526020017f6f7261636c653a76303a706b7365637265740000000000000000000000000000815250612fc0565b90508091505090565b6060600080634010000173ffffffffffffffffffffffffffffffffffffffff1686868660405160200161283493929190614c01565b604051602081830303815290604052604051612850919061456e565b600060405180830381855afa9150503d806000811461288b576040519150601f19603f3d011682016040523d82523d6000602084013e612890565b606091505b5091509150816128dd576340100001816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016128d49291906142fb565b60405180910390fd5b808060200190518101906128f191906145f5565b925050509392505050565b6060612906610d56565b61290f57600080fd5b600080634010000373ffffffffffffffffffffffffffffffffffffffff1686868660405160200161294293929190614c4d565b60405160208183030381529060405260405161295e919061456e565b600060405180830381855afa9150503d8060008114612999576040519150601f19603f3d011682016040523d82523d6000602084013e61299e565b606091505b5091509150816129eb576340100003816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016129e29291906142fb565b60405180910390fd5b808060200190518101906129ff91906145f5565b925050509392505050565b600080600080612a19856130a7565b92509250925060018682858560405160008152602001604052604051612a429493929190614ca1565b6020604051602081039080840390855afa158015612a64573d6000803e3d6000fd5b50505060206040510351935050505092915050565b612a816138fb565b600080634203000073ffffffffffffffffffffffffffffffffffffffff1687878787604051602001612ab69493929190614db3565b604051602081830303815290604052604051612ad2919061456e565b600060405180830381855afa9150503d8060008114612b0d576040519150601f19603f3d011682016040523d82523d6000602084013e612b12565b606091505b509150915081612b5f576342030000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401612b569291906142fb565b60405180910390fd5b80806020019051810190612b739190615012565b92505050949350505050565b600080634202000073ffffffffffffffffffffffffffffffffffffffff16858585604051602001612bb29392919061505b565b604051602081830303815290604052604051612bce919061456e565b600060405180830381855afa9150503d8060008114612c09576040519150601f19603f3d011682016040523d82523d6000602084013e612c0e565b606091505b509150915081612c5b576342020000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401612c529291906142fb565b60405180910390fd5b5050505050565b6000612c6d82610e9d565b604051602001612c7d9190615138565b6040516020818303038152906040529050600080634210000073ffffffffffffffffffffffffffffffffffffffff1683604051602001612cbd9190613c88565b604051602081830303815290604052604051612cd9919061456e565b600060405180830381855afa9150503d8060008114612d14576040519150601f19603f3d011682016040523d82523d6000602084013e612d19565b606091505b5091509150612d478282604051602001612d3391906151b1565b604051602081830303815290604052610e1e565b50505050565b6000600167ffffffffffffffff811115612d6a57612d69613990565b5b604051908082528060200260200182016040528015612d9d57816020015b6060815260200190600190039081612d885790505b5090508281600081518110612db557612db46141f1565b5b60200260200101819052506000612dd6828467ffffffffffffffff1661312b565b9050600080634300000173ffffffffffffffffffffffffffffffffffffffff1660405180606001604052806022815260200161581a6022913984604051602001612e2192919061521f565b604051602081830303815290604052604051612e3d919061456e565b600060405180830381855afa9150503d8060008114612e78576040519150601f19603f3d011682016040523d82523d6000602084013e612e7d565b606091505b5091509150612eab8282604051602001612e9791906152b5565b604051602081830303815290604052610e1e565b505050505050565b6060612ec6612ec18361324a565b612ecd565b9050919050565b60608060018351148015612f055750608083600081518110612ef257612ef16141f1565b5b602001015160f81c60f81b60f81c60ff16105b15612f1257829050612f42565b612f1e835160806133cd565b83604051602001612f309291906152d7565b60405160208183030381529060405290505b80915050919050565b6060612f7582604051602001612f619190615343565b604051602081830303815290604052612ecd565b9050919050565b60606000612f8983613619565b9050612f97815160c06133cd565b81604051602001612fa99291906152d7565b604051602081830303815290604052915050919050565b6060600080634202000173ffffffffffffffffffffffffffffffffffffffff168585604051602001612ff392919061535e565b60405160208183030381529060405260405161300f919061456e565b600060405180830381855afa9150503d806000811461304a576040519150601f19603f3d011682016040523d82523d6000602084013e61304f565b606091505b50915091508161309c576342020001816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016130939291906142fb565b60405180910390fd5b809250505092915050565b600080600060418451146130f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130e7906153da565b60405180910390fd5b6020840151925060408401519150606084015160001a9050601b8160ff16101561312457601b8161312191906153fa565b90505b9193909250565b60606000613138836137ab565b60405160200161314891906154c9565b604051602081830303815290604052905060005b845181101561321d578161318986838151811061317c5761317b6141f1565b5b6020026020010151610e9d565b60405160200161319a929190615542565b6040516020818303038152906040529150600185516131b991906146fd565b8110156131e757816040516020016131d191906155c8565b604051602081830303815290604052915061320a565b816040516020016131f89190615636565b60405160208183030381529060405291505b808061321590614731565b91505061315c565b508060405160200161322f91906156a4565b60405160208183030381529060405290508091505092915050565b606060008260405160200161325f91906156e7565b604051602081830303815290604052905060005b60208110156132d957600060f81b828281518110613294576132936141f1565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036132d95780806132d190614731565b915050613273565b60008160206132e891906146fd565b67ffffffffffffffff81111561330157613300613990565b5b6040519080825280601f01601f1916602001820160405280156133335781602001600182028036833780820191505090505b50905060005b81518110156133c15783838061334e90614731565b945081518110613361576133606141f1565b5b602001015160f81c60f81b82828151811061337f5761337e6141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806133b990614731565b915050613339565b50809350505050919050565b606080603884101561348057600167ffffffffffffffff8111156133f4576133f3613990565b5b6040519080825280601f01601f1916602001820160405280156134265781602001600182028036833780820191505090505b509050828461343591906153fa565b60f81b8160008151811061344c5761344b6141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061360f565b600080600190505b600081876134969190615731565b146134be5781806134a690614731565b925050610100816134b791906147ad565b9050613488565b6001826134cb9190614807565b67ffffffffffffffff8111156134e4576134e3613990565b5b6040519080825280601f01601f1916602001820160405280156135165781602001600182028036833780820191505090505b5092506037858361352791906153fa565b61353191906153fa565b60f81b83600081518110613548576135476141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b81811161360c57610100818361359291906146fd565b61010061359f9190615762565b876135aa9190615731565b6135b491906157ad565b60f81b8382815181106135ca576135c96141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350808061360490614731565b91505061357c565b50505b8091505092915050565b6060600082510361367957600067ffffffffffffffff81111561363f5761363e613990565b5b6040519080825280601f01601f1916602001820160405280156136715781602001600182028036833780820191505090505b5090506137a6565b600080600090505b83518110156136c65783818151811061369d5761369c6141f1565b5b602002602001015151826136b19190614807565b915080806136be90614731565b915050613681565b60008267ffffffffffffffff8111156136e2576136e1613990565b5b6040519080825280601f01601f1916602001820160405280156137145781602001600182028036833780820191505090505b5090506000602082019050600092505b855183101561379e576000868481518110613742576137416141f1565b5b602002602001015190506000602082019050613760838284516137d1565b878581518110613773576137726141f1565b5b602002602001015151836137879190614807565b92505050828061379690614731565b935050613724565b819450505050505b919050565b60606137b682613847565b90506002815101613078825260028203915080825250919050565b6000839050600083905060008390505b6020811061381f57815183526020836137fa9190614807565b92506020826138099190614807565b915060208161381891906146fd565b90506137e1565b60006001826020036101000a0390508019835116818551168181178652505050505050505050565b606060806040510190506020810160405260008152806f30313233343536373839616263646566600f52600119835b6001156138a2578184019350600f8116516001850153600f8160041c165184538060081c905080613876575b50828203602084039350808452505050919050565b6040518060a00160405280606081526020016060815260200160608152602001606081526020016000151581525090565b6040518060200160405280600081525090565b6040518060c0016040528060006fffffffffffffffffffffffffffffffff1916815260200160006fffffffffffffffffffffffffffffffff19168152602001600067ffffffffffffffff1681526020016060815260200160608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6139c88261397f565b810181811067ffffffffffffffff821117156139e7576139e6613990565b5b80604052505050565b60006139fa613961565b9050613a0682826139bf565b919050565b600067ffffffffffffffff821115613a2657613a25613990565b5b613a2f8261397f565b9050602081019050919050565b82818337600083830152505050565b6000613a5e613a5984613a0b565b6139f0565b905082815260208101848484011115613a7a57613a7961397a565b5b613a85848285613a3c565b509392505050565b600082601f830112613aa257613aa1613975565b5b8135613ab2848260208601613a4b565b91505092915050565b6000819050919050565b613ace81613abb565b8114613ad957600080fd5b50565b600081359050613aeb81613ac5565b92915050565b600067ffffffffffffffff82169050919050565b613b0e81613af1565b8114613b1957600080fd5b50565b600081359050613b2b81613b05565b92915050565b60008115159050919050565b613b4681613b31565b8114613b5157600080fd5b50565b600081359050613b6381613b3d565b92915050565b600080600080600060a08688031215613b8557613b8461396b565b5b600086013567ffffffffffffffff811115613ba357613ba2613970565b5b613baf88828901613a8d565b9550506020613bc088828901613adc565b9450506040613bd188828901613adc565b9350506060613be288828901613b1c565b9250506080613bf388828901613b54565b9150509295509295909350565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c3a578082015181840152602081019050613c1f565b83811115613c49576000848401525b50505050565b6000613c5a82613c00565b613c648185613c0b565b9350613c74818560208601613c1c565b613c7d8161397f565b840191505092915050565b60006020820190508181036000830152613ca28184613c4f565b905092915050565b600067ffffffffffffffff821115613cc557613cc4613990565b5b613cce8261397f565b9050602081019050919050565b6000613cee613ce984613caa565b6139f0565b905082815260208101848484011115613d0a57613d0961397a565b5b613d15848285613a3c565b509392505050565b600082601f830112613d3257613d31613975565b5b8135613d42848260208601613cdb565b91505092915050565b600060208284031215613d6157613d6061396b565b5b600082013567ffffffffffffffff811115613d7f57613d7e613970565b5b613d8b84828501613d1d565b91505092915050565b600060ff82169050919050565b613daa81613d94565b82525050565b6000602082019050613dc56000830184613da1565b92915050565b613dd481613abb565b82525050565b6000602082019050613def6000830184613dcb565b92915050565b600060208284031215613e0b57613e0a61396b565b5b600082013567ffffffffffffffff811115613e2957613e28613970565b5b613e3584828501613a8d565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613e6982613e3e565b9050919050565b613e7981613e5e565b8114613e8457600080fd5b50565b600081359050613e9681613e70565b92915050565b600060208284031215613eb257613eb161396b565b5b6000613ec084828501613e87565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613ef082613ec9565b613efa8185613ed4565b9350613f0a818560208601613c1c565b613f138161397f565b840191505092915050565b60006020820190508181036000830152613f388184613ee5565b905092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b6000613f7782613f40565b9050919050565b613f8781613f6c565b82525050565b6000602082019050613fa26000830184613f7e565b92915050565b60008060408385031215613fbf57613fbe61396b565b5b600083013567ffffffffffffffff811115613fdd57613fdc613970565b5b613fe985828601613a8d565b9250506020613ffa85828601613adc565b9150509250929050565b61400d81613f40565b811461401857600080fd5b50565b60008135905061402a81614004565b92915050565b600080604083850312156140475761404661396b565b5b60006140558582860161401b565b925050602061406685828601613e87565b9150509250929050565b61407981613e5e565b82525050565b60006020820190506140946000830184614070565b92915050565b600060408201905081810360008301526140b48185613ee5565b90506140c36020830184613dcb565b9392505050565b600081905092915050565b7f7b226a736f6e727063223a22322e30222c226d6574686f64223a226574685f7360008201527f656e645261775472616e73616374696f6e222c22706172616d73223a5b220000602082015250565b6000614131603e836140ca565b915061413c826140d5565b603e82019050919050565b600061415282613ec9565b61415c81856140ca565b935061416c818560208601613c1c565b80840191505092915050565b7f225d2c226964223a317d00000000000000000000000000000000000000000000600082015250565b60006141ae600a836140ca565b91506141b982614178565b600a82019050919050565b60006141cf82614124565b91506141db8284614147565b91506141e6826141a1565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f416c726561647920726567697374657265640000000000000000000000000000600082015250565b6000614256601283613ed4565b915061426182614220565b602082019050919050565b6000602082019050818103600083015261428581614249565b9050919050565b60006040820190506142a16000830185613f7e565b6142ae6020830184614070565b9392505050565b600081905092915050565b50565b60006142d06000836142b5565b91506142db826142c0565b600082019050919050565b60006142f1826142c3565b9150819050919050565b60006040820190506143106000830185614070565b81810360208301526143228184613c4f565b90509392505050565b600082825260208201905092915050565b600061434782613ec9565b614351818561432b565b9350614361818560208601613c1c565b61436a8161397f565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006143ad838361433c565b905092915050565b6000602082019050919050565b60006143cd82614375565b6143d78185614380565b9350836020820285016143e985614391565b8060005b85811015614425578484038952815161440685826143a1565b9450614411836143b5565b925060208a019950506001810190506143ed565b50829750879550505050505092915050565b600082825260208201905092915050565b600061445382613c00565b61445d8185614437565b935061446d818560208601613c1c565b6144768161397f565b840191505092915050565b61448a81613b31565b82525050565b600060a08301600083015184820360008601526144ad828261433c565b915050602083015184820360208601526144c7828261433c565b915050604083015184820360408601526144e182826143c2565b915050606083015184820360608601526144fb8282614448565b91505060808301516145106080860182614481565b508091505092915050565b600060208201905081810360008301526145358184614490565b905092915050565b600061454882613c00565b61455281856142b5565b9350614562818560208601613c1c565b80840191505092915050565b600061457a828461453d565b915081905092915050565b600061459861459384613caa565b6139f0565b9050828152602081018484840111156145b4576145b361397a565b5b6145bf848285613c1c565b509392505050565b600082601f8301126145dc576145db613975565b5b81516145ec848260208601614585565b91505092915050565b60006020828403121561460b5761460a61396b565b5b600082015167ffffffffffffffff81111561462957614628613970565b5b614635848285016145c7565b91505092915050565b600061464a8285614147565b91506146568284614147565b91508190509392505050565b7f496e70757420746f6f2073686f72740000000000000000000000000000000000600082015250565b6000614698600f83613ed4565b91506146a382614662565b602082019050919050565b600060208201905081810360008301526146c78161468b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061470882613abb565b915061471383613abb565b925082821015614726576147256146ce565b5b828203905092915050565b600061473c82613abb565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361476e5761476d6146ce565b5b600182019050919050565b600061478482613d94565b915061478f83613d94565b9250828210156147a2576147a16146ce565b5b828203905092915050565b60006147b882613abb565b91506147c383613abb565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156147fc576147fb6146ce565b5b828202905092915050565b600061481282613abb565b915061481d83613abb565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614852576148516146ce565b5b828201905092915050565b600061486882613abb565b91506000820361487b5761487a6146ce565b5b600182039050919050565b60008160011c9050919050565b6000808291508390505b60018511156148dd578086048111156148b9576148b86146ce565b5b60018516156148c85780820291505b80810290506148d685614886565b945061489d565b94509492505050565b6000826148f657600190506149b2565b8161490457600090506149b2565b816001811461491a576002811461492457614953565b60019150506149b2565b60ff841115614936576149356146ce565b5b8360020a91508482111561494d5761494c6146ce565b5b506149b2565b5060208310610133831016604e8410600b84101617156149885782820a905083811115614983576149826146ce565b5b6149b2565b6149958484846001614893565b925090508184048111156149ac576149ab6146ce565b5b81810290505b9392505050565b60006149c482613abb565b91506149cf83613d94565b92506149fc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846148e6565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110614a4457614a43614a04565b5b50565b6000819050614a5582614a33565b919050565b6000614a6582614a47565b9050919050565b614a7581614a5a565b82525050565b6000602082019050614a906000830184614a6c565b92915050565b6000614aa9614aa484613a0b565b6139f0565b905082815260208101848484011115614ac557614ac461397a565b5b614ad0848285613c1c565b509392505050565b600082601f830112614aed57614aec613975565b5b8151614afd848260208601614a96565b91505092915050565b600060208284031215614b1c57614b1b61396b565b5b600082015167ffffffffffffffff811115614b3a57614b39613970565b5b614b4684828501614ad8565b91505092915050565b7f796f000000000000000000000000000000000000000000000000000000000000600082015250565b6000614b85600283613ed4565b9150614b9082614b4f565b602082019050919050565b60006020820190508181036000830152614bb481614b78565b9050919050565b6000819050919050565b6000819050919050565b614be0614bdb82614bbb565b614bc5565b82525050565b6000614bf28284614bcf565b60208201915081905092915050565b60006060820190508181036000830152614c1b8186613c4f565b90508181036020830152614c2f8185613ee5565b90508181036040830152614c438184613ee5565b9050949350505050565b60006060820190508181036000830152614c678186613c4f565b9050614c766020830185614a6c565b8181036040830152614c888184613ee5565b9050949350505050565b614c9b81614bbb565b82525050565b6000608082019050614cb66000830187614c92565b614cc36020830186613da1565b614cd06040830185614c92565b614cdd6060830184614c92565b95945050505050565b614cef81613af1565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614d2a81613e5e565b82525050565b6000614d3c8383614d21565b60208301905092915050565b6000602082019050919050565b6000614d6082614cf5565b614d6a8185614d00565b9350614d7583614d11565b8060005b83811015614da6578151614d8d8882614d30565b9750614d9883614d48565b925050600181019050614d79565b5085935050505092915050565b6000608082019050614dc86000830187614ce6565b8181036020830152614dda8186614d55565b90508181036040830152614dee8185614d55565b90508181036060830152614e028184613ee5565b905095945050505050565b600080fd5b600080fd5b600081519050614e2681614004565b92915050565b600081519050614e3b81613b05565b92915050565b600067ffffffffffffffff821115614e5c57614e5b613990565b5b602082029050602081019050919050565b600080fd5b600081519050614e8181613e70565b92915050565b6000614e9a614e9584614e41565b6139f0565b90508083825260208201905060208402830185811115614ebd57614ebc614e6d565b5b835b81811015614ee65780614ed28882614e72565b845260208401935050602081019050614ebf565b5050509392505050565b600082601f830112614f0557614f04613975565b5b8151614f15848260208601614e87565b91505092915050565b600060c08284031215614f3457614f33614e0d565b5b614f3e60c06139f0565b90506000614f4e84828501614e17565b6000830152506020614f6284828501614e17565b6020830152506040614f7684828501614e2c565b604083015250606082015167ffffffffffffffff811115614f9a57614f99614e12565b5b614fa684828501614ef0565b606083015250608082015167ffffffffffffffff811115614fca57614fc9614e12565b5b614fd684828501614ef0565b60808301525060a082015167ffffffffffffffff811115614ffa57614ff9614e12565b5b61500684828501614ad8565b60a08301525092915050565b6000602082840312156150285761502761396b565b5b600082015167ffffffffffffffff81111561504657615045613970565b5b61505284828501614f1e565b91505092915050565b60006060820190506150706000830186613f7e565b81810360208301526150828185613ee5565b905081810360408301526150968184613c4f565b9050949350505050565b7f7b22747873223a205b2200000000000000000000000000000000000000000000600082015250565b60006150d6600a836140ca565b91506150e1826150a0565b600a82019050919050565b7f225d7d0000000000000000000000000000000000000000000000000000000000600082015250565b60006151226003836140ca565b915061512d826150ec565b600382019050919050565b6000615143826150c9565b915061514f8284614147565b915061515a82615115565b915081905092915050565b7f42756e646c6553696d756c6174696f6e4661696c65643a200000000000000000600082015250565b600061519b6018836140ca565b91506151a682615165565b601882019050919050565b60006151bc8261518e565b91506151c88284614147565b915081905092915050565b7f6574685f73656e6442756e646c65000000000000000000000000000000000000600082015250565b6000615209600e83613ed4565b9150615214826151d3565b602082019050919050565b600060608201905081810360008301526152398185613ee5565b9050818103602083015261524c816151fc565b905081810360408301526152608184613c4f565b90509392505050565b7f42756e646c655375626d697373696f6e4661696c65643a200000000000000000600082015250565b600061529f6018836140ca565b91506152aa82615269565b601882019050919050565b60006152c082615292565b91506152cc8284614147565b915081905092915050565b60006152e3828561453d565b91506152ef828461453d565b91508190509392505050565b60008160601b9050919050565b6000615313826152fb565b9050919050565b600061532582615308565b9050919050565b61533d61533882613e5e565b61531a565b82525050565b600061534f828461532c565b60148201915081905092915050565b60006040820190506153736000830185613f7e565b81810360208301526153858184613ee5565b90509392505050565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b60006153c4601883613ed4565b91506153cf8261538e565b602082019050919050565b600060208201905081810360008301526153f3816153b7565b9050919050565b600061540582613d94565b915061541083613d94565b92508260ff03821115615426576154256146ce565b5b828201905092915050565b7f7b22626c6f636b4e756d626572223a2022000000000000000000000000000000600082015250565b60006154676011836140ca565b915061547282615431565b601182019050919050565b7f222c2022747873223a205b000000000000000000000000000000000000000000600082015250565b60006154b3600b836140ca565b91506154be8261547d565b600b82019050919050565b60006154d48261545a565b91506154e08284614147565b91506154eb826154a6565b915081905092915050565b7f2200000000000000000000000000000000000000000000000000000000000000600082015250565b600061552c6001836140ca565b9150615537826154f6565b600182019050919050565b600061554e828561453d565b91506155598261551f565b91506155658284614147565b91506155708261551f565b91508190509392505050565b7f2c00000000000000000000000000000000000000000000000000000000000000600082015250565b60006155b26001836140ca565b91506155bd8261557c565b600182019050919050565b60006155d4828461453d565b91506155df826155a5565b915081905092915050565b7f5d00000000000000000000000000000000000000000000000000000000000000600082015250565b60006156206001836140ca565b915061562b826155ea565b600182019050919050565b6000615642828461453d565b915061564d82615613565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061568e6001836140ca565b915061569982615658565b600182019050919050565b60006156b0828461453d565b91506156bb82615681565b915081905092915050565b6000819050919050565b6156e16156dc82613abb565b6156c6565b82525050565b60006156f382846156d0565b60208201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061573c82613abb565b915061574783613abb565b92508261575757615756615702565b5b828204905092915050565b600061576d82613abb565b915061577883613abb565b92506157a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846148e6565b905092915050565b60006157b882613abb565b91506157c383613abb565b9250826157d3576157d2615702565b5b82820690509291505056fe68747470733a2f2f646174612d6170692e62696e616e63652e766973696f6e2f6170692f76332f7469636b65722f70726963653f73796d626f6c3d68747470733a2f2f72656c61792d676f65726c692e666c617368626f74732e6e657468747470733a2f2f676f65726c692e696e667572612e696f2f76332f3961613364393562336263343430666138386561313265616134343536313631a264697066735822122094fa656988693296a6c71e7e78853503c2b9e7e490a74e0ff6a2f37e446ed22464736f6c634300080d0033", + "deployedBytecode": "0x60806040526004361061010d5760003560e01c80639e0f4f4511610095578063d3596e7f11610064578063d3596e7f14610385578063d40ec066146103b0578063e2411625146103d9578063ea42418b14610402578063f77c47911461042d5761010e565b80639e0f4f45146102db578063adb8b6d614610306578063b72a654014610331578063cf1b037c1461035c5761010e565b806350723553116100dc57806350723553146101e057806357e3c1b51461021d57806370c905a51461025a5780637e48532c146102855780639829ba42146102b05761010e565b80630de8cb93146101105780631d148b8d1461014d5780632e0f26251461018a5780633eb84396146101b55761010e565b5b005b34801561011c57600080fd5b5061013760048036038101906101329190613b69565b610458565b6040516101449190613c88565b60405180910390f35b34801561015957600080fd5b50610174600480360381019061016f9190613d4b565b61053f565b6040516101819190613c88565b60405180910390f35b34801561019657600080fd5b5061019f6106b0565b6040516101ac9190613db0565b60405180910390f35b3480156101c157600080fd5b506101ca6106b5565b6040516101d79190613dda565b60405180910390f35b3480156101ec57600080fd5b5061020760048036038101906102029190613df5565b6106ba565b6040516102149190613dda565b60405180910390f35b34801561022957600080fd5b50610244600480360381019061023f9190613e9c565b610746565b6040516102519190613c88565b60405180910390f35b34801561026657600080fd5b5061026f6108b4565b60405161027c9190613f1e565b60405180910390f35b34801561029157600080fd5b5061029a6108d0565b6040516102a79190613c88565b60405180910390f35b3480156102bc57600080fd5b506102c5610a0d565b6040516102d29190613f1e565b60405180910390f35b3480156102e757600080fd5b506102f0610a46565b6040516102fd9190613f1e565b60405180910390f35b34801561031257600080fd5b5061031b610a62565b6040516103289190613f1e565b60405180910390f35b34801561033d57600080fd5b50610346610a9b565b6040516103539190613f1e565b60405180910390f35b34801561036857600080fd5b50610383600480360381019061037e9190613e9c565b610ab7565b005b34801561039157600080fd5b5061039a610be4565b6040516103a79190613f8d565b60405180910390f35b3480156103bc57600080fd5b506103d760048036038101906103d29190613fa8565b610bf7565b005b3480156103e557600080fd5b5061040060048036038101906103fb9190614030565b610c34565b005b34801561040e57600080fd5b50610417610d0a565b604051610424919061407f565b60405180910390f35b34801561043957600080fd5b50610442610d30565b60405161044f919061407f565b60405180910390f35b60606104a0610465610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b60006104ab876106ba565b90506104bb878288888888610e64565b63d40ec06660e01b87826040516024016104d692919061409a565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505091505095945050505050565b6060600061054c83610e9d565b60405160200161055c91906141c4565b60405160208183030381529060405290506105756138b7565b6040518060400160405280600481526020017f504f5354000000000000000000000000000000000000000000000000000000008152508160200181905250818160600181905250600167ffffffffffffffff8111156105d7576105d6613990565b5b60405190808252806020026020018201604052801561060a57816020015b60608152602001906001900390816105f55790505b5081604001819052506040518060400160405280601e81526020017f436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e00008152508160400151600081518110610661576106606141f1565b5b602002602001018190525060008160800190151590811515815250506040518060600160405280603c815260200161583c603c913981600001819052506106a781610ec3565b92505050919050565b600481565b600581565b6000806106c683610f7c565b905060006106d382611121565b905060006107276107226040518060400160405280600781526020017f22707269636522000000000000000000000000000000000000000000000000008152508461114d90919063ffffffff16565b6111d0565b905061073c610735826111f2565b60046112bf565b9350505050919050565b606061078e610753610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461081f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108169061426c565b60405180910390fd5b600061082a83611486565b90506108358161053f565b5063cf1b037c60e01b8360405160240161084f919061407f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050915050919050565b60405180606001604052806022815260200161581a6022913981565b60606109186108dd610d56565b6040518060400160405280601081526020017f4e6f7420636f6e666964656e7469616c00000000000000000000000000000000815250610e1e565b61096560008054906101000a900460ff16156040518060400160405280601381526020017f416c726561647920696e697469616c697a656400000000000000000000000000815250610e1e565b60006109716000611623565b9050600061097e8261171a565b9050600061098b83611786565b905063e241162560e01b81836040516024016109a892919061428c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050935050505090565b6040518060400160405280601281526020017f6f7261636c653a76303a706b736563726574000000000000000000000000000081525081565b6040518060600160405280603c815260200161583c603c913981565b6040518060400160405280600381526020017f307835000000000000000000000000000000000000000000000000000000000081525081565b6040518060600160405280603b81526020016157df603b913981565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610b615750600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16145b610ba0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b979061426c565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600060019054906101000a900460801b81565b7ff61f2fd6ab65716facd3516c91d806d98dffa9670f127beac522f8cacfd1d8df8282604051610c2892919061409a565b60405180910390a15050565b610c8160008054906101000a900460ff16156040518060400160405280601381526020017f416c726561647920696e697469616c697a656400000000000000000000000000815250610e1e565b81600060016101000a8154816fffffffffffffffffffffffffffffffff021916908360801c021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016000806101000a81548160ff0219169083151502179055505050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000806000634201000073ffffffffffffffffffffffffffffffffffffffff16604051610d82906142e6565b600060405180830381855afa9150503d8060008114610dbd576040519150601f19603f3d011682016040523d82523d6000602084013e610dc2565b606091505b509150915081610e0f576342010000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401610e069291906142fb565b60405180910390fd5b80516020820151935050505090565b81610e6057806040517f0c25cd98000000000000000000000000000000000000000000000000000000008152600401610e579190613f1e565b60405180910390fd5b5050565b6000610e7287878787611962565b90508115610e8957610e848184611b2b565b610e94565b610e928161053f565b505b50505050505050565b6060610ea882611b42565b90506002815101613078825260028203915080825250919050565b6060600080634320000273ffffffffffffffffffffffffffffffffffffffff1684604051602001610ef4919061451b565b604051602081830303815290604052604051610f10919061456e565b600060405180830381855afa9150503d8060008114610f4b576040519150601f19603f3d011682016040523d82523d6000602084013e610f50565b606091505b5091509150610f5f8282610e1e565b80806020019051810190610f7391906145f5565b92505050919050565b60606000600167ffffffffffffffff811115610f9b57610f9a613990565b5b604051908082528060200260200182016040528015610fce57816020015b6060815260200190600190039081610fb95790505b5090506040518060400160405280601e81526020017f436f6e74656e742d547970653a206170706c69636174696f6e2f6a736f6e00008152508160008151811061101b5761101a6141f1565b5b602002602001018190525060006040518060a001604052806040518060600160405280603b81526020016157df603b91398660405160200161105e92919061463e565b60405160208183030381529060405281526020016040518060400160405280600381526020017f47455400000000000000000000000000000000000000000000000000000000008152508152602001838152602001600067ffffffffffffffff8111156110ce576110cd613990565b5b6040519080825280601f01601f1916602001820160405280156111005781602001600182028036833780820191505090505b50815260200160001515815250905061111881610ec3565b92505050919050565b6111296138e8565b80604052600061114261113b84611bb0565b60ff611bba565b905080915050919050565b6111556138e8565b80604052606090506111668361247e565b156111ca57600082805190602001209050600061118285612495565b9050600060058251901b90505b600081146111c657808201519550602081039050826111ad876124b7565b80519060200120036111c1578593506111c6565b61118f565b5050505b92915050565b606060006111e76111e0846124e9565b6000611bba565b905080915050919050565b60606000829050600281511161123d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611234906146ae565b60405180910390fd5b60006002825161124d91906146fd565b905060008167ffffffffffffffff81111561126b5761126a613990565b5b6040519080825280601f01601f19166020018201604052801561129d5781602001600182028036833780820191505090505b5090506021830160208201845182518252848452505050809350505050919050565b600080839050600080600090505b825181101561133b57602e60f81b8382815181106112ee576112ed6141f1565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036113285780915061133b565b808061133390614731565b9150506112cd565b5060008060006001905060008490505b60008111156113ca578160308760018461136591906146fd565b81518110611376576113756141f1565b5b602001015160f81c60f81b60f81c61138e9190614779565b60ff1661139b91906147ad565b846113a69190614807565b9350600a826113b591906147ad565b915080806113c29061485d565b91505061134b565b506001905060008760ff16856113e09190614807565b90505b8481111561145557816030878381518110611401576114006141f1565b5b602001015160f81c60f81b60f81c6114199190614779565b60ff1661142691906147ad565b836114319190614807565b9250600a8261144091906147ad565b9150808061144d9061485d565b9150506113e3565b508187600a61146491906149b9565b8461146f91906147ad565b6114799190614807565b9550505050505092915050565b606060006040518061014001604052808473ffffffffffffffffffffffffffffffffffffffff168152602001620186a0815260200164174876e800815260200160008152602001600081526020016040516024016040516020818303038152906040527f1aa3a008000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508152602001600581526020017f111111111111111111111111111111111111111111111111111111111111111181526020017f11111111111111111111111111111111111111111111111111111111111111118152602001601b67ffffffffffffffff16815250905060006115cb826124f3565b905060006115d76127a4565b9050611619826040518060400160405280600381526020017f3078350000000000000000000000000000000000000000000000000000000000815250836127ff565b9350505050919050565b6060600080635320000373ffffffffffffffffffffffffffffffffffffffff16846040516020016116549190614a7b565b604051602081830303815290604052604051611670919061456e565b600060405180830381855afa9150503d80600081146116ab576040519150601f19603f3d011682016040523d82523d6000602084013e6116b0565b606091505b5091509150816116fd576353200003816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016116f49291906142fb565b60405180910390fd5b808060200190518101906117119190614b06565b92505050919050565b60008060405160200161172c90614b9b565b60405160208183030381529060405280519060200120905060006117718260405160200161175a9190614be6565b6040516020818303038152906040526000866128fc565b905061177d8282612a0a565b92505050919050565b600080600367ffffffffffffffff8111156117a4576117a3613990565b5b6040519080825280602002602001820160405280156117d25781602001602082028036833780820191505090505b50905030816000815181106117ea576117e96141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505063420300018160018151811061183d5761183c6141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506342020001816002815181106118905761188f6141f1565b5b602002602001019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600061190e600083846040518060400160405280601281526020017f6f7261636c653a76303a706b7365637265740000000000000000000000000000815250612a79565b905061195481600001516040518060400160405280601281526020017f6f7261636c653a76303a706b736563726574000000000000000000000000000081525086612b7f565b806000015192505050919050565b60606000604051806101400160405280600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001620186a081526020018481526020016000815260200185815260200187876040516024016119df92919061409a565b6040516020818303038152906040527f4a432a46000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050508152602001600581526020017f111111111111111111111111111111111111111111111111111111111111111181526020017f11111111111111111111111111111111111111111111111111111111111111118152602001601b67ffffffffffffffff1681525090506000611ad0826124f3565b90506000611adc6127a4565b9050611b1e826040518060400160405280600381526020017f3078350000000000000000000000000000000000000000000000000000000000815250836127ff565b9350505050949350505050565b611b3482612c62565b611b3e8282612d4d565b5050565b60608151600260405101915080810182526f30313233343536373839616263646566600f52602082018184015b808514611b9d57600185019450600f855116516001830153600f855160041c16518253600282019150611b6f565b6000825260208201604052505050919050565b6000819050919050565b60006123c6565b63101827966000526004601cfd5b6000815160001a9050919050565b60008190505b600115611c0d576001640100002600611bfb83611bcf565b1c1615611c0e57600181019050611be3565b5b92915050565b600063ffffffff84113d3d3e83831b8263ffffffff851b19161790509392505050565b600081831c63ffffffff16905092915050565b60006040519050611c6f8486036078611c6a602086018803605888611c14565b611c14565b925085831781526020810160405295945050505050565b600080611c97846018600051611c14565b611ca18787611bdd565b9150868210611cb05750611e03565b611cb982611bcf565b600115611df45760228103611ced5782611cd589858589612045565b9350611ce560048583868a611c4a565b945050611df4565b605b8103611d0a57611d0188848488611e0c565b93509350611df4565b607b8103611d2757611d1e88848488611ee4565b93509350611df4565b6001611ff9602d1b821c1615611d4c57611d4388848488612154565b93509350611df4565b876004840111611daf5782835160e01c63747275658103611d8457600485019450611d7b60058684878b611c4a565b95505050611df4565b636e756c6c8103611dac57600485019450611da360068684878b611c4a565b95505050611df4565b50505b876005840111611deb5782835160d81c6466616c73658103611de857600585019450611ddf60058684878b611c4a565b95505050611df4565b50505b611df3611bc1565b5b50611dff8783611bdd565b9150505b94509492505050565b60008060006001860191505b600115611eb657868210611e2f57611e2e611bc1565b5b82611e5257611e3e8783611bdd565b9150605d611e4b83611bcf565b0315611eb6575b611e5e87838587611c86565b925092508215611ea757611e788160988551604017611c14565b8352600181019050611e8982611bcf565b605d8103611e975750611eb6565b602c8103611ea55750611eab565b505b8691505b600182019150611e18565b600182019150611ec883603887611c14565b9450611ed8600183888888611c4a565b92505094509492505050565b6000806001850190505b600115611fd757858110611f0557611f04611bc1565b5b81611f2857611f148682611bdd565b9050607d611f2182611bcf565b0315611fd7575b611f328682611bdd565b905080611f4187838587612045565b611f4b8882611bdd565b9250603a611f5884611bcf565b03611fc657611f6c88600185018688611c86565b935093508315611fc557611f986020860183036098611f9385850360b88951608017611c14565b611c14565b8452611fa383611bcf565b607d8103611fb357505050611fd7565b602c8103611fc357505050611fcc565b505b5b87925050505b600181019050611eee565b600181019050611fe982603886611c14565b9350611ff9600282878787611c4a565b915094509492505050565b6001667e0000007e03ff603061201b858501611bcf565b031c1661202b5761202a611bc1565b5b60058214612041576120406001830182612004565b5b5050565b600084841061205757612056611bc1565b5b6001840190505b6001156120f05761206e81611bcf565b6022810361207c57506120f0565b605c811461209057600182019150506120eb565b61209c60018301611bcf565b905060016a0510110400000000002001602283031c16156120c357600282019150506120eb565b607581036120e2576120d6600283612004565b600682019150506120eb565b859150506120f0565b61205e565b848110612100576120ff611bc1565b5b600181019050949350505050565b60008190505b60011561213a57600a603061212883611bcf565b03101561213a57600181019050612114565b80821484161561214d5761214c611bc1565b5b9392505050565b600080849050602d61216582611bcf565b03612171576001810190505b600a603061217e83611bcf565b031061218d5761218c611bc1565b5b61219681611bcf565b600182019150603081146121b3576121b06000888461210e565b91505b602e6121be83611bcf565b036121d5576121d26001886001850161210e565b91505b815160658160001a60201703612204576122016001896001860162010001600e8660011a031a0161210e565b92505b612212600384898989611c4a565b9350505094509492505050565b600060405190508282019150601f1980601f8601165b60011561224f578084015181840152818101905080612235575b50848252600085602084010152846040830101604052509392505050565b6000606090508151600281600716116123595782158115176123595760208116156122a45761229d603882611c37565b9150612359565b6040519150602082016122b8603883611c37565b5b80156122ed5780825280516122cf601882611c37565b6122db87601884611c14565b835280925060208401935050506122b9565b50601f1983820381018060051c85528260405261230c85603886611c14565b93508360201786526040811061235557602085018186015b60011561235257815181518352808252848201915060208301925081831061234c5750612352565b50612324565b50505b5050505b50919050565b600060609050815180158315171561237757506123be565b6123818482611c37565b91508086166123bc5761239560d882611c37565b6123a96123a28784611c37565b848361221f565b92506123b6838684611c14565b87178452505b505b949350505050565b816000811461243f5760018114612455576003811461246b576020840184518101808214612424576123f781611bcf565b6022825361240b8760d8602260f81b611c14565b60005261241b828460008a611c86565b93509450808253505b8315818310171561243857612437611bc1565b5b5050612477565b61244e6010607860588761235f565b9150612477565b612464600860b860988761235f565b9150612477565b6124748461226d565b91505b5092915050565b6000600260ff166007836000015116149050919050565b606060006124ac6124a5846124e9565b6003611bba565b905080915050919050565b606060006080836000015116146124e45760006124dd6124d6846124e9565b6001611bba565b9050809150505b919050565b6000819050919050565b60606000600967ffffffffffffffff81111561251257612511613990565b5b60405190808252806020026020018201604052801561254557816020015b60608152602001906001900390816125305790505b5090506125558360800151612eb3565b81600081518110612569576125686141f1565b5b60200260200101819052506125818360400151612eb3565b81600181518110612595576125946141f1565b5b60200260200101819052506125ad8360200151612eb3565b816002815181106125c1576125c06141f1565b5b6020026020010181905250600073ffffffffffffffffffffffffffffffffffffffff16836000015173ffffffffffffffffffffffffffffffffffffffff16036126405761261c60405180602001604052806000815250612ecd565b816003815181106126305761262f6141f1565b5b602002602001018190525061266d565b61264d8360000151612f4b565b81600381518110612661576126606141f1565b5b60200260200101819052505b61267a8360600151612eb3565b8160048151811061268e5761268d6141f1565b5b60200260200101819052506126a68360a00151612ecd565b816005815181106126ba576126b96141f1565b5b60200260200101819052506126dd83610120015167ffffffffffffffff16612eb3565b816006815181106126f1576126f06141f1565b5b60200260200101819052506127288360e001516040516020016127149190614be6565b604051602081830303815290604052612ecd565b8160078151811061273c5761273b6141f1565b5b60200260200101819052506127748361010001516040516020016127609190614be6565b604051602081830303815290604052612ecd565b81600881518110612788576127876141f1565b5b602002602001018190525061279c81612f7c565b915050919050565b606060006127f6600060019054906101000a900460801b6040518060400160405280601281526020017f6f7261636c653a76303a706b7365637265740000000000000000000000000000815250612fc0565b90508091505090565b6060600080634010000173ffffffffffffffffffffffffffffffffffffffff1686868660405160200161283493929190614c01565b604051602081830303815290604052604051612850919061456e565b600060405180830381855afa9150503d806000811461288b576040519150601f19603f3d011682016040523d82523d6000602084013e612890565b606091505b5091509150816128dd576340100001816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016128d49291906142fb565b60405180910390fd5b808060200190518101906128f191906145f5565b925050509392505050565b6060612906610d56565b61290f57600080fd5b600080634010000373ffffffffffffffffffffffffffffffffffffffff1686868660405160200161294293929190614c4d565b60405160208183030381529060405260405161295e919061456e565b600060405180830381855afa9150503d8060008114612999576040519150601f19603f3d011682016040523d82523d6000602084013e61299e565b606091505b5091509150816129eb576340100003816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016129e29291906142fb565b60405180910390fd5b808060200190518101906129ff91906145f5565b925050509392505050565b600080600080612a19856130a7565b92509250925060018682858560405160008152602001604052604051612a429493929190614ca1565b6020604051602081039080840390855afa158015612a64573d6000803e3d6000fd5b50505060206040510351935050505092915050565b612a816138fb565b600080634203000073ffffffffffffffffffffffffffffffffffffffff1687878787604051602001612ab69493929190614db3565b604051602081830303815290604052604051612ad2919061456e565b600060405180830381855afa9150503d8060008114612b0d576040519150601f19603f3d011682016040523d82523d6000602084013e612b12565b606091505b509150915081612b5f576342030000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401612b569291906142fb565b60405180910390fd5b80806020019051810190612b739190615012565b92505050949350505050565b600080634202000073ffffffffffffffffffffffffffffffffffffffff16858585604051602001612bb29392919061505b565b604051602081830303815290604052604051612bce919061456e565b600060405180830381855afa9150503d8060008114612c09576040519150601f19603f3d011682016040523d82523d6000602084013e612c0e565b606091505b509150915081612c5b576342020000816040517f75fff467000000000000000000000000000000000000000000000000000000008152600401612c529291906142fb565b60405180910390fd5b5050505050565b6000612c6d82610e9d565b604051602001612c7d9190615138565b6040516020818303038152906040529050600080634210000073ffffffffffffffffffffffffffffffffffffffff1683604051602001612cbd9190613c88565b604051602081830303815290604052604051612cd9919061456e565b600060405180830381855afa9150503d8060008114612d14576040519150601f19603f3d011682016040523d82523d6000602084013e612d19565b606091505b5091509150612d478282604051602001612d3391906151b1565b604051602081830303815290604052610e1e565b50505050565b6000600167ffffffffffffffff811115612d6a57612d69613990565b5b604051908082528060200260200182016040528015612d9d57816020015b6060815260200190600190039081612d885790505b5090508281600081518110612db557612db46141f1565b5b60200260200101819052506000612dd6828467ffffffffffffffff1661312b565b9050600080634300000173ffffffffffffffffffffffffffffffffffffffff1660405180606001604052806022815260200161581a6022913984604051602001612e2192919061521f565b604051602081830303815290604052604051612e3d919061456e565b600060405180830381855afa9150503d8060008114612e78576040519150601f19603f3d011682016040523d82523d6000602084013e612e7d565b606091505b5091509150612eab8282604051602001612e9791906152b5565b604051602081830303815290604052610e1e565b505050505050565b6060612ec6612ec18361324a565b612ecd565b9050919050565b60608060018351148015612f055750608083600081518110612ef257612ef16141f1565b5b602001015160f81c60f81b60f81c60ff16105b15612f1257829050612f42565b612f1e835160806133cd565b83604051602001612f309291906152d7565b60405160208183030381529060405290505b80915050919050565b6060612f7582604051602001612f619190615343565b604051602081830303815290604052612ecd565b9050919050565b60606000612f8983613619565b9050612f97815160c06133cd565b81604051602001612fa99291906152d7565b604051602081830303815290604052915050919050565b6060600080634202000173ffffffffffffffffffffffffffffffffffffffff168585604051602001612ff392919061535e565b60405160208183030381529060405260405161300f919061456e565b600060405180830381855afa9150503d806000811461304a576040519150601f19603f3d011682016040523d82523d6000602084013e61304f565b606091505b50915091508161309c576342020001816040517f75fff4670000000000000000000000000000000000000000000000000000000081526004016130939291906142fb565b60405180910390fd5b809250505092915050565b600080600060418451146130f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130e7906153da565b60405180910390fd5b6020840151925060408401519150606084015160001a9050601b8160ff16101561312457601b8161312191906153fa565b90505b9193909250565b60606000613138836137ab565b60405160200161314891906154c9565b604051602081830303815290604052905060005b845181101561321d578161318986838151811061317c5761317b6141f1565b5b6020026020010151610e9d565b60405160200161319a929190615542565b6040516020818303038152906040529150600185516131b991906146fd565b8110156131e757816040516020016131d191906155c8565b604051602081830303815290604052915061320a565b816040516020016131f89190615636565b60405160208183030381529060405291505b808061321590614731565b91505061315c565b508060405160200161322f91906156a4565b60405160208183030381529060405290508091505092915050565b606060008260405160200161325f91906156e7565b604051602081830303815290604052905060005b60208110156132d957600060f81b828281518110613294576132936141f1565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036132d95780806132d190614731565b915050613273565b60008160206132e891906146fd565b67ffffffffffffffff81111561330157613300613990565b5b6040519080825280601f01601f1916602001820160405280156133335781602001600182028036833780820191505090505b50905060005b81518110156133c15783838061334e90614731565b945081518110613361576133606141f1565b5b602001015160f81c60f81b82828151811061337f5761337e6141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080806133b990614731565b915050613339565b50809350505050919050565b606080603884101561348057600167ffffffffffffffff8111156133f4576133f3613990565b5b6040519080825280601f01601f1916602001820160405280156134265781602001600182028036833780820191505090505b509050828461343591906153fa565b60f81b8160008151811061344c5761344b6141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061360f565b600080600190505b600081876134969190615731565b146134be5781806134a690614731565b925050610100816134b791906147ad565b9050613488565b6001826134cb9190614807565b67ffffffffffffffff8111156134e4576134e3613990565b5b6040519080825280601f01601f1916602001820160405280156135165781602001600182028036833780820191505090505b5092506037858361352791906153fa565b61353191906153fa565b60f81b83600081518110613548576135476141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190505b81811161360c57610100818361359291906146fd565b61010061359f9190615762565b876135aa9190615731565b6135b491906157ad565b60f81b8382815181106135ca576135c96141f1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350808061360490614731565b91505061357c565b50505b8091505092915050565b6060600082510361367957600067ffffffffffffffff81111561363f5761363e613990565b5b6040519080825280601f01601f1916602001820160405280156136715781602001600182028036833780820191505090505b5090506137a6565b600080600090505b83518110156136c65783818151811061369d5761369c6141f1565b5b602002602001015151826136b19190614807565b915080806136be90614731565b915050613681565b60008267ffffffffffffffff8111156136e2576136e1613990565b5b6040519080825280601f01601f1916602001820160405280156137145781602001600182028036833780820191505090505b5090506000602082019050600092505b855183101561379e576000868481518110613742576137416141f1565b5b602002602001015190506000602082019050613760838284516137d1565b878581518110613773576137726141f1565b5b602002602001015151836137879190614807565b92505050828061379690614731565b935050613724565b819450505050505b919050565b60606137b682613847565b90506002815101613078825260028203915080825250919050565b6000839050600083905060008390505b6020811061381f57815183526020836137fa9190614807565b92506020826138099190614807565b915060208161381891906146fd565b90506137e1565b60006001826020036101000a0390508019835116818551168181178652505050505050505050565b606060806040510190506020810160405260008152806f30313233343536373839616263646566600f52600119835b6001156138a2578184019350600f8116516001850153600f8160041c165184538060081c905080613876575b50828203602084039350808452505050919050565b6040518060a00160405280606081526020016060815260200160608152602001606081526020016000151581525090565b6040518060200160405280600081525090565b6040518060c0016040528060006fffffffffffffffffffffffffffffffff1916815260200160006fffffffffffffffffffffffffffffffff19168152602001600067ffffffffffffffff1681526020016060815260200160608152602001606081525090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6139c88261397f565b810181811067ffffffffffffffff821117156139e7576139e6613990565b5b80604052505050565b60006139fa613961565b9050613a0682826139bf565b919050565b600067ffffffffffffffff821115613a2657613a25613990565b5b613a2f8261397f565b9050602081019050919050565b82818337600083830152505050565b6000613a5e613a5984613a0b565b6139f0565b905082815260208101848484011115613a7a57613a7961397a565b5b613a85848285613a3c565b509392505050565b600082601f830112613aa257613aa1613975565b5b8135613ab2848260208601613a4b565b91505092915050565b6000819050919050565b613ace81613abb565b8114613ad957600080fd5b50565b600081359050613aeb81613ac5565b92915050565b600067ffffffffffffffff82169050919050565b613b0e81613af1565b8114613b1957600080fd5b50565b600081359050613b2b81613b05565b92915050565b60008115159050919050565b613b4681613b31565b8114613b5157600080fd5b50565b600081359050613b6381613b3d565b92915050565b600080600080600060a08688031215613b8557613b8461396b565b5b600086013567ffffffffffffffff811115613ba357613ba2613970565b5b613baf88828901613a8d565b9550506020613bc088828901613adc565b9450506040613bd188828901613adc565b9350506060613be288828901613b1c565b9250506080613bf388828901613b54565b9150509295509295909350565b600081519050919050565b600082825260208201905092915050565b60005b83811015613c3a578082015181840152602081019050613c1f565b83811115613c49576000848401525b50505050565b6000613c5a82613c00565b613c648185613c0b565b9350613c74818560208601613c1c565b613c7d8161397f565b840191505092915050565b60006020820190508181036000830152613ca28184613c4f565b905092915050565b600067ffffffffffffffff821115613cc557613cc4613990565b5b613cce8261397f565b9050602081019050919050565b6000613cee613ce984613caa565b6139f0565b905082815260208101848484011115613d0a57613d0961397a565b5b613d15848285613a3c565b509392505050565b600082601f830112613d3257613d31613975565b5b8135613d42848260208601613cdb565b91505092915050565b600060208284031215613d6157613d6061396b565b5b600082013567ffffffffffffffff811115613d7f57613d7e613970565b5b613d8b84828501613d1d565b91505092915050565b600060ff82169050919050565b613daa81613d94565b82525050565b6000602082019050613dc56000830184613da1565b92915050565b613dd481613abb565b82525050565b6000602082019050613def6000830184613dcb565b92915050565b600060208284031215613e0b57613e0a61396b565b5b600082013567ffffffffffffffff811115613e2957613e28613970565b5b613e3584828501613a8d565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613e6982613e3e565b9050919050565b613e7981613e5e565b8114613e8457600080fd5b50565b600081359050613e9681613e70565b92915050565b600060208284031215613eb257613eb161396b565b5b6000613ec084828501613e87565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000613ef082613ec9565b613efa8185613ed4565b9350613f0a818560208601613c1c565b613f138161397f565b840191505092915050565b60006020820190508181036000830152613f388184613ee5565b905092915050565b60007fffffffffffffffffffffffffffffffff0000000000000000000000000000000082169050919050565b6000613f7782613f40565b9050919050565b613f8781613f6c565b82525050565b6000602082019050613fa26000830184613f7e565b92915050565b60008060408385031215613fbf57613fbe61396b565b5b600083013567ffffffffffffffff811115613fdd57613fdc613970565b5b613fe985828601613a8d565b9250506020613ffa85828601613adc565b9150509250929050565b61400d81613f40565b811461401857600080fd5b50565b60008135905061402a81614004565b92915050565b600080604083850312156140475761404661396b565b5b60006140558582860161401b565b925050602061406685828601613e87565b9150509250929050565b61407981613e5e565b82525050565b60006020820190506140946000830184614070565b92915050565b600060408201905081810360008301526140b48185613ee5565b90506140c36020830184613dcb565b9392505050565b600081905092915050565b7f7b226a736f6e727063223a22322e30222c226d6574686f64223a226574685f7360008201527f656e645261775472616e73616374696f6e222c22706172616d73223a5b220000602082015250565b6000614131603e836140ca565b915061413c826140d5565b603e82019050919050565b600061415282613ec9565b61415c81856140ca565b935061416c818560208601613c1c565b80840191505092915050565b7f225d2c226964223a317d00000000000000000000000000000000000000000000600082015250565b60006141ae600a836140ca565b91506141b982614178565b600a82019050919050565b60006141cf82614124565b91506141db8284614147565b91506141e6826141a1565b915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f416c726561647920726567697374657265640000000000000000000000000000600082015250565b6000614256601283613ed4565b915061426182614220565b602082019050919050565b6000602082019050818103600083015261428581614249565b9050919050565b60006040820190506142a16000830185613f7e565b6142ae6020830184614070565b9392505050565b600081905092915050565b50565b60006142d06000836142b5565b91506142db826142c0565b600082019050919050565b60006142f1826142c3565b9150819050919050565b60006040820190506143106000830185614070565b81810360208301526143228184613c4f565b90509392505050565b600082825260208201905092915050565b600061434782613ec9565b614351818561432b565b9350614361818560208601613c1c565b61436a8161397f565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006143ad838361433c565b905092915050565b6000602082019050919050565b60006143cd82614375565b6143d78185614380565b9350836020820285016143e985614391565b8060005b85811015614425578484038952815161440685826143a1565b9450614411836143b5565b925060208a019950506001810190506143ed565b50829750879550505050505092915050565b600082825260208201905092915050565b600061445382613c00565b61445d8185614437565b935061446d818560208601613c1c565b6144768161397f565b840191505092915050565b61448a81613b31565b82525050565b600060a08301600083015184820360008601526144ad828261433c565b915050602083015184820360208601526144c7828261433c565b915050604083015184820360408601526144e182826143c2565b915050606083015184820360608601526144fb8282614448565b91505060808301516145106080860182614481565b508091505092915050565b600060208201905081810360008301526145358184614490565b905092915050565b600061454882613c00565b61455281856142b5565b9350614562818560208601613c1c565b80840191505092915050565b600061457a828461453d565b915081905092915050565b600061459861459384613caa565b6139f0565b9050828152602081018484840111156145b4576145b361397a565b5b6145bf848285613c1c565b509392505050565b600082601f8301126145dc576145db613975565b5b81516145ec848260208601614585565b91505092915050565b60006020828403121561460b5761460a61396b565b5b600082015167ffffffffffffffff81111561462957614628613970565b5b614635848285016145c7565b91505092915050565b600061464a8285614147565b91506146568284614147565b91508190509392505050565b7f496e70757420746f6f2073686f72740000000000000000000000000000000000600082015250565b6000614698600f83613ed4565b91506146a382614662565b602082019050919050565b600060208201905081810360008301526146c78161468b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061470882613abb565b915061471383613abb565b925082821015614726576147256146ce565b5b828203905092915050565b600061473c82613abb565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361476e5761476d6146ce565b5b600182019050919050565b600061478482613d94565b915061478f83613d94565b9250828210156147a2576147a16146ce565b5b828203905092915050565b60006147b882613abb565b91506147c383613abb565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156147fc576147fb6146ce565b5b828202905092915050565b600061481282613abb565b915061481d83613abb565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115614852576148516146ce565b5b828201905092915050565b600061486882613abb565b91506000820361487b5761487a6146ce565b5b600182039050919050565b60008160011c9050919050565b6000808291508390505b60018511156148dd578086048111156148b9576148b86146ce565b5b60018516156148c85780820291505b80810290506148d685614886565b945061489d565b94509492505050565b6000826148f657600190506149b2565b8161490457600090506149b2565b816001811461491a576002811461492457614953565b60019150506149b2565b60ff841115614936576149356146ce565b5b8360020a91508482111561494d5761494c6146ce565b5b506149b2565b5060208310610133831016604e8410600b84101617156149885782820a905083811115614983576149826146ce565b5b6149b2565b6149958484846001614893565b925090508184048111156149ac576149ab6146ce565b5b81810290505b9392505050565b60006149c482613abb565b91506149cf83613d94565b92506149fc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846148e6565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60028110614a4457614a43614a04565b5b50565b6000819050614a5582614a33565b919050565b6000614a6582614a47565b9050919050565b614a7581614a5a565b82525050565b6000602082019050614a906000830184614a6c565b92915050565b6000614aa9614aa484613a0b565b6139f0565b905082815260208101848484011115614ac557614ac461397a565b5b614ad0848285613c1c565b509392505050565b600082601f830112614aed57614aec613975565b5b8151614afd848260208601614a96565b91505092915050565b600060208284031215614b1c57614b1b61396b565b5b600082015167ffffffffffffffff811115614b3a57614b39613970565b5b614b4684828501614ad8565b91505092915050565b7f796f000000000000000000000000000000000000000000000000000000000000600082015250565b6000614b85600283613ed4565b9150614b9082614b4f565b602082019050919050565b60006020820190508181036000830152614bb481614b78565b9050919050565b6000819050919050565b6000819050919050565b614be0614bdb82614bbb565b614bc5565b82525050565b6000614bf28284614bcf565b60208201915081905092915050565b60006060820190508181036000830152614c1b8186613c4f565b90508181036020830152614c2f8185613ee5565b90508181036040830152614c438184613ee5565b9050949350505050565b60006060820190508181036000830152614c678186613c4f565b9050614c766020830185614a6c565b8181036040830152614c888184613ee5565b9050949350505050565b614c9b81614bbb565b82525050565b6000608082019050614cb66000830187614c92565b614cc36020830186613da1565b614cd06040830185614c92565b614cdd6060830184614c92565b95945050505050565b614cef81613af1565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b614d2a81613e5e565b82525050565b6000614d3c8383614d21565b60208301905092915050565b6000602082019050919050565b6000614d6082614cf5565b614d6a8185614d00565b9350614d7583614d11565b8060005b83811015614da6578151614d8d8882614d30565b9750614d9883614d48565b925050600181019050614d79565b5085935050505092915050565b6000608082019050614dc86000830187614ce6565b8181036020830152614dda8186614d55565b90508181036040830152614dee8185614d55565b90508181036060830152614e028184613ee5565b905095945050505050565b600080fd5b600080fd5b600081519050614e2681614004565b92915050565b600081519050614e3b81613b05565b92915050565b600067ffffffffffffffff821115614e5c57614e5b613990565b5b602082029050602081019050919050565b600080fd5b600081519050614e8181613e70565b92915050565b6000614e9a614e9584614e41565b6139f0565b90508083825260208201905060208402830185811115614ebd57614ebc614e6d565b5b835b81811015614ee65780614ed28882614e72565b845260208401935050602081019050614ebf565b5050509392505050565b600082601f830112614f0557614f04613975565b5b8151614f15848260208601614e87565b91505092915050565b600060c08284031215614f3457614f33614e0d565b5b614f3e60c06139f0565b90506000614f4e84828501614e17565b6000830152506020614f6284828501614e17565b6020830152506040614f7684828501614e2c565b604083015250606082015167ffffffffffffffff811115614f9a57614f99614e12565b5b614fa684828501614ef0565b606083015250608082015167ffffffffffffffff811115614fca57614fc9614e12565b5b614fd684828501614ef0565b60808301525060a082015167ffffffffffffffff811115614ffa57614ff9614e12565b5b61500684828501614ad8565b60a08301525092915050565b6000602082840312156150285761502761396b565b5b600082015167ffffffffffffffff81111561504657615045613970565b5b61505284828501614f1e565b91505092915050565b60006060820190506150706000830186613f7e565b81810360208301526150828185613ee5565b905081810360408301526150968184613c4f565b9050949350505050565b7f7b22747873223a205b2200000000000000000000000000000000000000000000600082015250565b60006150d6600a836140ca565b91506150e1826150a0565b600a82019050919050565b7f225d7d0000000000000000000000000000000000000000000000000000000000600082015250565b60006151226003836140ca565b915061512d826150ec565b600382019050919050565b6000615143826150c9565b915061514f8284614147565b915061515a82615115565b915081905092915050565b7f42756e646c6553696d756c6174696f6e4661696c65643a200000000000000000600082015250565b600061519b6018836140ca565b91506151a682615165565b601882019050919050565b60006151bc8261518e565b91506151c88284614147565b915081905092915050565b7f6574685f73656e6442756e646c65000000000000000000000000000000000000600082015250565b6000615209600e83613ed4565b9150615214826151d3565b602082019050919050565b600060608201905081810360008301526152398185613ee5565b9050818103602083015261524c816151fc565b905081810360408301526152608184613c4f565b90509392505050565b7f42756e646c655375626d697373696f6e4661696c65643a200000000000000000600082015250565b600061529f6018836140ca565b91506152aa82615269565b601882019050919050565b60006152c082615292565b91506152cc8284614147565b915081905092915050565b60006152e3828561453d565b91506152ef828461453d565b91508190509392505050565b60008160601b9050919050565b6000615313826152fb565b9050919050565b600061532582615308565b9050919050565b61533d61533882613e5e565b61531a565b82525050565b600061534f828461532c565b60148201915081905092915050565b60006040820190506153736000830185613f7e565b81810360208301526153858184613ee5565b90509392505050565b7f696e76616c6964207369676e6174757265206c656e6774680000000000000000600082015250565b60006153c4601883613ed4565b91506153cf8261538e565b602082019050919050565b600060208201905081810360008301526153f3816153b7565b9050919050565b600061540582613d94565b915061541083613d94565b92508260ff03821115615426576154256146ce565b5b828201905092915050565b7f7b22626c6f636b4e756d626572223a2022000000000000000000000000000000600082015250565b60006154676011836140ca565b915061547282615431565b601182019050919050565b7f222c2022747873223a205b000000000000000000000000000000000000000000600082015250565b60006154b3600b836140ca565b91506154be8261547d565b600b82019050919050565b60006154d48261545a565b91506154e08284614147565b91506154eb826154a6565b915081905092915050565b7f2200000000000000000000000000000000000000000000000000000000000000600082015250565b600061552c6001836140ca565b9150615537826154f6565b600182019050919050565b600061554e828561453d565b91506155598261551f565b91506155658284614147565b91506155708261551f565b91508190509392505050565b7f2c00000000000000000000000000000000000000000000000000000000000000600082015250565b60006155b26001836140ca565b91506155bd8261557c565b600182019050919050565b60006155d4828461453d565b91506155df826155a5565b915081905092915050565b7f5d00000000000000000000000000000000000000000000000000000000000000600082015250565b60006156206001836140ca565b915061562b826155ea565b600182019050919050565b6000615642828461453d565b915061564d82615613565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000600082015250565b600061568e6001836140ca565b915061569982615658565b600182019050919050565b60006156b0828461453d565b91506156bb82615681565b915081905092915050565b6000819050919050565b6156e16156dc82613abb565b6156c6565b82525050565b60006156f382846156d0565b60208201915081905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061573c82613abb565b915061574783613abb565b92508261575757615756615702565b5b828204905092915050565b600061576d82613abb565b915061577883613abb565b92506157a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846148e6565b905092915050565b60006157b882613abb565b91506157c383613abb565b9250826157d3576157d2615702565b5b82820690509291505056fe68747470733a2f2f646174612d6170692e62696e616e63652e766973696f6e2f6170692f76332f7469636b65722f70726963653f73796d626f6c3d68747470733a2f2f72656c61792d676f65726c692e666c617368626f74732e6e657468747470733a2f2f676f65726c692e696e667572612e696f2f76332f3961613364393562336263343430666138386561313265616134343536313631a264697066735822122094fa656988693296a6c71e7e78853503c2b9e7e490a74e0ff6a2f37e446ed22464736f6c634300080d0033", + "devdoc": { + "kind": "dev", + "methods": {}, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 3596, + "contract": "contracts/oracle/BinanceOracle.sol:BinanceOracle", + "label": "isInitialized", + "offset": 0, + "slot": "0", + "type": "t_bool" + }, + { + "astId": 3599, + "contract": "contracts/oracle/BinanceOracle.sol:BinanceOracle", + "label": "pkBidId", + "offset": 1, + "slot": "0", + "type": "t_userDefinedValueType(DataId)858" + }, + { + "astId": 3601, + "contract": "contracts/oracle/BinanceOracle.sol:BinanceOracle", + "label": "controller", + "offset": 0, + "slot": "1", + "type": "t_address" + }, + { + "astId": 3603, + "contract": "contracts/oracle/BinanceOracle.sol:BinanceOracle", + "label": "settlementContract", + "offset": 0, + "slot": "2", + "type": "t_address" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "encoding": "inplace", + "label": "bool", + "numberOfBytes": "1" + }, + "t_userDefinedValueType(DataId)858": { + "encoding": "inplace", + "label": "Suave.DataId", + "numberOfBytes": "16" + } + } + } +} \ No newline at end of file diff --git a/deployments/rigil/BlockAdAuctionV2.json b/deployments/rigil/BlockAdAuctionV2.json index d262bb3..61a29b7 100644 --- a/deployments/rigil/BlockAdAuctionV2.json +++ b/deployments/rigil/BlockAdAuctionV2.json @@ -580,7 +580,7 @@ "label": "secretBidId", "offset": 0, "slot": "0", - "type": "t_userDefinedValueType(DataId)1886" + "type": "t_userDefinedValueType(DataId)2393" }, { "astId": 1387, @@ -679,7 +679,7 @@ "label": "paymentBidId", "offset": 0, "slot": "3", - "type": "t_userDefinedValueType(DataId)1886" + "type": "t_userDefinedValueType(DataId)2393" } ], "numberOfBytes": "128" @@ -689,10 +689,10 @@ "label": "uint256", "numberOfBytes": "32" }, - "t_userDefinedValueType(DataId)1886": { + "t_userDefinedValueType(DataId)2393": { "encoding": "inplace", "label": "Suave.DataId", - "numberOfBytes": "32" + "numberOfBytes": "16" } } } diff --git a/deployments/rigil/solcInputs/853b3cf0cd754334abb4d5db7d2932f9.json b/deployments/rigil/solcInputs/853b3cf0cd754334abb4d5db7d2932f9.json new file mode 100644 index 0000000..cd7e871 --- /dev/null +++ b/deployments/rigil/solcInputs/853b3cf0cd754334abb4d5db7d2932f9.json @@ -0,0 +1,65 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen() internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, string memory signingKey) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport { floatToInt, trimStrEdges, getAddressForPk } from \"./lib/Utils.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n isInitialized = true;\n }\n\n function registerCallback(address _settlementContract) public {\n require(_settlementContract == settlementContract || settlementContract == address(0), \"Already registered\");\n settlementContract = _settlementContract;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen();\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\n }\n\n function queryAndSubmit(\n string memory ticker, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) external view onlyConfidential returns (uint) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum);\n return price;\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n string memory ticker,\n uint price, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) internal view {\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\n // sendBundle(signedTx, settlementBlockNum);\n sendRawTx(signedTx);\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: gasPrice,\n gas: 100_000,\n to: settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"updatePrice(string,uint256)\", ticker, price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}" + }, + "contracts/oracle/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\n// 🚨 THIS IS UNTESTED DEMO CODE - DONT USE IN PRODUCTION 🚨\n\n\npragma solidity ^0.8.8;\n\nimport '../../libraries/Suave.sol';\n\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Reset power of ten\n tenPower = 1;\n \n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/rigil/solcInputs/c30c35cbf6d4ade5bd1ec6169afebb51.json b/deployments/rigil/solcInputs/c30c35cbf6d4ade5bd1ec6169afebb51.json new file mode 100644 index 0000000..6d951f2 --- /dev/null +++ b/deployments/rigil/solcInputs/c30c35cbf6d4ade5bd1ec6169afebb51.json @@ -0,0 +1,62 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n enum CryptoSignature {\n SECP256,\n BLS\n }\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto));\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, CryptoSignature crypto, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, crypto, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n isInitialized = true;\n }\n\n function registerCallback(address _settlementContract) public {\n require(_settlementContract == settlementContract || settlementContract == address(0), \"Already registered\");\n settlementContract = _settlementContract;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\n }\n\n function queryAndSubmit(\n string memory ticker,\n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum,\n bool privateSubmission\n ) external view onlyConfidential returns (bytes memory) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum, privateSubmission);\n return abi.encodeWithSelector(this.queryAndSubmitCallback.selector, ticker, price);\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n string memory ticker,\n uint price, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum,\n bool privateSubmission\n ) internal view {\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\n if (privateSubmission) {\n sendBundle(signedTx, settlementBlockNum);\n } else {\n sendRawTx(signedTx);\n }\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: gasPrice,\n gas: 100_000,\n to: settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"updatePrice(string,uint256)\", ticker, price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}\n\n// 🔧 Utils\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n // Reset power of ten\n tenPower = 1;\n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), Suave.CryptoSignature.SECP256, pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/rigil/solcInputs/f0b2f426399e8375c22afdd65eead6a2.json b/deployments/rigil/solcInputs/f0b2f426399e8375c22afdd65eead6a2.json new file mode 100644 index 0000000..5d266e8 --- /dev/null +++ b/deployments/rigil/solcInputs/f0b2f426399e8375c22afdd65eead6a2.json @@ -0,0 +1,80 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/BlockAdV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AnyBundleContract, EthBlockBidSenderContract, Suave } from \"../standard_peekers/bids.sol\";\n\n\ncontract BlockAdAuctionV1 is AnyBundleContract {\n\n\tstruct AdBid {\n\t\tstring extra; \n\t\tSuave.DataId paymentBidId;\n\t\tuint blockHeight;\n\t}\n\n\tstruct EffectiveAdBid {\n\t\tstring extra;\n\t\tuint64 egp;\n\t\tbytes paymentBundle;\n\t}\n\n\tevent AdBidEvent(\n\t\tstring extra,\n\t\tuint blockNum\n\t);\n\n\tmapping(uint => AdBid[]) public blockToBid;\n\tEthBlockBidSenderContract public builder;\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\t// Make sure the builder contract cannot abuse the confidential payment bundle\n\t\tbuilder = new EthBlockBidSenderContract(boostRelayUrl_);\n\t}\n\n\t// ON-CHAIN METHODS\n\n\tfunction buyAdCallback(AdBid[] memory bids) external {\n\t\tfor (uint i = 0; i < bids.length; ++i) {\n\t\t\tuint blockNum = bids[i].blockHeight;\n\t\t\tblockToBid[blockNum].push(bids[i]);\n\t\t\t// todo: add some form of an id to the bid\n\t\t\temit AdBidEvent(bids[i].extra, blockNum);\n\t\t}\n\t}\n\n\t// CONFIDENTIAL METHODS\n\n\tfunction buyAd(\n\t\tuint64 blockStart, \n\t\tuint64 range, \n\t\tstring memory extra\n\t) external returns (bytes memory) {\n\t\trequire(Suave.isConfidential(), \"Not confidential\");\n\t\t// Check payment is valid for the latest state\n\t\tbytes memory paymentBundle = this.fetchConfidentialBundleData();\n\t\trequire(Suave.simulateBundle(paymentBundle) != 0, \"Initial sim check failed\");\n\t\t\n\t\taddress[] memory allowedPeekers = new address[](1);\n\t\tallowedPeekers[0] = address(this);\n\n\t\tAdBid[] memory bids = new AdBid[](range);\n\t\tfor (uint64 b = blockStart; b < blockStart+range; b++) {\n\t\t\t// Store payment bundle\n\t\t\tSuave.DataRecord memory paymentBid = Suave.newDataRecord(0, allowedPeekers, allowedPeekers, \"blockad:v0:paymentBundle\");\n\t\t\tSuave.confidentialStore(paymentBid.id, \"blockad:v0:paymentBundle\", paymentBundle);\n\t\t\t// Prepare bid data to be commited on-chain\n\t\t\tbids[b-blockStart] = AdBid(extra, paymentBid.id, b);\n\t\t}\n\t\treturn abi.encodeWithSelector(this.buyAdCallback.selector, bids);\n\t}\n\n\tfunction buildBlock(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n\t\trequire(Suave.isConfidential());\n\n\t\tAdBid[] storage blockBids = blockToBid[blockHeight];\n\t\trequire(blockBids.length > 0, \"No bids\");\n\n\t\tEffectiveAdBid memory bestOffer;\n\t\tfor (uint i = 0; i < blockBids.length; ++i) {\n\t\t\tbytes memory paymentBundle = Suave.confidentialRetrieve(\n\t\t\t\tblockBids[i].paymentBidId, \n\t\t\t\t\"blockad:v0:paymentBundle\"\n\t\t\t);\n\t\t\tuint64 egp = Suave.simulateBundle(paymentBundle);\n\t\t\tif (egp > bestOffer.egp)\n\t\t\t\tbestOffer = EffectiveAdBid(blockBids[i].extra, egp, paymentBundle);\n\t\t\t// todo: if egp == 0, delete all of their bids for the next blocks (when someone wins an ad, discard their subsequent(pending) bids)\n\t\t}\n\t\tdelete blockToBid[blockHeight];\n\n\t\t// Prep for block building - include extra & payment bundle\n\t\tif (bestOffer.egp > 0)\n\t\t\tblockArgs.extra = bytes(bestOffer.extra);\n\t\t// Expect the payment on top; if someone wants to fail the payment with other txs they have to have higher egp than the payment tx\n\t\taddress[] memory allowedPeekers = new address[](3);\n\t\tallowedPeekers[0] = address(builder);\n\t\tallowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\t\tallowedPeekers[2] = address(this);\n\t\tSuave.DataRecord memory paymentBundleBid = Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:ethBundles\");\n\t\tSuave.confidentialStore(paymentBundleBid.id, \"default:v0:ethBundles\", bestOffer.paymentBundle);\n\t\tSuave.confidentialStore(paymentBundleBid.id, \"default:v0:ethBundleSimResults\", abi.encode(bestOffer.egp));\n\t\t\n\t\treturn builder.buildFromPool(blockArgs, blockHeight);\n\t}\n\n}\n" + }, + "contracts/blockad/BlockAdV2.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { ConfidentialControl } from \"./lib/ConfidentialControl.sol\";\nimport { DynamicUintArray } from \"./lib/Utils.sol\";\nimport { Builder } from \"./lib/Builder.sol\";\n\n\ncontract BlockAdAuctionV2 is AnyBundleContract, ConfidentialControl {\n\tusing DynamicUintArray for bytes;\n\n\tstruct AdRequest {\n\t\tuint id;\n\t\tstring extra;\n\t\tuint blockLimit;\n\t\tSuave.DataId paymentBidId;\n\t}\n\tstruct Offer {\n\t\tuint id;\n\t\tstring extra;\n\t\tuint64 egp;\n\t\tbytes paymentBundle;\n\t}\n\n\tevent RequestAdded(uint indexed id, string extra, uint blockLimit);\n\tevent RequestRemoved(uint indexed id);\n\tevent RequestIncluded(uint indexed id, uint64 egp, string blockHash);\n\n\tstring internal constant PB_NAMESPACE = \"blockad:v0:paymentBundle\";\n\tstring internal constant EB_NAMESPACE = \"default:v0:ethBundles\";\n\tstring internal constant EB_SIM_NAMESPACE = \"default:v0:ethBundleSimResults\";\n\tBuilder public builder;\n\tAdRequest[] public requests;\n\tuint public nextId;\n\n\t/**********************************************************************\n\t * ⛓️ ON-CHAIN METHODS *\n\t ***********************************************************************/\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\tbuilder = new Builder(boostRelayUrl_);\n\t}\n\n\tfunction buyAdCallback(AdRequest calldata request, UnlockArgs calldata uArgs) external unlock(uArgs) {\n\t\trequests.push(request);\n\t\tnextId++;\n\t\temit RequestAdded(request.id, request.extra, request.blockLimit);\n\t}\n\n\tfunction buildCallback(\n\t\tbytes memory builderCall,\n\t\tbytes memory includedRequestB,\n\t\tbytes memory pendingRemovalsB,\n\t\tUnlockArgs calldata uArgs\n\t) external unlock(uArgs) {\n\t\tif (pendingRemovalsB.length > 0) {\n\t\t\tremoveRequests(pendingRemovalsB.export());\n\t\t}\n\t\tstring memory blockHash = handleBuilderCallback(address(builder), builderCall);\n\t\thandleIncludedRequest(includedRequestB, blockHash);\n\t}\n\n\tfunction requestsLength() public view returns (uint) {\n\t\treturn requests.length;\n\t}\n\n\t/**********************************************************************\n\t * 🔒 CONFIDENTIAL METHODS *\n\t ***********************************************************************/\n\n\tfunction confidentialConstructor() public view override onlyConfidential returns (bytes memory) {\n\t\treturn ConfidentialControl.confidentialConstructor();\n\t}\n\n\tfunction buyAd(uint64 blockLimit, string memory extra) external onlyConfidential returns (bytes memory) {\n\t\tbytes memory paymentBundle = this.fetchConfidentialBundleData();\n\t\t(,uint64 egp) = simulateBundleSafe(paymentBundle, true);\n\t\tcrequire(egp > 0, \"egp too low\");\n\t\tSuave.DataId paymentBidId = storePaymentBundle(paymentBundle);\n\t\tAdRequest memory request = AdRequest(nextId, extra, blockLimit, paymentBidId);\n\t\treturn abi.encodeWithSelector(this.buyAdCallback.selector, request, getUnlockPair());\n\t}\n\n\tfunction buildBlock(\n\t\tSuave.BuildBlockArgs memory blockArgs,\n\t\tuint64 blockHeight\n\t) public onlyConfidential returns (bytes memory) {\n\t\tcrequire(requests.length > 0, \"No requests\");\n\t\t(Offer memory bestOffer, bytes memory removals) = filterOffers(blockHeight);\n\t\tcrequire(bestOffer.egp > 0, \"No valid offers\");\n\n\t\tstoreBundleInPool(blockHeight, bestOffer);\n\t\tblockArgs.extra = bytes(bestOffer.extra);\n\t\t// Expect flow is ordered by egp; if one wants to fail payment they need higher egp\n\t\tbytes memory externalCallback = builder.buildFromPool(blockArgs, blockHeight);\n\n\t\treturn\n\t\t\tabi.encodeWithSelector(\n\t\t\t\tthis.buildCallback.selector,\n\t\t\t\texternalCallback,\n\t\t\t\tabi.encode(bestOffer.id, bestOffer.egp),\n\t\t\t\tremovals,\n\t\t\t\tgetUnlockPair()\n\t\t\t);\n\t}\n\n\t/**********************************************************************\n\t * 🛠️ INTERNAL METHODS *\n\t ***********************************************************************/\n\n\tfunction removeRequests(uint[] memory pendingRemovals) internal {\n\t\t// Assume that the pendingRemovals were added in ascending order\n\t\t// Assume that pendingRemovals.length <= requests.length\n\t\tfor (uint i = pendingRemovals.length; i > 0; --i) {\n\t\t\tuint indexToRemove = pendingRemovals[i - 1];\n\t\t\tuint requestId = requests[indexToRemove].id;\n\t\t\tif (indexToRemove < requests.length - 1) {\n\t\t\t\trequests[indexToRemove] = requests[requests.length - 1];\n\t\t\t}\n\t\t\trequests.pop();\n\t\t\temit RequestRemoved(requestId);\n\t\t}\n\t}\n\n\tfunction handleIncludedRequest(bytes memory includedRequestB, string memory blockHash) internal {\n\t\t(uint id, uint64 egp) = abi.decode(includedRequestB, (uint, uint64));\n\t\temit RequestIncluded(id, egp, blockHash);\n\t}\n\n\tfunction handleBuilderCallback(address target, bytes memory data) internal returns (string memory) {\n\t\t(bool success, bytes memory res) = target.call(data);\n\t\tcrequire(success, \"External call failed\");\n\t\treturn abi.decode(res, (string));\n\t}\n\n\tfunction storePaymentBundle(bytes memory paymentBundle) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](1);\n\t\tpeekers[0] = address(this);\n\t\tSuave.DataRecord memory paymentBid = Suave.newDataRecord(0, peekers, peekers, PB_NAMESPACE);\n\t\tSuave.confidentialStore(paymentBid.id, PB_NAMESPACE, paymentBundle);\n\t\treturn paymentBid.id;\n\t}\n\n\tfunction filterOffers(uint blockHeight) internal view returns (Offer memory bestOffer, bytes memory removals) {\n\t\tfor (uint i; i < requests.length; ++i) {\n\t\t\tAdRequest memory request = requests[i];\n\t\t\tif (request.blockLimit < blockHeight) {\n\t\t\t\tremovals = removals.append(i);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbytes memory paymentBundle = Suave.confidentialRetrieve(request.paymentBidId, PB_NAMESPACE);\n\t\t\t(bool success, uint64 egp) = simulateBundleSafe(paymentBundle, false);\n\t\t\tif (!success || egp == 0) {\n\t\t\t\tremovals = removals.append(i);\n\t\t\t} else if (egp > bestOffer.egp) {\n\t\t\t\tbestOffer = Offer(request.id, request.extra, egp, paymentBundle);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storeBundleInPool(uint64 blockHeight, Offer memory bestOffer) internal view {\n\t\taddress[] memory allowedPeekers = new address[](3);\n\t\tallowedPeekers[0] = address(builder);\n\t\tallowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\t\tallowedPeekers[2] = address(this);\n\t\tSuave.DataRecord memory paymentBundleBid = Suave.newDataRecord(\n\t\t\tblockHeight, \n\t\t\tallowedPeekers, \n\t\t\tallowedPeekers, \n\t\t\tEB_NAMESPACE\n\t\t);\n\t\tSuave.confidentialStore(paymentBundleBid.id, EB_NAMESPACE, bestOffer.paymentBundle);\n\t\tSuave.confidentialStore(paymentBundleBid.id, EB_SIM_NAMESPACE, abi.encode(bestOffer.egp));\n\t}\n}\n" + }, + "contracts/blockad/lib/Builder.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { EthBlockContract, Suave } from \"../../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"./SuaveContract.sol\";\n\n\ncontract Builder is EthBlockContract, SuaveContract {\n\tstring constant BB_NAMESPACE = \"blockad:v0:builderBid\";\n\tstring boostRelayUrl;\n\n\tevent RelaySubmission(bytes32 bidId);\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\tboostRelayUrl = boostRelayUrl_;\n\t}\n\n\tfunction buildAndEmitCallback(string memory blockHash, bytes32 id) external returns (string memory) {\n\t\temit RelaySubmission(id);\n\t\treturn blockHash;\n\t}\n\n\tfunction buildAndEmit(\n\t\tSuave.BuildBlockArgs memory blockArgs,\n\t\tuint64 blockHeight,\n\t\tSuave.DataId[] memory bids,\n\t\tstring memory namespace\n\t) public virtual override onlyConfidential returns (bytes memory) {\n\t\t(Suave.DataRecord memory blockBid, bytes memory builderBid) = this.doBuild(blockArgs, blockHeight, bids, namespace);\n\t\tstoreBuilderBid(blockBid.id, builderBid);\n\t\tsubmitToRelay(builderBid);\n\t\tstring memory blockHash = extractBlockHash(builderBid, blockArgs.slot);\n\t\treturn abi.encodeWithSelector(this.buildAndEmitCallback.selector, blockHash, keccak256(builderBid));\n\t}\n\n\tfunction submitBlock(uint slot) external view onlyConfidential returns (bytes memory) {\n\t\tbytes memory builderBid = Suave.confidentialInputs();\n\t\tsubmitToRelay(builderBid);\n\t\tstring memory blockHash = extractBlockHash(builderBid, slot);\n\t\treturn abi.encodeWithSelector(this.buildAndEmitCallback.selector, blockHash, keccak256(builderBid));\n\t}\n\n\tfunction submitToRelay(bytes memory builderBid) internal view {\n\t\t(bool success, bytes memory data) = Suave.SUBMIT_ETH_BLOCK_TO_RELAY\n\t\t\t.staticcall(abi.encode(boostRelayUrl, builderBid));\n\t\tif (!success) {\n\t\t\trevert SuaveErrorWithData(string(data), builderBid);\n\t\t}\n\t}\n\n\tfunction storeBuilderBid(Suave.DataId blockBidId, bytes memory builderBid) internal view {\n\t\taddress[] memory peekers = new address[](1);\n\t\tpeekers[0] = address(this);\n\t\tSuave.confidentialStore(blockBidId, BB_NAMESPACE, builderBid);\n\t}\n\n\t// Extract block-hash from stringified SubmitBlockRequest JSON object - method will fail if the struct changes!\n\tfunction extractBlockHash(bytes memory builderBid, uint slot) public pure returns (string memory) {\n\t\tuint resultBytesLen = 64;\n\t\tuint offset = 121 + decLen(slot);\n\t\tbytes memory result = new bytes(resultBytesLen);\n\t\tassembly {\n\t\t\tfor { let i:=32 } lt(i, add(resultBytesLen, 32)) { i:=add(i, 32) } {\n\t\t\t\tmstore(add(result, i), mload(add(builderBid, add(offset, i))))\n\t\t\t}\n\t\t}\n\t\treturn string(result);\n\t}\n\n\tfunction decLen(uint num) internal pure returns (uint count) {\n\t\tassembly {\n\t\t\tfor { let dec := 10 } true { dec := mul(dec, 10) } {\n\t\t\t\tcount := add(count, 1)\n\t\t\t\tswitch lt(num, dec)\n\t\t\t\t\tcase 1 { break }\n\t\t\t}\n\t\t}\n\t}\n}" + }, + "contracts/blockad/lib/ConfidentialControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { SuaveContract, Suave } from \"./SuaveContract.sol\";\n\n\nabstract contract ConfidentialControl is SuaveContract {\n\tstruct UnlockArgs {\n\t\tbytes32 key;\n\t\tbytes32 nextHash;\n\t}\n\n\tmodifier unlock(UnlockArgs calldata unlockPair) {\n\t\tcrequire(isValidKey(unlockPair.key), \"Invalid key\");\n\t\t_;\n\t\tpresentHash = unlockPair.nextHash;\n\t\tnonce++;\n\t}\n\n\tstring internal constant S_NAMESPACE = \"blockad:v0:secret\";\n\tSuave.DataId internal secretBidId;\n\tbytes32 internal presentHash;\n\tuint internal nonce;\n\n\t/**********************************************************************\n\t * ⛓️ ON-CHAIN METHODS *\n\t ***********************************************************************/\n\n\tfunction ccCallback(bytes32 nextHash, Suave.DataId sBidId) external {\n\t\tcrequire(!isInitialized(), \"Already initialized\");\n\t\tpresentHash = nextHash;\n\t\tsecretBidId = sBidId;\n\t}\n\n\tfunction isInitialized() public view returns (bool) {\n\t\treturn presentHash != 0;\n\t}\n\n\t/**********************************************************************\n\t * 🔒 CONFIDENTIAL METHODS *\n\t ***********************************************************************/\n\n\tfunction confidentialConstructor() public view virtual onlyConfidential returns (bytes memory) {\n\t\tcrequire(!isInitialized(), \"Already initialized\");\n\t\tbytes memory secret = Suave.confidentialInputs();\n\t\tSuave.DataId sBidId = storeSecret(secret);\n\t\tbytes32 nextHash = makeHash(abi.decode(secret, (bytes32)), nonce);\n\t\treturn abi.encodeWithSelector(this.ccCallback.selector, nextHash, sBidId);\n\t}\n\n\t/**********************************************************************\n\t * 🛠️ INTERNAL METHODS *\n\t ***********************************************************************/\n\n\tfunction storeSecret(bytes memory secret) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, secret);\n\t\treturn secretBid.id;\n\t}\n\n\tfunction isValidKey(bytes32 key) internal view returns (bool) {\n\t\treturn keccak256(abi.encode(key)) == presentHash;\n\t}\n\n\tfunction getUnlockPair() internal view returns (UnlockArgs memory) {\n\t\treturn UnlockArgs(getKey(nonce), getHash(nonce + 1));\n\t}\n\n\tfunction getHash(uint _nonce) internal view returns (bytes32) {\n\t\treturn keccak256(abi.encode(getKey(_nonce)));\n\t}\n\n\tfunction getKey(uint _nonce) internal view returns (bytes32) {\n\t\treturn makeKey(getSecret(), _nonce);\n\t}\n\n\tfunction makeHash(bytes32 secret, uint _nonce) internal pure returns (bytes32) {\n\t\treturn keccak256(abi.encode(makeKey(secret, _nonce)));\n\t}\n\n\tfunction makeKey(bytes32 secret, uint _nonce) internal pure returns (bytes32) {\n\t\treturn keccak256(abi.encode(secret, _nonce));\n\t}\n\n\tfunction getSecret() internal view returns (bytes32) {\n\t\tbytes memory secretB = Suave.confidentialRetrieve(secretBidId, S_NAMESPACE);\n\t\treturn abi.decode(secretB, (bytes32));\n\t}\n}\n" + }, + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/blockad/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.8;\n\n\nlibrary DynamicUintArray {\n\tfunction append(bytes memory a, uint e) internal pure returns (bytes memory) {\n\t\treturn bytes.concat(a, TypeConversion.toBytes(e));\n\t}\n\n\tfunction export(bytes memory a) internal pure returns (uint[] memory) {\n\t\treturn TypeConversion.toUints(a);\n\t}\n}\n\nlibrary TypeConversion {\n\tfunction toBytes(uint x) internal pure returns (bytes memory y) {\n\t\ty = new bytes(32);\n\t\tassembly {\n\t\t\tmstore(add(y, 32), x)\n\t\t}\n\t}\n\n\tfunction toUint(bytes memory x, uint offset) internal pure returns (uint y) {\n\t\tassembly {\n\t\t\ty := mload(add(x, offset))\n\t\t}\n\t}\n\n\tfunction toUints(bytes memory xs) internal pure returns (uint[] memory ys) {\n\t\tys = new uint[](xs.length / 32);\n\t\tfor (uint i = 0; i < xs.length / 32; i++) {\n\t\t\tys[i] = toUint(xs, i * 32 + 32);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n enum CryptoSignature {\n SECP256,\n BLS\n }\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto));\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, string memory signingKey) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport { floatToInt, trimStrEdges, getAddressForPk } from \"./lib/Utils.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n isInitialized = true;\n }\n\n function registerCallback(address _settlementContract) public {\n require(_settlementContract == settlementContract || settlementContract == address(0), \"Already registered\");\n settlementContract = _settlementContract;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\n }\n\n function queryAndSubmit(\n string memory ticker, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) external view onlyConfidential returns (uint) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum);\n return price;\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n string memory ticker,\n uint price, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) internal view {\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\n // sendBundle(signedTx, settlementBlockNum);\n sendRawTx(signedTx);\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: gasPrice,\n gas: 100_000,\n to: settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"updatePrice(string,uint256)\", ticker, price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}" + }, + "contracts/oracle/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\n// 🚨 THIS IS UNTESTED DEMO CODE - DONT USE IN PRODUCTION 🚨\n\n\npragma solidity ^0.8.8;\n\nimport '../../libraries/Suave.sol';\n\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Reset power of ten\n tenPower = 1;\n \n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/rigil/solcInputs/f3002e1c8db8b22e6d171da1d3b2b4ff.json b/deployments/rigil/solcInputs/f3002e1c8db8b22e6d171da1d3b2b4ff.json new file mode 100644 index 0000000..d85f0eb --- /dev/null +++ b/deployments/rigil/solcInputs/f3002e1c8db8b22e6d171da1d3b2b4ff.json @@ -0,0 +1,80 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/BlockAdV1.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { AnyBundleContract, EthBlockBidSenderContract, Suave } from \"../standard_peekers/bids.sol\";\n\n\ncontract BlockAdAuctionV1 is AnyBundleContract {\n\n\tstruct AdBid {\n\t\tstring extra; \n\t\tSuave.DataId paymentBidId;\n\t\tuint blockHeight;\n\t}\n\n\tstruct EffectiveAdBid {\n\t\tstring extra;\n\t\tuint64 egp;\n\t\tbytes paymentBundle;\n\t}\n\n\tevent AdBidEvent(\n\t\tstring extra,\n\t\tuint blockNum\n\t);\n\n\tmapping(uint => AdBid[]) public blockToBid;\n\tEthBlockBidSenderContract public builder;\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\t// Make sure the builder contract cannot abuse the confidential payment bundle\n\t\tbuilder = new EthBlockBidSenderContract(boostRelayUrl_);\n\t}\n\n\t// ON-CHAIN METHODS\n\n\tfunction buyAdCallback(AdBid[] memory bids) external {\n\t\tfor (uint i = 0; i < bids.length; ++i) {\n\t\t\tuint blockNum = bids[i].blockHeight;\n\t\t\tblockToBid[blockNum].push(bids[i]);\n\t\t\t// todo: add some form of an id to the bid\n\t\t\temit AdBidEvent(bids[i].extra, blockNum);\n\t\t}\n\t}\n\n\t// CONFIDENTIAL METHODS\n\n\tfunction buyAd(\n\t\tuint64 blockStart, \n\t\tuint64 range, \n\t\tstring memory extra\n\t) external returns (bytes memory) {\n\t\trequire(Suave.isConfidential(), \"Not confidential\");\n\t\t// Check payment is valid for the latest state\n\t\tbytes memory paymentBundle = this.fetchConfidentialBundleData();\n\t\trequire(Suave.simulateBundle(paymentBundle) != 0, \"Initial sim check failed\");\n\t\t\n\t\taddress[] memory allowedPeekers = new address[](1);\n\t\tallowedPeekers[0] = address(this);\n\n\t\tAdBid[] memory bids = new AdBid[](range);\n\t\tfor (uint64 b = blockStart; b < blockStart+range; b++) {\n\t\t\t// Store payment bundle\n\t\t\tSuave.DataRecord memory paymentBid = Suave.newDataRecord(0, allowedPeekers, allowedPeekers, \"blockad:v0:paymentBundle\");\n\t\t\tSuave.confidentialStore(paymentBid.id, \"blockad:v0:paymentBundle\", paymentBundle);\n\t\t\t// Prepare bid data to be commited on-chain\n\t\t\tbids[b-blockStart] = AdBid(extra, paymentBid.id, b);\n\t\t}\n\t\treturn abi.encodeWithSelector(this.buyAdCallback.selector, bids);\n\t}\n\n\tfunction buildBlock(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n\t\trequire(Suave.isConfidential());\n\n\t\tAdBid[] storage blockBids = blockToBid[blockHeight];\n\t\trequire(blockBids.length > 0, \"No bids\");\n\n\t\tEffectiveAdBid memory bestOffer;\n\t\tfor (uint i = 0; i < blockBids.length; ++i) {\n\t\t\tbytes memory paymentBundle = Suave.confidentialRetrieve(\n\t\t\t\tblockBids[i].paymentBidId, \n\t\t\t\t\"blockad:v0:paymentBundle\"\n\t\t\t);\n\t\t\tuint64 egp = Suave.simulateBundle(paymentBundle);\n\t\t\tif (egp > bestOffer.egp)\n\t\t\t\tbestOffer = EffectiveAdBid(blockBids[i].extra, egp, paymentBundle);\n\t\t\t// todo: if egp == 0, delete all of their bids for the next blocks (when someone wins an ad, discard their subsequent(pending) bids)\n\t\t}\n\t\tdelete blockToBid[blockHeight];\n\n\t\t// Prep for block building - include extra & payment bundle\n\t\tif (bestOffer.egp > 0)\n\t\t\tblockArgs.extra = bytes(bestOffer.extra);\n\t\t// Expect the payment on top; if someone wants to fail the payment with other txs they have to have higher egp than the payment tx\n\t\taddress[] memory allowedPeekers = new address[](3);\n\t\tallowedPeekers[0] = address(builder);\n\t\tallowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\t\tallowedPeekers[2] = address(this);\n\t\tSuave.DataRecord memory paymentBundleBid = Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:ethBundles\");\n\t\tSuave.confidentialStore(paymentBundleBid.id, \"default:v0:ethBundles\", bestOffer.paymentBundle);\n\t\tSuave.confidentialStore(paymentBundleBid.id, \"default:v0:ethBundleSimResults\", abi.encode(bestOffer.egp));\n\t\t\n\t\treturn builder.buildFromPool(blockArgs, blockHeight);\n\t}\n\n}\n" + }, + "contracts/blockad/BlockAdV2.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { ConfidentialControl } from \"./lib/ConfidentialControl.sol\";\nimport { DynamicUintArray } from \"./lib/Utils.sol\";\nimport { Builder } from \"./lib/Builder.sol\";\n\n\ncontract BlockAdAuctionV2 is AnyBundleContract, ConfidentialControl {\n\tusing DynamicUintArray for bytes;\n\n\tstruct AdRequest {\n\t\tuint id;\n\t\tstring extra;\n\t\tuint blockLimit;\n\t\tSuave.DataId paymentBidId;\n\t}\n\tstruct Offer {\n\t\tuint id;\n\t\tstring extra;\n\t\tuint64 egp;\n\t\tbytes paymentBundle;\n\t}\n\n\tevent RequestAdded(uint indexed id, string extra, uint blockLimit);\n\tevent RequestRemoved(uint indexed id);\n\tevent RequestIncluded(uint indexed id, uint64 egp, string blockHash);\n\n\tstring internal constant PB_NAMESPACE = \"blockad:v0:paymentBundle\";\n\tstring internal constant EB_NAMESPACE = \"default:v0:ethBundles\";\n\tstring internal constant EB_SIM_NAMESPACE = \"default:v0:ethBundleSimResults\";\n\tBuilder public builder;\n\tAdRequest[] public requests;\n\tuint public nextId;\n\n\t/**********************************************************************\n\t * ⛓️ ON-CHAIN METHODS *\n\t ***********************************************************************/\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\tbuilder = new Builder(boostRelayUrl_);\n\t}\n\n\tfunction buyAdCallback(AdRequest calldata request, UnlockArgs calldata uArgs) external unlock(uArgs) {\n\t\trequests.push(request);\n\t\tnextId++;\n\t\temit RequestAdded(request.id, request.extra, request.blockLimit);\n\t}\n\n\tfunction buildCallback(\n\t\tbytes memory builderCall,\n\t\tbytes memory includedRequestB,\n\t\tbytes memory pendingRemovalsB,\n\t\tUnlockArgs calldata uArgs\n\t) external unlock(uArgs) {\n\t\tif (pendingRemovalsB.length > 0) {\n\t\t\tremoveRequests(pendingRemovalsB.export());\n\t\t}\n\t\tstring memory blockHash = handleBuilderCallback(address(builder), builderCall);\n\t\thandleIncludedRequest(includedRequestB, blockHash);\n\t}\n\n\tfunction requestsLength() public view returns (uint) {\n\t\treturn requests.length;\n\t}\n\n\t/**********************************************************************\n\t * 🔒 CONFIDENTIAL METHODS *\n\t ***********************************************************************/\n\n\tfunction confidentialConstructor() public view override onlyConfidential returns (bytes memory) {\n\t\treturn ConfidentialControl.confidentialConstructor();\n\t}\n\n\tfunction buyAd(uint64 blockLimit, string memory extra) external onlyConfidential returns (bytes memory) {\n\t\tbytes memory paymentBundle = this.fetchConfidentialBundleData();\n\t\t(,uint64 egp) = simulateBundleSafe(paymentBundle, true);\n\t\tcrequire(egp > 0, \"egp too low\");\n\t\tSuave.DataId paymentBidId = storePaymentBundle(paymentBundle);\n\t\tAdRequest memory request = AdRequest(nextId, extra, blockLimit, paymentBidId);\n\t\treturn abi.encodeWithSelector(this.buyAdCallback.selector, request, getUnlockPair());\n\t}\n\n\tfunction buildBlock(\n\t\tSuave.BuildBlockArgs memory blockArgs,\n\t\tuint64 blockHeight\n\t) public onlyConfidential returns (bytes memory) {\n\t\tcrequire(requests.length > 0, \"No requests\");\n\t\t(Offer memory bestOffer, bytes memory removals) = filterOffers(blockHeight);\n\t\tcrequire(bestOffer.egp > 0, \"No valid offers\");\n\n\t\tstoreBundleInPool(blockHeight, bestOffer);\n\t\tblockArgs.extra = bytes(bestOffer.extra);\n\t\t// Expect flow is ordered by egp; if one wants to fail payment they need higher egp\n\t\tbytes memory externalCallback = builder.buildFromPool(blockArgs, blockHeight);\n\n\t\treturn\n\t\t\tabi.encodeWithSelector(\n\t\t\t\tthis.buildCallback.selector,\n\t\t\t\texternalCallback,\n\t\t\t\tabi.encode(bestOffer.id, bestOffer.egp),\n\t\t\t\tremovals,\n\t\t\t\tgetUnlockPair()\n\t\t\t);\n\t}\n\n\t/**********************************************************************\n\t * 🛠️ INTERNAL METHODS *\n\t ***********************************************************************/\n\n\tfunction removeRequests(uint[] memory pendingRemovals) internal {\n\t\t// Assume that the pendingRemovals were added in ascending order\n\t\t// Assume that pendingRemovals.length <= requests.length\n\t\tfor (uint i = pendingRemovals.length; i > 0; --i) {\n\t\t\tuint indexToRemove = pendingRemovals[i - 1];\n\t\t\tuint requestId = requests[indexToRemove].id;\n\t\t\tif (indexToRemove < requests.length - 1) {\n\t\t\t\trequests[indexToRemove] = requests[requests.length - 1];\n\t\t\t}\n\t\t\trequests.pop();\n\t\t\temit RequestRemoved(requestId);\n\t\t}\n\t}\n\n\tfunction handleIncludedRequest(bytes memory includedRequestB, string memory blockHash) internal {\n\t\t(uint id, uint64 egp) = abi.decode(includedRequestB, (uint, uint64));\n\t\temit RequestIncluded(id, egp, blockHash);\n\t}\n\n\tfunction handleBuilderCallback(address target, bytes memory data) internal returns (string memory) {\n\t\t(bool success, bytes memory res) = target.call(data);\n\t\tcrequire(success, \"External call failed\");\n\t\treturn abi.decode(res, (string));\n\t}\n\n\tfunction storePaymentBundle(bytes memory paymentBundle) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](1);\n\t\tpeekers[0] = address(this);\n\t\tSuave.DataRecord memory paymentBid = Suave.newDataRecord(0, peekers, peekers, PB_NAMESPACE);\n\t\tSuave.confidentialStore(paymentBid.id, PB_NAMESPACE, paymentBundle);\n\t\treturn paymentBid.id;\n\t}\n\n\tfunction filterOffers(uint blockHeight) internal view returns (Offer memory bestOffer, bytes memory removals) {\n\t\tfor (uint i; i < requests.length; ++i) {\n\t\t\tAdRequest memory request = requests[i];\n\t\t\tif (request.blockLimit < blockHeight) {\n\t\t\t\tremovals = removals.append(i);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbytes memory paymentBundle = Suave.confidentialRetrieve(request.paymentBidId, PB_NAMESPACE);\n\t\t\t(bool success, uint64 egp) = simulateBundleSafe(paymentBundle, false);\n\t\t\tif (!success || egp == 0) {\n\t\t\t\tremovals = removals.append(i);\n\t\t\t} else if (egp > bestOffer.egp) {\n\t\t\t\tbestOffer = Offer(request.id, request.extra, egp, paymentBundle);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction storeBundleInPool(uint64 blockHeight, Offer memory bestOffer) internal view {\n\t\taddress[] memory allowedPeekers = new address[](3);\n\t\tallowedPeekers[0] = address(builder);\n\t\tallowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\t\tallowedPeekers[2] = address(this);\n\t\tSuave.DataRecord memory paymentBundleBid = Suave.newDataRecord(\n\t\t\tblockHeight, \n\t\t\tallowedPeekers, \n\t\t\tallowedPeekers, \n\t\t\tEB_NAMESPACE\n\t\t);\n\t\tSuave.confidentialStore(paymentBundleBid.id, EB_NAMESPACE, bestOffer.paymentBundle);\n\t\tSuave.confidentialStore(paymentBundleBid.id, EB_SIM_NAMESPACE, abi.encode(bestOffer.egp));\n\t}\n}\n" + }, + "contracts/blockad/lib/Builder.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { EthBlockContract, Suave } from \"../../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"./SuaveContract.sol\";\n\n\ncontract Builder is EthBlockContract, SuaveContract {\n\tstring constant BB_NAMESPACE = \"blockad:v0:builderBid\";\n\tstring boostRelayUrl;\n\n\tevent RelaySubmission(bytes32 bidId);\n\n\tconstructor(string memory boostRelayUrl_) {\n\t\tboostRelayUrl = boostRelayUrl_;\n\t}\n\n\tfunction buildAndEmitCallback(string memory blockHash, bytes32 id) external returns (string memory) {\n\t\temit RelaySubmission(id);\n\t\treturn blockHash;\n\t}\n\n\tfunction buildAndEmit(\n\t\tSuave.BuildBlockArgs memory blockArgs,\n\t\tuint64 blockHeight,\n\t\tSuave.DataId[] memory bids,\n\t\tstring memory namespace\n\t) public virtual override onlyConfidential returns (bytes memory) {\n\t\t(Suave.DataRecord memory blockBid, bytes memory builderBid) = this.doBuild(blockArgs, blockHeight, bids, namespace);\n\t\tstoreBuilderBid(blockBid.id, builderBid);\n\t\tsubmitToRelay(builderBid);\n\t\tstring memory blockHash = extractBlockHash(builderBid, blockArgs.slot);\n\t\treturn abi.encodeWithSelector(this.buildAndEmitCallback.selector, blockHash, keccak256(builderBid));\n\t}\n\n\tfunction submitBlock(uint slot) external view onlyConfidential returns (bytes memory) {\n\t\tbytes memory builderBid = Suave.confidentialInputs();\n\t\tsubmitToRelay(builderBid);\n\t\tstring memory blockHash = extractBlockHash(builderBid, slot);\n\t\treturn abi.encodeWithSelector(this.buildAndEmitCallback.selector, blockHash, keccak256(builderBid));\n\t}\n\n\tfunction submitToRelay(bytes memory builderBid) internal view {\n\t\t(bool success, bytes memory data) = Suave.SUBMIT_ETH_BLOCK_TO_RELAY\n\t\t\t.staticcall(abi.encode(boostRelayUrl, builderBid));\n\t\tif (!success) {\n\t\t\trevert SuaveErrorWithData(string(data), builderBid);\n\t\t}\n\t}\n\n\tfunction storeBuilderBid(Suave.DataId blockBidId, bytes memory builderBid) internal view {\n\t\taddress[] memory peekers = new address[](1);\n\t\tpeekers[0] = address(this);\n\t\tSuave.confidentialStore(blockBidId, BB_NAMESPACE, builderBid);\n\t}\n\n\t// Extract block-hash from stringified SubmitBlockRequest JSON object - method will fail if the struct changes!\n\tfunction extractBlockHash(bytes memory builderBid, uint slot) public pure returns (string memory) {\n\t\tuint resultBytesLen = 64;\n\t\tuint offset = 121 + decLen(slot);\n\t\tbytes memory result = new bytes(resultBytesLen);\n\t\tassembly {\n\t\t\tfor { let i:=32 } lt(i, add(resultBytesLen, 32)) { i:=add(i, 32) } {\n\t\t\t\tmstore(add(result, i), mload(add(builderBid, add(offset, i))))\n\t\t\t}\n\t\t}\n\t\treturn string(result);\n\t}\n\n\tfunction decLen(uint num) internal pure returns (uint count) {\n\t\tassembly {\n\t\t\tfor { let dec := 10 } true { dec := mul(dec, 10) } {\n\t\t\t\tcount := add(count, 1)\n\t\t\t\tswitch lt(num, dec)\n\t\t\t\t\tcase 1 { break }\n\t\t\t}\n\t\t}\n\t}\n}" + }, + "contracts/blockad/lib/ConfidentialControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { SuaveContract, Suave } from \"./SuaveContract.sol\";\n\n\nabstract contract ConfidentialControl is SuaveContract {\n\tstruct UnlockArgs {\n\t\tbytes32 key;\n\t\tbytes32 nextHash;\n\t}\n\n\tmodifier unlock(UnlockArgs calldata unlockPair) {\n\t\tcrequire(isValidKey(unlockPair.key), \"Invalid key\");\n\t\t_;\n\t\tpresentHash = unlockPair.nextHash;\n\t\tnonce++;\n\t}\n\n\tstring internal constant S_NAMESPACE = \"blockad:v0:secret\";\n\tSuave.DataId internal secretBidId;\n\tbytes32 internal presentHash;\n\tuint internal nonce;\n\n\t/**********************************************************************\n\t * ⛓️ ON-CHAIN METHODS *\n\t ***********************************************************************/\n\n\tfunction ccCallback(bytes32 nextHash, Suave.DataId sBidId) external {\n\t\tcrequire(!isInitialized(), \"Already initialized\");\n\t\tpresentHash = nextHash;\n\t\tsecretBidId = sBidId;\n\t}\n\n\tfunction isInitialized() public view returns (bool) {\n\t\treturn presentHash != 0;\n\t}\n\n\t/**********************************************************************\n\t * 🔒 CONFIDENTIAL METHODS *\n\t ***********************************************************************/\n\n\tfunction confidentialConstructor() public view virtual onlyConfidential returns (bytes memory) {\n\t\tcrequire(!isInitialized(), \"Already initialized\");\n\t\tbytes memory secret = Suave.confidentialInputs();\n\t\tSuave.DataId sBidId = storeSecret(secret);\n\t\tbytes32 nextHash = makeHash(abi.decode(secret, (bytes32)), nonce);\n\t\treturn abi.encodeWithSelector(this.ccCallback.selector, nextHash, sBidId);\n\t}\n\n\t/**********************************************************************\n\t * 🛠️ INTERNAL METHODS *\n\t ***********************************************************************/\n\n\tfunction storeSecret(bytes memory secret) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, secret);\n\t\treturn secretBid.id;\n\t}\n\n\tfunction isValidKey(bytes32 key) internal view returns (bool) {\n\t\treturn keccak256(abi.encode(key)) == presentHash;\n\t}\n\n\tfunction getUnlockPair() internal view returns (UnlockArgs memory) {\n\t\treturn UnlockArgs(getKey(nonce), getHash(nonce + 1));\n\t}\n\n\tfunction getHash(uint _nonce) internal view returns (bytes32) {\n\t\treturn keccak256(abi.encode(getKey(_nonce)));\n\t}\n\n\tfunction getKey(uint _nonce) internal view returns (bytes32) {\n\t\treturn makeKey(getSecret(), _nonce);\n\t}\n\n\tfunction makeHash(bytes32 secret, uint _nonce) internal pure returns (bytes32) {\n\t\treturn keccak256(abi.encode(makeKey(secret, _nonce)));\n\t}\n\n\tfunction makeKey(bytes32 secret, uint _nonce) internal pure returns (bytes32) {\n\t\treturn keccak256(abi.encode(secret, _nonce));\n\t}\n\n\tfunction getSecret() internal view returns (bytes32) {\n\t\tbytes memory secretB = Suave.confidentialRetrieve(secretBidId, S_NAMESPACE);\n\t\treturn abi.decode(secretB, (bytes32));\n\t}\n}\n" + }, + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/blockad/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.8;\n\n\nlibrary DynamicUintArray {\n\tfunction append(bytes memory a, uint e) internal pure returns (bytes memory) {\n\t\treturn bytes.concat(a, TypeConversion.toBytes(e));\n\t}\n\n\tfunction export(bytes memory a) internal pure returns (uint[] memory) {\n\t\treturn TypeConversion.toUints(a);\n\t}\n}\n\nlibrary TypeConversion {\n\tfunction toBytes(uint x) internal pure returns (bytes memory y) {\n\t\ty = new bytes(32);\n\t\tassembly {\n\t\t\tmstore(add(y, 32), x)\n\t\t}\n\t}\n\n\tfunction toUint(bytes memory x, uint offset) internal pure returns (uint y) {\n\t\tassembly {\n\t\t\ty := mload(add(x, offset))\n\t\t}\n\t}\n\n\tfunction toUints(bytes memory xs) internal pure returns (uint[] memory ys) {\n\t\tys = new uint[](xs.length / 32);\n\t\tfor (uint i = 0; i < xs.length / 32; i++) {\n\t\t\tys[i] = toUint(xs, i * 32 + 32);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n enum CryptoSignature {\n SECP256,\n BLS\n }\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto));\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, CryptoSignature crypto, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, crypto, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport { floatToInt, trimStrEdges, getAddressForPk } from \"./lib/Utils.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n isInitialized = true;\n }\n\n function registerCallback(address _settlementContract) public {\n require(_settlementContract == settlementContract || settlementContract == address(0), \"Already registered\");\n settlementContract = _settlementContract;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\n }\n\n function queryAndSubmit(\n string memory ticker, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) external view onlyConfidential returns (uint) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum);\n return price;\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n string memory ticker,\n uint price, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum\n ) internal view {\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\n // sendBundle(signedTx, settlementBlockNum);\n sendRawTx(signedTx);\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: gasPrice,\n gas: 100_000,\n to: settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"updatePrice(string,uint256)\", ticker, price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}" + }, + "contracts/oracle/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\n// 🚨 THIS IS UNTESTED DEMO CODE - DONT USE IN PRODUCTION 🚨\n\n\npragma solidity ^0.8.8;\n\nimport '../../libraries/Suave.sol';\n\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Reset power of ten\n tenPower = 1;\n \n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), Suave.CryptoSignature.SECP256, pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/deployments/rigil/solcInputs/feb7a997c83638df5a6e60425a049b5a.json b/deployments/rigil/solcInputs/feb7a997c83638df5a6e60425a049b5a.json new file mode 100644 index 0000000..1c1ee92 --- /dev/null +++ b/deployments/rigil/solcInputs/feb7a997c83638df5a6e60425a049b5a.json @@ -0,0 +1,65 @@ +{ + "language": "Solidity", + "sources": { + "contracts/blockad/lib/SuaveContract.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.8;\n\nimport { Suave } from \"../../standard_peekers/bids.sol\";\n\n\nabstract contract SuaveContract {\n\terror SuaveError(string message);\n\terror SuaveErrorWithData(string message, bytes data);\n\n\tmodifier onlyConfidential() {\n\t\tcrequire(Suave.isConfidential(), \"Not confidential\");\n\t\t_;\n\t}\n\n\tfunction simulateBundleSafe(bytes memory bundle, bool doRevert) internal view returns (bool valid, uint64 egp) {\n\t\t(bool success, bytes memory d) = Suave.SIMULATE_BUNDLE.staticcall{ gas: 20_000 }(abi.encode(bundle));\n\t\tcrequire(!doRevert || success, string(d));\n\t\tif (success) {\n\t\t\treturn (true, abi.decode(d, (uint64)));\n\t\t}\n\t}\n\n\tfunction crequire(bool condition, string memory message) internal pure {\n\t\tif (!condition) {\n\t\t\trevert SuaveError(message);\n\t\t}\n\t}\n}\n" + }, + "contracts/libraries/Bundle.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/protocols/Bundle.sol\n\n\n// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./Suave.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n// https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_sendbundle\nlibrary Bundle {\n struct BundleObj {\n uint64 blockNumber;\n uint64 minTimestamp;\n uint64 maxTimestamp;\n bytes[] txns;\n }\n\n function sendBundle(string memory url, BundleObj memory bundle) internal view returns (bytes memory) {\n Suave.HttpRequest memory request = encodeBundle(bundle);\n request.url = url;\n return Suave.doHTTPRequest(request);\n }\n\n function encodeBundle(BundleObj memory args) internal pure returns (Suave.HttpRequest memory) {\n require(args.txns.length > 0, \"Bundle: no txns\");\n\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(args.blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < args.txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(args.txns[i]), '\"');\n if (i < args.txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n if (args.minTimestamp > 0) {\n params = abi.encodePacked(params, ', \"minTimestamp\": ', LibString.toString(args.minTimestamp));\n }\n if (args.maxTimestamp > 0) {\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n }\n params = abi.encodePacked(params, ', \"maxTimestamp\": ', LibString.toString(args.maxTimestamp));\n params = abi.encodePacked(params, \"}\");\n\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendBundle\",\"params\":[', params, '],\"id\":1}');\n\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = true;\n\n return request;\n }\n}" + }, + "contracts/libraries/RLPWriter.sol": { + "content": "// Source: https://github.com/flashbots/suave-std/blob/main/src/utils/RLPWriter.sol\n\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode\n * @title RLPWriter\n * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's\n * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor\n * modifications to improve legibility.\n */\nlibrary RLPWriter {\n /**\n * @notice RLP encodes a byte string.\n *\n * @param _in The byte string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeBytes(bytes memory _in) internal pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_in.length == 1 && uint8(_in[0]) < 128) {\n encoded = _in;\n } else {\n encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);\n }\n\n return encoded;\n }\n\n /**\n * @notice RLP encodes a list of RLP encoded byte byte strings.\n *\n * @param _in The list of RLP encoded byte strings.\n *\n * @return The RLP encoded list of items in bytes.\n */\n function writeList(bytes[] memory _in) internal pure returns (bytes memory) {\n bytes memory list = _flatten(_in);\n return abi.encodePacked(_writeLength(list.length, 192), list);\n }\n\n /**\n * @notice RLP encodes a string.\n *\n * @param _in The string to encode.\n *\n * @return The RLP encoded string in bytes.\n */\n function writeString(string memory _in) internal pure returns (bytes memory) {\n return writeBytes(bytes(_in));\n }\n\n /**\n * @notice RLP encodes an address.\n *\n * @param _in The address to encode.\n *\n * @return The RLP encoded address in bytes.\n */\n function writeAddress(address _in) internal pure returns (bytes memory) {\n return writeBytes(abi.encodePacked(_in));\n }\n\n /**\n * @notice RLP encodes a uint.\n *\n * @param _in The uint256 to encode.\n *\n * @return The RLP encoded uint256 in bytes.\n */\n function writeUint(uint256 _in) internal pure returns (bytes memory) {\n return writeBytes(_toBinary(_in));\n }\n\n /**\n * @notice RLP encodes a bool.\n *\n * @param _in The bool to encode.\n *\n * @return The RLP encoded bool in bytes.\n */\n function writeBool(bool _in) internal pure returns (bytes memory) {\n bytes memory encoded = new bytes(1);\n encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));\n return encoded;\n }\n\n /**\n * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55.\n *\n * @param _len The length of the string or the payload.\n * @param _offset 128 if item is string, 192 if item is list.\n *\n * @return RLP encoded bytes.\n */\n function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {\n bytes memory encoded;\n\n if (_len < 56) {\n encoded = new bytes(1);\n encoded[0] = bytes1(uint8(_len) + uint8(_offset));\n } else {\n uint256 lenLen;\n uint256 i = 1;\n while (_len / i != 0) {\n lenLen++;\n i *= 256;\n }\n\n encoded = new bytes(lenLen + 1);\n encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);\n for (i = 1; i <= lenLen; i++) {\n encoded[i] = bytes1(uint8((_len / (256 ** (lenLen - i))) % 256));\n }\n }\n\n return encoded;\n }\n\n /**\n * @notice Encode integer in big endian binary form with no leading zeroes.\n *\n * @param _x The integer to encode.\n *\n * @return RLP encoded bytes.\n */\n function _toBinary(uint256 _x) private pure returns (bytes memory) {\n bytes memory b = abi.encodePacked(_x);\n\n uint256 i = 0;\n for (; i < 32; i++) {\n if (b[i] != 0) {\n break;\n }\n }\n\n bytes memory res = new bytes(32 - i);\n for (uint256 j = 0; j < res.length; j++) {\n res[j] = b[i++];\n }\n\n return res;\n }\n\n /**\n * @custom:attribution https://github.com/Arachnid/solidity-stringutils\n * @notice Copies a piece of memory to another location.\n *\n * @param _dest Destination location.\n * @param _src Source location.\n * @param _len Length of memory to copy.\n */\n function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure {\n uint256 dest = _dest;\n uint256 src = _src;\n uint256 len = _len;\n\n for (; len >= 32; len -= 32) {\n assembly {\n mstore(dest, mload(src))\n }\n dest += 32;\n src += 32;\n }\n\n uint256 mask;\n unchecked {\n mask = 256 ** (32 - len) - 1;\n }\n assembly {\n let srcpart := and(mload(src), not(mask))\n let destpart := and(mload(dest), mask)\n mstore(dest, or(destpart, srcpart))\n }\n }\n\n /**\n * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder\n * @notice Flattens a list of byte strings into one byte string.\n *\n * @param _list List of byte strings to flatten.\n *\n * @return The flattened byte string.\n */\n function _flatten(bytes[] memory _list) private pure returns (bytes memory) {\n if (_list.length == 0) {\n return new bytes(0);\n }\n\n uint256 len;\n uint256 i = 0;\n for (; i < _list.length; i++) {\n len += _list[i].length;\n }\n\n bytes memory flattened = new bytes(len);\n uint256 flattenedPtr;\n assembly {\n flattenedPtr := add(flattened, 0x20)\n }\n\n for (i = 0; i < _list.length; i++) {\n bytes memory item = _list[i];\n\n uint256 listPtr;\n assembly {\n listPtr := add(item, 0x20)\n }\n\n _memcpy(flattenedPtr, listPtr, item.length);\n flattenedPtr += _list[i].length;\n }\n\n return flattened;\n }\n}" + }, + "contracts/libraries/Suave.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.8;\n\nlibrary Suave {\n error PeekerReverted(address, bytes);\n\n enum CryptoSignature {\n SECP256,\n BLS\n }\n\n type DataId is bytes16;\n\n struct BuildBlockArgs {\n uint64 slot;\n bytes proposerPubkey;\n bytes32 parent;\n uint64 timestamp;\n address feeRecipient;\n uint64 gasLimit;\n bytes32 random;\n Withdrawal[] withdrawals;\n bytes extra;\n bytes32 beaconRoot;\n bool fillPending;\n }\n\n struct DataRecord {\n DataId id;\n DataId salt;\n uint64 decryptionCondition;\n address[] allowedPeekers;\n address[] allowedStores;\n string version;\n }\n\n struct HttpRequest {\n string url;\n string method;\n string[] headers;\n bytes body;\n bool withFlashbotsSignature;\n }\n\n struct SimulateTransactionResult {\n uint64 egp;\n SimulatedLog[] logs;\n bool success;\n string error;\n }\n\n struct SimulatedLog {\n bytes data;\n address addr;\n bytes32[] topics;\n }\n\n struct Withdrawal {\n uint64 index;\n uint64 validator;\n address Address;\n uint64 amount;\n }\n\n address public constant ANYALLOWED = 0xC8df3686b4Afb2BB53e60EAe97EF043FE03Fb829;\n\n address public constant IS_CONFIDENTIAL_ADDR = 0x0000000000000000000000000000000042010000;\n\n address public constant BUILD_ETH_BLOCK = 0x0000000000000000000000000000000042100001;\n\n address public constant CONFIDENTIAL_INPUTS = 0x0000000000000000000000000000000042010001;\n\n address public constant CONFIDENTIAL_RETRIEVE = 0x0000000000000000000000000000000042020001;\n\n address public constant CONFIDENTIAL_STORE = 0x0000000000000000000000000000000042020000;\n\n address public constant DO_HTTPREQUEST = 0x0000000000000000000000000000000043200002;\n\n address public constant ETHstaticcall = 0x0000000000000000000000000000000042100003;\n\n address public constant EXTRACT_HINT = 0x0000000000000000000000000000000042100037;\n\n address public constant FETCH_DATA_RECORDS = 0x0000000000000000000000000000000042030001;\n\n address public constant FILL_MEV_SHARE_BUNDLE = 0x0000000000000000000000000000000043200001;\n\n address public constant NEW_BUILDER = 0x0000000000000000000000000000000053200001;\n\n address public constant NEW_DATA_RECORD = 0x0000000000000000000000000000000042030000;\n\n address public constant PRIVATE_KEY_GEN = 0x0000000000000000000000000000000053200003;\n\n address public constant SIGN_ETH_TRANSACTION = 0x0000000000000000000000000000000040100001;\n\n address public constant SIGN_MESSAGE = 0x0000000000000000000000000000000040100003;\n\n address public constant SIMULATE_BUNDLE = 0x0000000000000000000000000000000042100000;\n\n address public constant SIMULATE_TRANSACTION = 0x0000000000000000000000000000000053200002;\n\n address public constant SUBMIT_BUNDLE_JSON_RPC = 0x0000000000000000000000000000000043000001;\n\n address public constant SUBMIT_ETH_BLOCK_TO_RELAY = 0x0000000000000000000000000000000042100002;\n\n // Returns whether execution is off- or on-chain\n function isConfidential() internal view returns (bool b) {\n (bool success, bytes memory isConfidentialBytes) = IS_CONFIDENTIAL_ADDR.staticcall(\"\");\n if (!success) {\n revert PeekerReverted(IS_CONFIDENTIAL_ADDR, isConfidentialBytes);\n }\n assembly {\n // Load the length of data (first 32 bytes)\n let len := mload(isConfidentialBytes)\n // Load the data after 32 bytes, so add 0x20\n b := mload(add(isConfidentialBytes, 0x20))\n }\n }\n\n function buildEthBlock(BuildBlockArgs memory blockArgs, DataId dataId, string memory namespace)\n internal\n view\n returns (bytes memory, bytes memory)\n {\n (bool success, bytes memory data) = BUILD_ETH_BLOCK.staticcall(abi.encode(blockArgs, dataId, namespace));\n if (!success) {\n revert PeekerReverted(BUILD_ETH_BLOCK, data);\n }\n\n return abi.decode(data, (bytes, bytes));\n }\n\n function confidentialInputs() internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_INPUTS.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_INPUTS, data);\n }\n\n return data;\n }\n\n function confidentialRetrieve(DataId dataId, string memory key) internal view returns (bytes memory) {\n (bool success, bytes memory data) = CONFIDENTIAL_RETRIEVE.staticcall(abi.encode(dataId, key));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_RETRIEVE, data);\n }\n\n return data;\n }\n\n function confidentialStore(DataId dataId, string memory key, bytes memory value) internal view {\n (bool success, bytes memory data) = CONFIDENTIAL_STORE.staticcall(abi.encode(dataId, key, value));\n if (!success) {\n revert PeekerReverted(CONFIDENTIAL_STORE, data);\n }\n }\n\n function doHTTPRequest(HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = DO_HTTPREQUEST.staticcall(abi.encode(request));\n if (!success) {\n revert PeekerReverted(DO_HTTPREQUEST, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function ethstaticcall(address contractAddr, bytes memory input1) internal view returns (bytes memory) {\n (bool success, bytes memory data) = ETHstaticcall.staticcall(abi.encode(contractAddr, input1));\n if (!success) {\n revert PeekerReverted(ETHstaticcall, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function extractHint(bytes memory bundleData) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = EXTRACT_HINT.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(EXTRACT_HINT, data);\n }\n\n return data;\n }\n\n function fetchDataRecords(uint64 cond, string memory namespace) internal view returns (DataRecord[] memory) {\n (bool success, bytes memory data) = FETCH_DATA_RECORDS.staticcall(abi.encode(cond, namespace));\n if (!success) {\n revert PeekerReverted(FETCH_DATA_RECORDS, data);\n }\n\n return abi.decode(data, (DataRecord[]));\n }\n\n function fillMevShareBundle(DataId dataId) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = FILL_MEV_SHARE_BUNDLE.staticcall(abi.encode(dataId));\n if (!success) {\n revert PeekerReverted(FILL_MEV_SHARE_BUNDLE, data);\n }\n\n return data;\n }\n\n function newBuilder() internal view returns (string memory) {\n (bool success, bytes memory data) = NEW_BUILDER.staticcall(abi.encode());\n if (!success) {\n revert PeekerReverted(NEW_BUILDER, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function newDataRecord(\n uint64 decryptionCondition,\n address[] memory allowedPeekers,\n address[] memory allowedStores,\n string memory dataType\n ) internal view returns (DataRecord memory) {\n (bool success, bytes memory data) =\n NEW_DATA_RECORD.staticcall(abi.encode(decryptionCondition, allowedPeekers, allowedStores, dataType));\n if (!success) {\n revert PeekerReverted(NEW_DATA_RECORD, data);\n }\n\n return abi.decode(data, (DataRecord));\n }\n\n function privateKeyGen(CryptoSignature crypto) internal view returns (string memory) {\n (bool success, bytes memory data) = PRIVATE_KEY_GEN.staticcall(abi.encode(crypto));\n if (!success) {\n revert PeekerReverted(PRIVATE_KEY_GEN, data);\n }\n\n return abi.decode(data, (string));\n }\n\n function signEthTransaction(bytes memory txn, string memory chainId, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n (bool success, bytes memory data) = SIGN_ETH_TRANSACTION.staticcall(abi.encode(txn, chainId, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_ETH_TRANSACTION, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function signMessage(bytes memory digest, CryptoSignature crypto, string memory signingKey)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SIGN_MESSAGE.staticcall(abi.encode(digest, crypto, signingKey));\n if (!success) {\n revert PeekerReverted(SIGN_MESSAGE, data);\n }\n\n return abi.decode(data, (bytes));\n }\n\n function simulateBundle(bytes memory bundleData) internal view returns (uint64) {\n (bool success, bytes memory data) = SIMULATE_BUNDLE.staticcall(abi.encode(bundleData));\n if (!success) {\n revert PeekerReverted(SIMULATE_BUNDLE, data);\n }\n\n return abi.decode(data, (uint64));\n }\n\n function simulateTransaction(string memory sessionid, bytes memory txn)\n internal\n view\n returns (SimulateTransactionResult memory)\n {\n (bool success, bytes memory data) = SIMULATE_TRANSACTION.staticcall(abi.encode(sessionid, txn));\n if (!success) {\n revert PeekerReverted(SIMULATE_TRANSACTION, data);\n }\n\n return abi.decode(data, (SimulateTransactionResult));\n }\n\n function submitBundleJsonRPC(string memory url, string memory method, bytes memory params)\n internal\n view\n returns (bytes memory)\n {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(url, method, params));\n if (!success) {\n revert PeekerReverted(SUBMIT_BUNDLE_JSON_RPC, data);\n }\n\n return data;\n }\n\n function submitEthBlockToRelay(string memory relayUrl, bytes memory builderBid) internal view returns (bytes memory) {\n require(isConfidential());\n (bool success, bytes memory data) = SUBMIT_ETH_BLOCK_TO_RELAY.staticcall(abi.encode(relayUrl, builderBid));\n if (!success) {\n revert PeekerReverted(SUBMIT_ETH_BLOCK_TO_RELAY, data);\n }\n\n return data;\n }\n}\n" + }, + "contracts/libraries/Transactions.sol": { + "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.13;\n\nimport \"./RLPWriter.sol\";\nimport \"./Suave.sol\";\nimport \"solidity-rlp/contracts/RLPReader.sol\";\n\nlibrary Transactions {\n using RLPReader for RLPReader.RLPItem;\n using RLPReader for RLPReader.Iterator;\n using RLPReader for bytes;\n\n struct EIP155 {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP155Request {\n address to;\n uint256 gas;\n uint256 gasPrice;\n uint256 value;\n uint256 nonce;\n bytes data;\n uint256 chainId;\n }\n\n struct EIP1559 {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n bytes32 r;\n bytes32 s;\n uint64 v;\n }\n\n struct EIP1559Request {\n address to;\n uint64 gas;\n uint64 maxFeePerGas;\n uint64 maxPriorityFeePerGas;\n uint64 value;\n uint64 nonce;\n bytes data;\n uint64 chainId;\n bytes accessList;\n }\n\n function encodeRLP(EIP155 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(uint256(txStruct.v));\n items[7] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[8] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP155Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.nonce);\n items[1] = RLPWriter.writeUint(txStruct.gasPrice);\n items[2] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[3] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[3] = RLPWriter.writeAddress(txStruct.to);\n }\n items[4] = RLPWriter.writeUint(txStruct.value);\n items[5] = RLPWriter.writeBytes(txStruct.data);\n items[6] = RLPWriter.writeUint(txStruct.chainId);\n items[7] = RLPWriter.writeBytes(\"\");\n items[8] = RLPWriter.writeBytes(\"\");\n\n return RLPWriter.writeList(items);\n }\n\n function encodeRLP(EIP1559 memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](12);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n items[9] = RLPWriter.writeUint(uint256(txStruct.v));\n items[10] = RLPWriter.writeBytes(abi.encodePacked(txStruct.r));\n items[11] = RLPWriter.writeBytes(abi.encodePacked(txStruct.s));\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function encodeRLP(EIP1559Request memory txStruct) internal pure returns (bytes memory) {\n bytes[] memory items = new bytes[](9);\n\n items[0] = RLPWriter.writeUint(txStruct.chainId);\n items[1] = RLPWriter.writeUint(txStruct.nonce);\n items[2] = RLPWriter.writeUint(txStruct.maxPriorityFeePerGas);\n items[3] = RLPWriter.writeUint(txStruct.maxFeePerGas);\n items[4] = RLPWriter.writeUint(txStruct.gas);\n\n if (txStruct.to == address(0)) {\n items[5] = RLPWriter.writeBytes(bytes(\"\"));\n } else {\n items[5] = RLPWriter.writeAddress(txStruct.to);\n }\n\n items[6] = RLPWriter.writeUint(txStruct.value);\n items[7] = RLPWriter.writeBytes(txStruct.data);\n\n if (txStruct.accessList.length == 0) {\n items[8] = hex\"c0\"; // Empty list encoding\n } else {\n items[8] = RLPWriter.writeBytes(txStruct.accessList);\n }\n\n bytes memory rlpTxn = RLPWriter.writeList(items);\n\n bytes memory txn = new bytes(1 + rlpTxn.length);\n txn[0] = 0x02;\n\n for (uint256 i = 0; i < rlpTxn.length; ++i) {\n txn[i + 1] = rlpTxn[i];\n }\n\n return txn;\n }\n\n function decodeRLP_EIP155(bytes memory rlp) internal pure returns (EIP155 memory) {\n EIP155 memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = uint64(ls[0].toUint());\n txStruct.gasPrice = uint64(ls[1].toUint());\n txStruct.gas = uint64(ls[2].toUint());\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = uint64(ls[4].toUint());\n txStruct.data = ls[5].toBytes();\n txStruct.v = uint64(ls[6].toUint());\n txStruct.r = bytesToBytes32(ls[7].toBytes());\n txStruct.s = bytesToBytes32(ls[8].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP155Request(bytes memory rlp) internal pure returns (EIP155Request memory) {\n EIP155Request memory txStruct;\n\n RLPReader.RLPItem[] memory ls = rlp.toRlpItem().toList();\n require(ls.length == 9, \"invalid transaction\");\n\n txStruct.nonce = ls[0].toUint();\n txStruct.gasPrice = ls[1].toUint();\n txStruct.gas = ls[2].toUint();\n\n if (ls[3].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[3].toAddress();\n }\n\n txStruct.value = ls[4].toUint();\n txStruct.data = ls[5].toBytes();\n txStruct.chainId = uint64(ls[6].toUint());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559(bytes memory rlp) internal pure returns (EIP1559 memory) {\n EIP1559 memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 12, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n txStruct.accessList = ls[8].toBytes();\n txStruct.v = uint64(ls[9].toUint());\n txStruct.r = bytesToBytes32(ls[10].toBytes());\n txStruct.s = bytesToBytes32(ls[11].toBytes());\n\n return txStruct;\n }\n\n function decodeRLP_EIP1559Request(bytes memory rlp) internal pure returns (EIP1559Request memory) {\n EIP1559Request memory txStruct;\n\n bytes memory rlpWithoutPrefix = new bytes(rlp.length - 1);\n\n for (uint256 i = 0; i < rlp.length - 1; ++i) {\n rlpWithoutPrefix[i] = rlp[i + 1];\n }\n\n RLPReader.RLPItem[] memory ls = rlpWithoutPrefix.toRlpItem().toList();\n require(ls.length == 8, \"invalid transaction\");\n\n txStruct.chainId = uint64(ls[0].toUint());\n txStruct.nonce = uint64(ls[1].toUint());\n txStruct.maxPriorityFeePerGas = uint64(ls[2].toUint());\n txStruct.maxFeePerGas = uint64(ls[3].toUint());\n txStruct.gas = uint64(ls[4].toUint());\n\n if (ls[5].toRlpBytes().length == 1) {\n txStruct.to = address(0);\n } else {\n txStruct.to = ls[5].toAddress();\n }\n\n txStruct.value = uint64(ls[6].toUint());\n txStruct.data = ls[7].toBytes();\n\n return txStruct;\n }\n\n function bytesToBytes32(bytes memory inBytes) internal pure returns (bytes32 out) {\n require(inBytes.length == 32, \"bytesToBytes32: invalid input length\");\n assembly {\n out := mload(add(inBytes, 32))\n }\n }\n\n function signTxn(Transactions.EIP1559Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP1559 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n response.to = request.to;\n response.gas = request.gas;\n response.maxFeePerGas = request.maxFeePerGas;\n response.maxPriorityFeePerGas = request.maxPriorityFeePerGas;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.accessList = request.accessList;\n response.v = v;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function signTxn(Transactions.EIP155Request memory request, string memory signingKey)\n internal\n view\n returns (Transactions.EIP155 memory response)\n {\n bytes memory rlp = Transactions.encodeRLP(request);\n bytes memory hash = abi.encodePacked(keccak256(rlp));\n bytes memory signature = Suave.signMessage(hash, Suave.CryptoSignature.SECP256, signingKey);\n\n // TODO: check overflow\n uint64 chainIdMul = uint64(request.chainId) * 2;\n (uint8 v, bytes32 r, bytes32 s) = decodeSignature(signature);\n\n uint64 v64 = uint64(v) + 35;\n v64 += chainIdMul;\n\n response.to = request.to;\n response.gas = request.gas;\n response.gasPrice = request.gasPrice;\n response.value = request.value;\n response.nonce = request.nonce;\n response.data = request.data;\n response.chainId = request.chainId;\n response.v = v64;\n response.r = r;\n response.s = s;\n\n return response;\n }\n\n function decodeSignature(bytes memory signature) public pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n }\n}" + }, + "contracts/oracle/BinanceOracle.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\npragma solidity ^0.8.13;\n\nimport { AnyBundleContract, Suave } from \"../standard_peekers/bids.sol\";\nimport { SuaveContract } from \"../blockad/lib/SuaveContract.sol\";\nimport { floatToInt, trimStrEdges, getAddressForPk } from \"./lib/Utils.sol\";\nimport \"../../node_modules/solady/src/utils/JSONParserLib.sol\";\nimport \"../libraries/Transactions.sol\";\nimport \"../libraries/Bundle.sol\";\nimport \"solady/src/utils/LibString.sol\";\n\n\ncontract BinanceOracle is SuaveContract {\n using JSONParserLib for *;\n\n uint public constant GOERLI_CHAINID = 5;\n string public constant GOERLI_CHAINID_STR = \"0x5\";\n uint8 public constant DECIMALS = 4;\n string public constant S_NAMESPACE = \"oracle:v0:pksecret\";\n string public constant INFURA_GOERLI_RPC = \"https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161\"; // Change when settlement node API is exposed\n string public constant URL_PARTIAL = \"https://data-api.binance.vision/api/v3/ticker/price?symbol=\";\n string public constant GOERLI_BUNDLE_ENDPOINT = \"https://relay-goerli.flashbots.net\";\n \n bool isInitialized;\n Suave.DataId public pkBidId;\n address public controller;\n address public settlementContract;\n\n event PriceSubmission(string ticker, uint price);\n\n // ⛓️ EVM Methods\n\n function confidentialConstructorCallback(\n Suave.DataId _pkBidId, \n address pkAddress\n ) public {\n crequire(!isInitialized, \"Already initialized\");\n pkBidId = _pkBidId;\n controller = pkAddress;\n isInitialized = true;\n }\n\n function registerCallback(address _settlementContract) public {\n require(_settlementContract == settlementContract || settlementContract == address(0), \"Already registered\");\n settlementContract = _settlementContract;\n }\n\n // ! Warning: This method is not restricted and emitted events should not be relied upon\n function queryAndSubmitCallback(string memory ticker, uint price) public {\n emit PriceSubmission(ticker, price);\n }\n\n fallback() external payable {\n // Needed to accept MEVM calls with no callbacks\n }\n\n // 🤐 MEVM Methods\n\n function confidentialConstructor() external view onlyConfidential returns (bytes memory) {\n crequire(!isInitialized, \"Already initialized\");\n\n string memory pk = Suave.privateKeyGen(Suave.CryptoSignature.SECP256);\n address pkAddress = getAddressForPk(pk);\n\t\tSuave.DataId bidId = storePK(bytes(pk));\n\n return abi.encodeWithSelector(\n this.confidentialConstructorCallback.selector, \n bidId, \n pkAddress\n );\n }\n\n function registerSettlementContract(address _settlementContract) external view onlyConfidential() returns (bytes memory) {\n require(settlementContract == address(0), \"Already registered\");\n bytes memory signedTx = createRegisterTx(_settlementContract);\n sendRawTx(signedTx);\n return abi.encodeWithSelector(this.registerCallback.selector, _settlementContract);\n }\n\n function queryAndSubmit(\n string memory ticker, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum,\n bool privateSubmission\n ) external view onlyConfidential returns (uint) {\n uint price = queryLatestPrice(ticker);\n submitPriceUpdate(ticker, price, nonce, gasPrice, settlementBlockNum, privateSubmission);\n return price;\n }\n\n function queryLatestPrice(string memory ticker) public view returns (uint price) {\n bytes memory response = doBinanceQuery(ticker);\n JSONParserLib.Item memory parsedRes = string(response).parse();\n string memory priceStr = string(parsedRes.at('\"price\"').value());\n price = floatToInt(trimStrEdges(priceStr), DECIMALS);\n }\n\n function submitPriceUpdate(\n string memory ticker,\n uint price, \n uint nonce,\n uint gasPrice,\n uint64 settlementBlockNum,\n bool privateSubmission\n ) internal view {\n bytes memory signedTx = createPriceUpdateTx(ticker, price, nonce, gasPrice);\n if (privateSubmission) {\n sendBundle(signedTx, settlementBlockNum);\n } else {\n sendRawTx(signedTx);\n }\n }\n\n function createRegisterTx(address _settlementContract) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: 0,\n gasPrice: 100 gwei,\n gas: 100_000,\n to: _settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"register()\"),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function createPriceUpdateTx(string memory ticker, uint price, uint nonce, uint gasPrice) internal view returns (bytes memory txSigned) {\n Transactions.EIP155 memory transaction = Transactions.EIP155({\n nonce: nonce,\n gasPrice: gasPrice,\n gas: 100_000,\n to: settlementContract,\n value: 0,\n data: abi.encodeWithSignature(\"updatePrice(string,uint256)\", ticker, price),\n chainId: GOERLI_CHAINID,\n v: 27,\n r: hex\"1111111111111111111111111111111111111111111111111111111111111111\",\n s: hex\"1111111111111111111111111111111111111111111111111111111111111111\"\n });\n bytes memory txRlp = Transactions.encodeRLP(transaction);\n string memory pk = retreivePK();\n txSigned = Suave.signEthTransaction(txRlp, GOERLI_CHAINID_STR, pk);\n }\n\n function sendRawTx(bytes memory txSigned) public view returns (bytes memory) {\n bytes memory body =\n abi.encodePacked('{\"jsonrpc\":\"2.0\",\"method\":\"eth_sendRawTransaction\",\"params\":[\"', LibString.toHexString(txSigned), '\"],\"id\":1}');\n Suave.HttpRequest memory request;\n request.method = \"POST\";\n request.body = body;\n request.headers = new string[](1);\n request.headers[0] = \"Content-Type: application/json\";\n request.withFlashbotsSignature = false;\n request.url = INFURA_GOERLI_RPC;\n return doHttpRequest(request);\n }\n\n function sendBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n simulateTx(txSigned);\n sendTxViaBundle(txSigned, settlementBlockNum);\n }\n\n function simulateTx(bytes memory signedTx) internal view {\n bytes memory bundle = abi.encodePacked('{\"txs\": [\"', LibString.toHexString(signedTx), '\"]}');\n (bool successSim, bytes memory data) = Suave.SIMULATE_BUNDLE.staticcall(abi.encode(bundle));\n crequire(successSim, string(abi.encodePacked(\"BundleSimulationFailed: \", string(data))));\n }\n\n function doBinanceQuery(string memory ticker) internal view returns (bytes memory) {\n string[] memory headers = new string[](1);\n headers[0] = \"Content-Type: application/json\";\n Suave.HttpRequest memory request = Suave.HttpRequest({\n url: string(abi.encodePacked(URL_PARTIAL, ticker)),\n method: 'GET',\n headers: headers,\n body: new bytes(0),\n withFlashbotsSignature: false\n });\n return doHttpRequest(request);\n }\n\n function doHttpRequest(Suave.HttpRequest memory request) internal view returns (bytes memory) {\n (bool success, bytes memory data) = Suave.DO_HTTPREQUEST.staticcall(abi.encode(request));\n crequire(success, string(data));\n return abi.decode(data, (bytes));\n }\n\n function sendTxViaBundle(bytes memory txSigned, uint64 settlementBlockNum) internal view {\n bytes[] memory txns = new bytes[](1);\n txns[0] = txSigned;\n bytes memory bundleReqParams = bundleRequestParams(txns, settlementBlockNum);\n (bool successReq, bytes memory dataReq) = Suave.SUBMIT_BUNDLE_JSON_RPC.staticcall(abi.encode(\n GOERLI_BUNDLE_ENDPOINT, \n \"eth_sendBundle\", \n bundleReqParams\n ));\n crequire(successReq, string(abi.encodePacked(\"BundleSubmissionFailed: \", string(dataReq))));\n }\n\n function bundleRequestParams(bytes[] memory txns, uint blockNumber) internal pure returns (bytes memory) {\n bytes memory params =\n abi.encodePacked('{\"blockNumber\": \"', LibString.toHexString(blockNumber), '\", \"txs\": [');\n for (uint256 i = 0; i < txns.length; i++) {\n params = abi.encodePacked(params, '\"', LibString.toHexString(txns[i]), '\"');\n if (i < txns.length - 1) {\n params = abi.encodePacked(params, \",\");\n } else {\n params = abi.encodePacked(params, \"]\");\n }\n }\n params = abi.encodePacked(params, \"}\");\n\n return params;\n }\n\n function storePK(bytes memory pk) internal view returns (Suave.DataId) {\n\t\taddress[] memory peekers = new address[](3);\n\t\tpeekers[0] = address(this);\n\t\tpeekers[1] = Suave.FETCH_DATA_RECORDS;\n\t\tpeekers[2] = Suave.CONFIDENTIAL_RETRIEVE;\n\t\tSuave.DataRecord memory secretBid = Suave.newDataRecord(0, peekers, peekers, S_NAMESPACE);\n\t\tSuave.confidentialStore(secretBid.id, S_NAMESPACE, pk);\n\t\treturn secretBid.id;\n\t}\n\n function retreivePK() internal view returns (string memory) {\n bytes memory pkBytes = Suave.confidentialRetrieve(pkBidId, S_NAMESPACE);\n return string(pkBytes);\n }\n\n}" + }, + "contracts/oracle/lib/Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// Author: Miha Lotric (halo3mic)\n\n// 🚨 THIS IS UNTESTED DEMO CODE - DONT USE IN PRODUCTION 🚨\n\n\npragma solidity ^0.8.8;\n\nimport '../../libraries/Suave.sol';\n\n\nfunction floatToInt(string memory floatString, uint8 decimals) pure returns (uint) {\n bytes memory stringBytes = bytes(floatString);\n uint dotPosition;\n \n // Find the position of the dot\n for (uint i = 0; i < stringBytes.length; i++) {\n if (stringBytes[i] == 0x2E) {\n dotPosition = i;\n break;\n }\n }\n \n uint integerPart = 0;\n uint decimalPart = 0;\n uint tenPower = 1;\n \n // Convert integer part\n for (uint i = dotPosition; i > 0; i--) {\n integerPart += (uint8(stringBytes[i - 1]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Reset power of ten\n tenPower = 1;\n \n // Convert decimal part\n for (uint i = dotPosition+decimals; i > dotPosition; i--) {\n decimalPart += (uint8(stringBytes[i]) - 48) * tenPower;\n tenPower *= 10;\n }\n \n // Combine integer and decimal parts\n return integerPart * (10**decimals) + decimalPart;\n}\n\nfunction trimStrEdges(string memory _input) pure returns (string memory) {\n bytes memory input = bytes(_input);\n require(input.length > 2, \"Input too short\");\n\n uint newLength = input.length - 2;\n bytes memory result = new bytes(newLength);\n\n assembly {\n let inputPtr := add(input, 0x21)\n let resultPtr := add(result, 0x20)\n let length := mload(input)\n mstore(resultPtr, mload(inputPtr))\n mstore(result, newLength)\n }\n return string(result);\n}\n\nfunction getAddressForPk(string memory pk) view returns (address) {\n bytes32 digest = keccak256(abi.encode(\"yo\"));\n bytes memory sig = Suave.signMessage(abi.encodePacked(digest), Suave.CryptoSignature.SECP256, pk);\n return recoverSigner(digest, sig);\n}\n\nfunction recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) pure returns (address) {\n (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);\n return ecrecover(_ethSignedMessageHash, v, r, s);\n}\n\nfunction splitSignature(bytes memory sig) pure returns (bytes32 r, bytes32 s, uint8 v) {\n require(sig.length == 65, \"invalid signature length\");\n assembly {\n r := mload(add(sig, 32))\n s := mload(add(sig, 64))\n v := byte(0, mload(add(sig, 96)))\n }\n if (v < 27) {\n v += 27;\n }\n}" + }, + "contracts/standard_peekers/bids.sol": { + "content": "pragma solidity ^0.8.8;\n\nimport \"../libraries/Suave.sol\";\n\ncontract AnyBundleContract {\n event DataRecordEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);\n\n function fetchConfidentialBundleData() public returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory confidentialInputs = Suave.confidentialInputs();\n return abi.decode(confidentialInputs, (bytes));\n }\n\n function emitDataRecord(Suave.DataRecord calldata dataRecord) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n }\n}\n\ncontract BundleContract is AnyBundleContract {\n function newBundle(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n require(Suave.isConfidential());\n\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n uint64 egp = Suave.simulateBundle(bundleData);\n\n Suave.DataRecord memory dataRecord =\n Suave.newDataRecord(decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"default:v0:ethBundles\");\n\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"default:v0:ethBundleSimResults\", abi.encode(egp));\n\n return emitAndReturn(dataRecord, bundleData);\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory) internal virtual returns (bytes memory) {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract EthBundleSenderContract is BundleContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitAndReturn(Suave.DataRecord memory dataRecord, bytes memory bundleData)\n internal\n virtual\n override\n returns (bytes memory)\n {\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"eth_sendBundle\", bundleData);\n }\n\n return BundleContract.emitAndReturn(dataRecord, bundleData);\n }\n}\n\ncontract MevShareContract is AnyBundleContract {\n event HintEvent(Suave.DataId dataId, bytes hint);\n\n event MatchEvent(Suave.DataId matchDataId, bytes matchHint);\n\n function newTransaction(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores\n ) external payable returns (bytes memory) {\n // 0. check confidential execution\n require(Suave.isConfidential());\n\n // 1. fetch bundle data\n bytes memory bundleData = this.fetchConfidentialBundleData();\n\n // 2. sim bundle\n uint64 egp = Suave.simulateBundle(bundleData);\n\n // 3. extract hint\n bytes memory hint = Suave.extractHint(bundleData);\n\n // // 4. store bundle and sim results\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:unmatchedBundles\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", bundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(egp));\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n\n // // 5. return \"callback\" to emit hint onchain\n return bytes.concat(this.emitDataRecordAndHint.selector, abi.encode(dataRecord, hint));\n }\n\n function emitDataRecordAndHint(Suave.DataRecord calldata dataRecord, bytes memory hint) public {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit HintEvent(dataRecord.id, hint);\n }\n\n function newMatch(\n uint64 decryptionCondition,\n address[] memory dataAllowedPeekers,\n address[] memory dataAllowedStores,\n Suave.DataId sharedataId\n ) external payable returns (bytes memory) {\n // WARNING : this function will copy the original mev share bid\n // into a new key with potentially different permsissions\n\n require(Suave.isConfidential());\n // 1. fetch confidential data\n bytes memory matchBundleData = this.fetchConfidentialBundleData();\n\n // 2. sim match alone for validity\n uint64 egp = Suave.simulateBundle(matchBundleData);\n\n // 3. extract hint\n bytes memory matchHint = Suave.extractHint(matchBundleData);\n\n Suave.DataRecord memory dataRecord = Suave.newDataRecord(\n decryptionCondition, dataAllowedPeekers, dataAllowedStores, \"mevshare:v0:matchDataRecords\"\n );\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundles\", matchBundleData);\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:ethBundleSimResults\", abi.encode(0));\n\n //4. merge data records\n Suave.DataId[] memory dataRecords = new Suave.DataId[](2);\n dataRecords[0] = sharedataId;\n dataRecords[1] = dataRecord.id;\n Suave.confidentialStore(dataRecord.id, \"mevshare:v0:mergedDataRecords\", abi.encode(dataRecords));\n\n return emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n returns (bytes memory)\n {\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n emit MatchEvent(dataRecord.id, matchHint);\n\n return bytes.concat(this.emitDataRecord.selector, abi.encode(dataRecord));\n }\n}\n\ncontract MevShareBundleSenderContract is MevShareContract {\n string[] public builderUrls;\n\n constructor(string[] memory builderUrls_) {\n builderUrls = builderUrls_;\n }\n\n function emitMatchDataRecordAndHint(Suave.DataRecord memory dataRecord, bytes memory matchHint)\n internal\n virtual\n override\n returns (bytes memory)\n {\n bytes memory bundleData = Suave.fillMevShareBundle(dataRecord.id);\n for (uint256 i = 0; i < builderUrls.length; i++) {\n Suave.submitBundleJsonRPC(builderUrls[i], \"mev_sendBundle\", bundleData);\n }\n\n return MevShareContract.emitMatchDataRecordAndHint(dataRecord, matchHint);\n }\n}\n\n/* Not tested or implemented on the precompile side */\nstruct EgpRecordPair {\n uint64 egp; // in wei, beware overflow\n Suave.DataId dataId;\n}\n\ncontract EthBlockContract is AnyBundleContract {\n event BuilderBoostBidEvent(Suave.DataId dataId, bytes builderBid);\n\n function idsEqual(Suave.DataId _l, Suave.DataId _r) public pure returns (bool) {\n bytes memory l = abi.encodePacked(_l);\n bytes memory r = abi.encodePacked(_r);\n for (uint256 i = 0; i < l.length; i++) {\n if (bytes(l)[i] != r[i]) {\n return false;\n }\n }\n\n return true;\n }\n\n function buildMevShare(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allShareMatchDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:matchDataRecords\");\n Suave.DataRecord[] memory allShareUserDataRecords =\n Suave.fetchDataRecords(blockHeight, \"mevshare:v0:unmatchedBundles\");\n\n if (allShareUserDataRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n Suave.DataRecord[] memory allRecords = new Suave.DataRecord[](allShareUserDataRecords.length);\n for (uint256 i = 0; i < allShareUserDataRecords.length; i++) {\n // TODO: sort matches by egp first!\n Suave.DataRecord memory dataRecordToInsert = allShareUserDataRecords[i]; // will be updated with the best match if any\n for (uint256 j = 0; j < allShareMatchDataRecords.length; j++) {\n // TODO: should be done once at the start and sorted\n Suave.DataId[] memory mergeddataIds = abi.decode(\n Suave.confidentialRetrieve(allShareMatchDataRecords[j].id, \"mevshare:v0:mergedDataRecords\"),\n (Suave.DataId[])\n );\n if (idsEqual(mergeddataIds[0], allShareUserDataRecords[i].id)) {\n dataRecordToInsert = allShareMatchDataRecords[j];\n break;\n }\n }\n allRecords[i] = dataRecordToInsert;\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"mevshare:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"mevshare:v0\");\n }\n\n function buildFromPool(Suave.BuildBlockArgs memory blockArgs, uint64 blockHeight) public returns (bytes memory) {\n require(Suave.isConfidential());\n\n Suave.DataRecord[] memory allRecords = Suave.fetchDataRecords(blockHeight, \"default:v0:ethBundles\");\n if (allRecords.length == 0) {\n revert Suave.PeekerReverted(address(this), \"no data records\");\n }\n\n EgpRecordPair[] memory bidsByEGP = new EgpRecordPair[](allRecords.length);\n for (uint256 i = 0; i < allRecords.length; i++) {\n bytes memory simResults = Suave.confidentialRetrieve(allRecords[i].id, \"default:v0:ethBundleSimResults\");\n uint64 egp = abi.decode(simResults, (uint64));\n bidsByEGP[i] = EgpRecordPair(egp, allRecords[i].id);\n }\n\n // Bubble sort, cause why not\n uint256 n = bidsByEGP.length;\n for (uint256 i = 0; i < n - 1; i++) {\n for (uint256 j = i + 1; j < n; j++) {\n if (bidsByEGP[i].egp < bidsByEGP[j].egp) {\n EgpRecordPair memory temp = bidsByEGP[i];\n bidsByEGP[i] = bidsByEGP[j];\n bidsByEGP[j] = temp;\n }\n }\n }\n\n Suave.DataId[] memory alldataIds = new Suave.DataId[](allRecords.length);\n for (uint256 i = 0; i < bidsByEGP.length; i++) {\n alldataIds[i] = bidsByEGP[i].dataId;\n }\n\n return buildAndEmit(blockArgs, blockHeight, alldataIds, \"\");\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public virtual returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockBid, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, records, namespace);\n\n emit BuilderBoostBidEvent(blockBid.id, builderBid);\n emit DataRecordEvent(blockBid.id, blockBid.decryptionCondition, blockBid.allowedPeekers);\n return bytes.concat(this.emitBuilderBidAndBid.selector, abi.encode(blockBid, builderBid));\n }\n\n function doBuild(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory records,\n string memory namespace\n ) public view returns (Suave.DataRecord memory, bytes memory) {\n address[] memory allowedPeekers = new address[](2);\n allowedPeekers[0] = address(this);\n allowedPeekers[1] = Suave.BUILD_ETH_BLOCK;\n\n Suave.DataRecord memory blockBid =\n Suave.newDataRecord(blockHeight, allowedPeekers, allowedPeekers, \"default:v0:mergedDataRecords\");\n Suave.confidentialStore(blockBid.id, \"default:v0:mergedDataRecords\", abi.encode(records));\n\n (bytes memory builderBid, bytes memory payload) = Suave.buildEthBlock(blockArgs, blockBid.id, namespace);\n Suave.confidentialStore(blockBid.id, \"default:v0:builderPayload\", payload); // only through this.unlock\n\n return (blockBid, builderBid);\n }\n\n function emitBuilderBidAndBid(Suave.DataRecord memory dataRecord, bytes memory builderBid)\n public\n returns (Suave.DataRecord memory, bytes memory)\n {\n emit BuilderBoostBidEvent(dataRecord.id, builderBid);\n emit DataRecordEvent(dataRecord.id, dataRecord.decryptionCondition, dataRecord.allowedPeekers);\n return (dataRecord, builderBid);\n }\n\n function unlock(Suave.DataId dataId, bytes memory signedBlindedHeader) public view returns (bytes memory) {\n require(Suave.isConfidential());\n\n // TODO: verify the header is correct\n // TODO: incorporate protocol name\n bytes memory payload = Suave.confidentialRetrieve(dataId, \"default:v0:builderPayload\");\n return payload;\n }\n}\n\ncontract EthBlockBidSenderContract is EthBlockContract {\n string boostRelayUrl;\n\n constructor(string memory boostRelayUrl_) {\n boostRelayUrl = boostRelayUrl_;\n }\n\n function buildAndEmit(\n Suave.BuildBlockArgs memory blockArgs,\n uint64 blockHeight,\n Suave.DataId[] memory dataRecords,\n string memory namespace\n ) public virtual override returns (bytes memory) {\n require(Suave.isConfidential());\n\n (Suave.DataRecord memory blockDataRecord, bytes memory builderBid) =\n this.doBuild(blockArgs, blockHeight, dataRecords, namespace);\n Suave.submitEthBlockToRelay(boostRelayUrl, builderBid);\n\n emit DataRecordEvent(blockDataRecord.id, blockDataRecord.decryptionCondition, blockDataRecord.allowedPeekers);\n return bytes.concat(this.emitDataRecord.selector, abi.encode(blockDataRecord));\n }\n}\n" + }, + "solady/src/utils/JSONParserLib.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for parsing JSONs.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/JSONParserLib.sol)\nlibrary JSONParserLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The input is invalid.\n error ParsingFailed();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // There are 6 types of variables in JSON (excluding undefined).\n\n /// @dev For denoting that an item has not been initialized.\n /// A item returned from `parse` will never be of an undefined type.\n /// Parsing a invalid JSON string will simply revert.\n uint8 internal constant TYPE_UNDEFINED = 0;\n\n /// @dev Type representing an array (e.g. `[1,2,3]`).\n uint8 internal constant TYPE_ARRAY = 1;\n\n /// @dev Type representing an object (e.g. `{\"a\":\"A\",\"b\":\"B\"}`).\n uint8 internal constant TYPE_OBJECT = 2;\n\n /// @dev Type representing a number (e.g. `-1.23e+21`).\n uint8 internal constant TYPE_NUMBER = 3;\n\n /// @dev Type representing a string (e.g. `\"hello\"`).\n uint8 internal constant TYPE_STRING = 4;\n\n /// @dev Type representing a boolean (i.e. `true` or `false`).\n uint8 internal constant TYPE_BOOLEAN = 5;\n\n /// @dev Type representing null (i.e. `null`).\n uint8 internal constant TYPE_NULL = 6;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STRUCTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev A pointer to a parsed JSON node.\n struct Item {\n // Do NOT modify the `_data` directly.\n uint256 _data;\n }\n\n // Private constants for packing `_data`.\n\n uint256 private constant _BITPOS_STRING = 32 * 7 - 8;\n uint256 private constant _BITPOS_KEY_LENGTH = 32 * 6 - 8;\n uint256 private constant _BITPOS_KEY = 32 * 5 - 8;\n uint256 private constant _BITPOS_VALUE_LENGTH = 32 * 4 - 8;\n uint256 private constant _BITPOS_VALUE = 32 * 3 - 8;\n uint256 private constant _BITPOS_CHILD = 32 * 2 - 8;\n uint256 private constant _BITPOS_SIBLING_OR_PARENT = 32 * 1 - 8;\n uint256 private constant _BITMASK_POINTER = 0xffffffff;\n uint256 private constant _BITMASK_TYPE = 7;\n uint256 private constant _KEY_INITED = 1 << 3;\n uint256 private constant _VALUE_INITED = 1 << 4;\n uint256 private constant _CHILDREN_INITED = 1 << 5;\n uint256 private constant _PARENT_IS_ARRAY = 1 << 6;\n uint256 private constant _PARENT_IS_OBJECT = 1 << 7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON PARSING OPERATION */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses the JSON string `s`, and returns the root.\n /// Reverts if `s` is not a valid JSON as specified in RFC 8259.\n /// Object items WILL simply contain all their children, inclusive of repeated keys,\n /// in the same order which they appear in the JSON string.\n ///\n /// Note: For efficiency, this function WILL NOT make a copy of `s`.\n /// The parsed tree WILL contain offsets to `s`.\n /// Do NOT pass in a string that WILL be modified later on.\n function parse(string memory s) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // We will use our own allocation instead.\n }\n bytes32 r = _query(_toInput(s), 255);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* JSON ITEM OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note:\n // - An item is a node in the JSON tree.\n // - The value of a string item WILL be double-quoted, JSON encoded.\n // - We make a distinction between `index` and `key`.\n // - Items in arrays are located by `index` (uint256).\n // - Items in objects are located by `key` (string).\n // - Keys are always strings, double-quoted, JSON encoded.\n //\n // These design choices are made to balance between efficiency and ease-of-use.\n\n /// @dev Returns the string value of the item.\n /// This is its exact string representation in the original JSON string.\n /// The returned string WILL have leading and trailing whitespace trimmed.\n /// All inner whitespace WILL be preserved, exactly as it is in the original JSON string.\n /// If the item's type is string, the returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function value(Item memory item) internal pure returns (string memory result) {\n bytes32 r = _query(_toInput(item), 0);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the index of the item in the array.\n /// It the item's parent is not an array, returns 0.\n function index(Item memory item) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if and(mload(item), _PARENT_IS_ARRAY) {\n result := and(_BITMASK_POINTER, shr(_BITPOS_KEY, mload(item)))\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item's parent is not an object, returns an empty string.\n /// The returned string WILL be double-quoted, JSON encoded.\n ///\n /// Note: This function lazily instantiates and caches the returned string.\n /// Do NOT modify the returned string.\n function key(Item memory item) internal pure returns (string memory result) {\n if (item._data & _PARENT_IS_OBJECT != 0) {\n bytes32 r = _query(_toInput(item), 1);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n }\n\n /// @dev Returns the key of the item in the object.\n /// It the item is neither an array nor object, returns an empty array.\n ///\n /// Note: This function lazily instantiates and caches the returned array.\n /// Do NOT modify the returned array.\n function children(Item memory item) internal pure returns (Item[] memory result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := r\n }\n }\n\n /// @dev Returns the number of children.\n /// It the item is neither an array nor object, returns zero.\n function size(Item memory item) internal pure returns (uint256 result) {\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(r)\n }\n }\n\n /// @dev Returns the item at index `i` for (array).\n /// If `item` is not an array, the result's type WILL be undefined.\n /// If there is no item with the index, the result's type WILL be undefined.\n function at(Item memory item, uint256 i) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n }\n bytes32 r = _query(_toInput(item), 3);\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(add(add(r, 0x20), shl(5, i)))\n if iszero(and(lt(i, mload(r)), eq(and(mload(item), _BITMASK_TYPE), TYPE_ARRAY))) {\n result := 0x60 // Reset to the zero pointer.\n }\n }\n }\n\n /// @dev Returns the item at key `k` for (object).\n /// If `item` is not an object, the result's type WILL be undefined.\n /// The key MUST be double-quoted, JSON encoded. This is for efficiency reasons.\n /// - Correct : `item.at('\"k\"')`.\n /// - Wrong : `item.at(\"k\")`.\n /// For duplicated keys, the last item with the key WILL be returned.\n /// If there is no item with the key, the result's type WILL be undefined.\n function at(Item memory item, string memory k) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We'll allocate manually.\n result := 0x60 // Initialize to the zero pointer.\n }\n if (isObject(item)) {\n bytes32 kHash = keccak256(bytes(k));\n Item[] memory r = children(item);\n // We'll just do a linear search. The alternatives are very bloated.\n for (uint256 i = r.length << 5; i != 0;) {\n /// @solidity memory-safe-assembly\n assembly {\n item := mload(add(r, i))\n i := sub(i, 0x20)\n }\n if (keccak256(bytes(key(item))) != kHash) continue;\n result = item;\n break;\n }\n }\n }\n\n /// @dev Returns the item's type.\n function getType(Item memory item) internal pure returns (uint8 result) {\n result = uint8(item._data & _BITMASK_TYPE);\n }\n\n /// Note: All types are mutually exclusive.\n\n /// @dev Returns whether the item is of type undefined.\n function isUndefined(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_UNDEFINED;\n }\n\n /// @dev Returns whether the item is of type array.\n function isArray(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_ARRAY;\n }\n\n /// @dev Returns whether the item is of type object.\n function isObject(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_OBJECT;\n }\n\n /// @dev Returns whether the item is of type number.\n function isNumber(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NUMBER;\n }\n\n /// @dev Returns whether the item is of type string.\n function isString(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_STRING;\n }\n\n /// @dev Returns whether the item is of type boolean.\n function isBoolean(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_BOOLEAN;\n }\n\n /// @dev Returns whether the item is of type null.\n function isNull(Item memory item) internal pure returns (bool result) {\n result = item._data & _BITMASK_TYPE == TYPE_NULL;\n }\n\n /// @dev Returns the item's parent.\n /// If the item does not have a parent, the result's type will be undefined.\n function parent(Item memory item) internal pure returns (Item memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x40, result) // Free the default allocation. We've already allocated.\n result := and(shr(_BITPOS_SIBLING_OR_PARENT, mload(item)), _BITMASK_POINTER)\n if iszero(result) { result := 0x60 } // Reset to the zero pointer.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* UTILITY FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Parses an unsigned integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid uint256 string matching the RegEx `^[0-9]+$`,\n /// or if the parsed number is too big for a uint256.\n function parseUint(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n let preMulOverflowThres := div(not(0), 10)\n for { let i := 0 } 1 {} {\n i := add(i, 1)\n let digit := sub(and(mload(add(s, i)), 0xff), 48)\n let mulOverflowed := gt(result, preMulOverflowThres)\n let product := mul(10, result)\n result := add(product, digit)\n n := mul(n, iszero(or(or(mulOverflowed, lt(result, product)), gt(digit, 9))))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Parses a signed integer from a string (in decimal, i.e. base 10).\n /// Reverts if `s` is not a valid int256 string matching the RegEx `^[+-]?[0-9]+$`,\n /// or if the parsed number cannot fit within `[-2**255 .. 2**255 - 1]`.\n function parseInt(string memory s) internal pure returns (int256 result) {\n uint256 n = bytes(s).length;\n uint256 sign;\n uint256 isNegative;\n /// @solidity memory-safe-assembly\n assembly {\n if n {\n let c := and(mload(add(s, 1)), 0xff)\n isNegative := eq(c, 45)\n if or(eq(c, 43), isNegative) {\n sign := c\n s := add(s, 1)\n mstore(s, sub(n, 1))\n }\n if iszero(or(sign, lt(sub(c, 48), 10))) { s := 0x60 }\n }\n }\n uint256 x = parseUint(s);\n /// @solidity memory-safe-assembly\n assembly {\n if iszero(lt(x, add(shl(255, 1), isNegative))) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n if sign {\n mstore(s, sign)\n s := sub(s, 1)\n mstore(s, n)\n }\n result := xor(x, mul(xor(x, add(not(x), 1)), isNegative))\n }\n }\n\n /// @dev Parses an unsigned integer from a string (in hexadecimal, i.e. base 16).\n /// Reverts if `s` is not a valid uint256 hex string matching the RegEx\n /// `^(0[xX])?[0-9a-fA-F]+$`, or if the parsed number cannot fit within `[0 .. 2**256 - 1]`.\n function parseUintFromHex(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let n := mload(s)\n // Skip two if starts with '0x' or '0X'.\n let i := shl(1, and(eq(0x3078, or(shr(240, mload(add(s, 0x20))), 0x20)), gt(n, 1)))\n for {} 1 {} {\n i := add(i, 1)\n let c :=\n byte(\n and(0x1f, shr(and(mload(add(s, i)), 0xff), 0x3e4088843e41bac000000000000)),\n 0x3010a071000000b0104040208000c05090d060e0f\n )\n n := mul(n, iszero(or(iszero(c), shr(252, result))))\n result := add(shl(4, result), sub(c, 1))\n if iszero(lt(i, n)) { break }\n }\n if iszero(n) {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n }\n }\n\n /// @dev Decodes a JSON encoded string.\n /// The string MUST be double-quoted, JSON encoded.\n /// Reverts if the string is invalid.\n /// As you can see, it's pretty complex for a deceptively simple looking task.\n function decodeString(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function decodeUnicodeEscapeSequence(pIn_, end_) -> _unicode, _pOut {\n _pOut := add(pIn_, 4)\n let b_ := iszero(gt(_pOut, end_))\n let t_ := mload(pIn_) // Load the whole word.\n for { let i_ := 0 } iszero(eq(i_, 4)) { i_ := add(i_, 1) } {\n let c_ := sub(byte(i_, t_), 48)\n if iszero(and(shr(c_, 0x7e0000007e03ff), b_)) { fail() } // Not hexadecimal.\n c_ := sub(c_, add(mul(gt(c_, 16), 7), shl(5, gt(c_, 48))))\n _unicode := add(shl(4, _unicode), c_)\n }\n }\n\n function decodeUnicodeCodePoint(pIn_, end_) -> _unicode, _pOut {\n _unicode, _pOut := decodeUnicodeEscapeSequence(pIn_, end_)\n if iszero(or(lt(_unicode, 0xd800), gt(_unicode, 0xdbff))) {\n let t_ := mload(_pOut) // Load the whole word.\n end_ := mul(end_, eq(shr(240, t_), 0x5c75)) // Fail if not starting with '\\\\u'.\n t_, _pOut := decodeUnicodeEscapeSequence(add(_pOut, 2), end_)\n _unicode := add(0x10000, add(shl(10, and(0x3ff, _unicode)), and(0x3ff, t_)))\n }\n }\n\n function appendCodePointAsUTF8(pIn_, c_) -> _pOut {\n if iszero(gt(c_, 0x7f)) {\n mstore8(pIn_, c_)\n _pOut := add(pIn_, 1)\n leave\n }\n mstore8(0x1f, c_)\n mstore8(0x1e, shr(6, c_))\n if iszero(gt(c_, 0x7ff)) {\n mstore(pIn_, shl(240, or(0xc080, and(0x1f3f, mload(0x00)))))\n _pOut := add(pIn_, 2)\n leave\n }\n mstore8(0x1d, shr(12, c_))\n if iszero(gt(c_, 0xffff)) {\n mstore(pIn_, shl(232, or(0xe08080, and(0x0f3f3f, mload(0x00)))))\n _pOut := add(pIn_, 3)\n leave\n }\n mstore8(0x1c, shr(18, c_))\n mstore(pIn_, shl(224, or(0xf0808080, and(0x073f3f3f, mload(0x00)))))\n _pOut := add(pIn_, shl(2, lt(c_, 0x110000)))\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n let n := mload(s)\n let end := add(add(s, n), 0x1f)\n if iszero(and(gt(n, 1), eq(0x2222, or(and(0xff00, mload(add(s, 2))), chr(end))))) {\n fail() // Fail if not double-quoted.\n }\n let out := add(mload(0x40), 0x20)\n for { let curr := add(s, 0x21) } iszero(eq(curr, end)) {} {\n let c := chr(curr)\n curr := add(curr, 1)\n // Not '\\\\'.\n if iszero(eq(c, 92)) {\n // Not '\"'.\n if iszero(eq(c, 34)) {\n mstore8(out, c)\n out := add(out, 1)\n continue\n }\n curr := end\n }\n if iszero(eq(curr, end)) {\n let escape := chr(curr)\n curr := add(curr, 1)\n // '\"', '/', '\\\\'.\n if and(shr(escape, 0x100000000000800400000000), 1) {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n // 'u'.\n if eq(escape, 117) {\n escape, curr := decodeUnicodeCodePoint(curr, end)\n out := appendCodePointAsUTF8(out, escape)\n continue\n }\n // `{'b':'\\b', 'f':'\\f', 'n':'\\n', 'r':'\\r', 't':'\\t'}`.\n escape := byte(sub(escape, 85), 0x080000000c000000000000000a0000000d0009)\n if escape {\n mstore8(out, escape)\n out := add(out, 1)\n continue\n }\n }\n fail()\n break\n }\n mstore(out, 0) // Zeroize the last slot.\n result := mload(0x40)\n mstore(result, sub(out, add(result, 0x20))) // Store the length.\n mstore(0x40, add(out, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* PRIVATE HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Performs a query on the input with the given mode.\n function _query(bytes32 input, uint256 mode) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n function fail() {\n mstore(0x00, 0x10182796) // `ParsingFailed()`.\n revert(0x1c, 0x04)\n }\n\n function chr(p_) -> _c {\n _c := byte(0, mload(p_))\n }\n\n function skipWhitespace(pIn_, end_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(and(shr(chr(_pOut), 0x100002600), 1)) { leave } // Not in ' \\n\\r\\t'.\n }\n }\n\n function setP(packed_, bitpos_, p_) -> _packed {\n // Perform an out-of-gas revert if `p_` exceeds `_BITMASK_POINTER`.\n returndatacopy(returndatasize(), returndatasize(), gt(p_, _BITMASK_POINTER))\n _packed := or(and(not(shl(bitpos_, _BITMASK_POINTER)), packed_), shl(bitpos_, p_))\n }\n\n function getP(packed_, bitpos_) -> _p {\n _p := and(_BITMASK_POINTER, shr(bitpos_, packed_))\n }\n\n function mallocItem(s_, packed_, pStart_, pCurr_, type_) -> _item {\n _item := mload(0x40)\n // forgefmt: disable-next-item\n packed_ := setP(setP(packed_, _BITPOS_VALUE, sub(pStart_, add(s_, 0x20))),\n _BITPOS_VALUE_LENGTH, sub(pCurr_, pStart_))\n mstore(_item, or(packed_, type_))\n mstore(0x40, add(_item, 0x20)) // Allocate memory.\n }\n\n function parseValue(s_, sibling_, pIn_, end_) -> _item, _pOut {\n let packed_ := setP(mload(0x00), _BITPOS_SIBLING_OR_PARENT, sibling_)\n _pOut := skipWhitespace(pIn_, end_)\n if iszero(lt(_pOut, end_)) { leave }\n for { let c_ := chr(_pOut) } 1 {} {\n // If starts with '\"'.\n if eq(c_, 34) {\n let pStart_ := _pOut\n _pOut := parseStringSub(s_, packed_, _pOut, end_)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_STRING)\n break\n }\n // If starts with '['.\n if eq(c_, 91) {\n _item, _pOut := parseArray(s_, packed_, _pOut, end_)\n break\n }\n // If starts with '{'.\n if eq(c_, 123) {\n _item, _pOut := parseObject(s_, packed_, _pOut, end_)\n break\n }\n // If starts with any in '0123456789-'.\n if and(shr(c_, shl(45, 0x1ff9)), 1) {\n _item, _pOut := parseNumber(s_, packed_, _pOut, end_)\n break\n }\n if iszero(gt(add(_pOut, 4), end_)) {\n let pStart_ := _pOut\n let w_ := shr(224, mload(_pOut))\n // 'true' in hex format.\n if eq(w_, 0x74727565) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n // 'null' in hex format.\n if eq(w_, 0x6e756c6c) {\n _pOut := add(_pOut, 4)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_NULL)\n break\n }\n }\n if iszero(gt(add(_pOut, 5), end_)) {\n let pStart_ := _pOut\n let w_ := shr(216, mload(_pOut))\n // 'false' in hex format.\n if eq(w_, 0x66616c7365) {\n _pOut := add(_pOut, 5)\n _item := mallocItem(s_, packed_, pStart_, _pOut, TYPE_BOOLEAN)\n break\n }\n }\n fail()\n break\n }\n _pOut := skipWhitespace(_pOut, end_)\n }\n\n function parseArray(s_, packed_, pIn_, end_) -> _item, _pOut {\n let j_ := 0\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 93) { break } // ']'.\n }\n _item, _pOut := parseValue(s_, _item, _pOut, end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(or(_PARENT_IS_ARRAY, mload(_item)),\n _BITPOS_KEY, j_))\n j_ := add(j_, 1)\n let c_ := chr(_pOut)\n if eq(c_, 93) { break } // ']'.\n if eq(c_, 44) { continue } // ','.\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_ARRAY)\n }\n\n function parseObject(s_, packed_, pIn_, end_) -> _item, _pOut {\n for { _pOut := add(pIn_, 1) } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(_pOut, end_)) { fail() }\n if iszero(_item) {\n _pOut := skipWhitespace(_pOut, end_)\n if eq(chr(_pOut), 125) { break } // '}'.\n }\n _pOut := skipWhitespace(_pOut, end_)\n let pKeyStart_ := _pOut\n let pKeyEnd_ := parseStringSub(s_, _item, _pOut, end_)\n _pOut := skipWhitespace(pKeyEnd_, end_)\n // If ':'.\n if eq(chr(_pOut), 58) {\n _item, _pOut := parseValue(s_, _item, add(_pOut, 1), end_)\n if _item {\n // forgefmt: disable-next-item\n mstore(_item, setP(setP(or(_PARENT_IS_OBJECT, mload(_item)),\n _BITPOS_KEY_LENGTH, sub(pKeyEnd_, pKeyStart_)),\n _BITPOS_KEY, sub(pKeyStart_, add(s_, 0x20))))\n let c_ := chr(_pOut)\n if eq(c_, 125) { break } // '}'.\n if eq(c_, 44) { continue } // ','.\n }\n }\n _pOut := end_\n }\n _pOut := add(_pOut, 1)\n packed_ := setP(packed_, _BITPOS_CHILD, _item)\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_OBJECT)\n }\n\n function checkStringU(p_, o_) {\n // If not in '0123456789abcdefABCDEF', revert.\n if iszero(and(shr(sub(chr(add(p_, o_)), 48), 0x7e0000007e03ff), 1)) { fail() }\n if iszero(eq(o_, 5)) { checkStringU(p_, add(o_, 1)) }\n }\n\n function parseStringSub(s_, packed_, pIn_, end_) -> _pOut {\n if iszero(lt(pIn_, end_)) { fail() }\n for { _pOut := add(pIn_, 1) } 1 {} {\n let c_ := chr(_pOut)\n if eq(c_, 34) { break } // '\"'.\n // Not '\\'.\n if iszero(eq(c_, 92)) {\n _pOut := add(_pOut, 1)\n continue\n }\n c_ := chr(add(_pOut, 1))\n // '\"', '\\', '//', 'b', 'f', 'n', 'r', 't'.\n if and(shr(sub(c_, 34), 0x510110400000000002001), 1) {\n _pOut := add(_pOut, 2)\n continue\n }\n // 'u'.\n if eq(c_, 117) {\n checkStringU(_pOut, 2)\n _pOut := add(_pOut, 6)\n continue\n }\n _pOut := end_\n break\n }\n if iszero(lt(_pOut, end_)) { fail() }\n _pOut := add(_pOut, 1)\n }\n\n function skip0To9s(pIn_, end_, atLeastOne_) -> _pOut {\n for { _pOut := pIn_ } 1 { _pOut := add(_pOut, 1) } {\n if iszero(lt(sub(chr(_pOut), 48), 10)) { break } // Not '0'..'9'.\n }\n if and(atLeastOne_, eq(pIn_, _pOut)) { fail() }\n }\n\n function parseNumber(s_, packed_, pIn_, end_) -> _item, _pOut {\n _pOut := pIn_\n if eq(chr(_pOut), 45) { _pOut := add(_pOut, 1) } // '-'.\n if iszero(lt(sub(chr(_pOut), 48), 10)) { fail() } // Not '0'..'9'.\n let c_ := chr(_pOut)\n _pOut := add(_pOut, 1)\n if iszero(eq(c_, 48)) { _pOut := skip0To9s(_pOut, end_, 0) } // Not '0'.\n if eq(chr(_pOut), 46) { _pOut := skip0To9s(add(_pOut, 1), end_, 1) } // '.'.\n let t_ := mload(_pOut)\n // 'E', 'e'.\n if eq(or(0x20, byte(0, t_)), 101) {\n // forgefmt: disable-next-item\n _pOut := skip0To9s(add(byte(sub(byte(1, t_), 14), 0x010001), // '+', '-'.\n add(_pOut, 1)), end_, 1)\n }\n _item := mallocItem(s_, packed_, pIn_, _pOut, TYPE_NUMBER)\n }\n\n function copyStr(s_, offset_, len_) -> _sCopy {\n _sCopy := mload(0x40)\n s_ := add(s_, offset_)\n let w_ := not(0x1f)\n for { let i_ := and(add(len_, 0x1f), w_) } 1 {} {\n mstore(add(_sCopy, i_), mload(add(s_, i_)))\n i_ := add(i_, w_) // `sub(i_, 0x20)`.\n if iszero(i_) { break }\n }\n mstore(_sCopy, len_) // Copy the length.\n mstore(add(add(_sCopy, 0x20), len_), 0) // Zeroize the last slot.\n mstore(0x40, add(add(_sCopy, 0x40), len_)) // Allocate memory.\n }\n\n function value(item_) -> _value {\n let packed_ := mload(item_)\n _value := getP(packed_, _BITPOS_VALUE) // The offset in the string.\n if iszero(and(_VALUE_INITED, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _value := copyStr(s_, _value, getP(packed_, _BITPOS_VALUE_LENGTH))\n packed_ := setP(packed_, _BITPOS_VALUE, _value)\n mstore(s_, or(_VALUE_INITED, packed_))\n }\n }\n\n function children(item_) -> _arr {\n _arr := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n for {} iszero(gt(and(_BITMASK_TYPE, packed_), TYPE_OBJECT)) {} {\n if or(iszero(packed_), iszero(item_)) { break }\n if and(packed_, _CHILDREN_INITED) {\n _arr := getP(packed_, _BITPOS_CHILD)\n break\n }\n _arr := mload(0x40)\n let o_ := add(_arr, 0x20)\n for { let h_ := getP(packed_, _BITPOS_CHILD) } h_ {} {\n mstore(o_, h_)\n let q_ := mload(h_)\n let y_ := getP(q_, _BITPOS_SIBLING_OR_PARENT)\n mstore(h_, setP(q_, _BITPOS_SIBLING_OR_PARENT, item_))\n h_ := y_\n o_ := add(o_, 0x20)\n }\n let w_ := not(0x1f)\n let n_ := add(w_, sub(o_, _arr))\n mstore(_arr, shr(5, n_))\n mstore(0x40, o_) // Allocate memory.\n packed_ := setP(packed_, _BITPOS_CHILD, _arr)\n mstore(item_, or(_CHILDREN_INITED, packed_))\n // Reverse the array.\n if iszero(lt(n_, 0x40)) {\n let lo_ := add(_arr, 0x20)\n let hi_ := add(_arr, n_)\n for {} 1 {} {\n let temp_ := mload(lo_)\n mstore(lo_, mload(hi_))\n mstore(hi_, temp_)\n hi_ := add(hi_, w_)\n lo_ := add(lo_, 0x20)\n if iszero(lt(lo_, hi_)) { break }\n }\n }\n break\n }\n }\n\n function getStr(item_, bitpos_, bitposLength_, bitmaskInited_) -> _result {\n _result := 0x60 // Initialize to the zero pointer.\n let packed_ := mload(item_)\n if or(iszero(item_), iszero(packed_)) { leave }\n _result := getP(packed_, bitpos_)\n if iszero(and(bitmaskInited_, packed_)) {\n let s_ := getP(packed_, _BITPOS_STRING)\n _result := copyStr(s_, _result, getP(packed_, bitposLength_))\n mstore(item_, or(bitmaskInited_, setP(packed_, bitpos_, _result)))\n }\n }\n\n switch mode\n // Get value.\n case 0 { result := getStr(input, _BITPOS_VALUE, _BITPOS_VALUE_LENGTH, _VALUE_INITED) }\n // Get key.\n case 1 { result := getStr(input, _BITPOS_KEY, _BITPOS_KEY_LENGTH, _KEY_INITED) }\n // Get children.\n case 3 { result := children(input) }\n // Parse.\n default {\n let p := add(input, 0x20)\n let e := add(p, mload(input))\n if iszero(eq(p, e)) {\n let c := chr(e)\n mstore8(e, 34) // Place a '\"' at the end to speed up parsing.\n // The `34 << 248` makes `mallocItem` preserve '\"' at the end.\n mstore(0x00, setP(shl(248, 34), _BITPOS_STRING, input))\n result, p := parseValue(input, 0, p, e)\n mstore8(e, c) // Restore the original char at the end.\n }\n if or(lt(p, e), iszero(result)) { fail() }\n }\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(string memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n\n /// @dev Casts the input to a bytes32.\n function _toInput(Item memory input) private pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := input\n }\n }\n}\n" + }, + "solady/src/utils/LibString.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Library for converting numbers into strings and other string operations.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)\n/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)\n///\n/// Note:\n/// For performance and bytecode compactness, most of the string operations are restricted to\n/// byte strings (7-bit ASCII), except where otherwise specified.\n/// Usage of byte string operations on charsets with runes spanning two or more bytes\n/// can lead to undefined behavior.\nlibrary LibString {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The length of the output is too small to contain all the hex digits.\n error HexLengthInsufficient();\n\n /// @dev The length of the string is more than 32 bytes.\n error TooBigForSmallString();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CONSTANTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The constant returned when the `search` is not found in the string.\n uint256 internal constant NOT_FOUND = type(uint256).max;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* DECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n // We will need 1 word for the trailing zeros padding, 1 word for the length,\n // and 3 words for a maximum of 78 digits.\n str := add(mload(0x40), 0x80)\n // Update the free memory pointer to allocate.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end of the memory to calculate the length later.\n let end := str\n\n let w := not(0) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 1)`.\n // Write the character to the pointer.\n // The ASCII index of the '0' character is 48.\n mstore8(str, add(48, mod(temp, 10)))\n // Keep dividing `temp` until zero.\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n\n let length := sub(end, str)\n // Move the pointer 32 bytes leftwards to make room for the length.\n str := sub(str, 0x20)\n // Store the length.\n mstore(str, length)\n }\n }\n\n /// @dev Returns the base 10 decimal representation of `value`.\n function toString(int256 value) internal pure returns (string memory str) {\n if (value >= 0) {\n return toString(uint256(value));\n }\n unchecked {\n str = toString(~uint256(value) + 1);\n }\n /// @solidity memory-safe-assembly\n assembly {\n // We still have some spare memory space on the left,\n // as we have allocated 3 words (96 bytes) for up to 78 digits.\n let length := mload(str) // Load the string length.\n mstore(str, 0x2d) // Store the '-' character.\n str := sub(str, 1) // Move back the string pointer by a byte.\n mstore(str, add(length, 1)) // Update the string length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HEXADECIMAL OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2 + 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value, length);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`,\n /// left-padded to an input length of `length` bytes.\n /// The output is prefixed with \"0x\" encoded using 2 hexadecimal digits per byte,\n /// giving a total length of `length * 2` bytes.\n /// Reverts if `length` is too small for the output to contain all the digits.\n function toHexStringNoPrefix(uint256 value, uint256 length)\n internal\n pure\n returns (string memory str)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes\n // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.\n // We add 0x20 to the total and round down to a multiple of 0x20.\n // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.\n str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let start := sub(str, add(length, length))\n let w := not(1) // Tsk.\n let temp := value\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for {} 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(xor(str, start)) { break }\n }\n\n if temp {\n mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.\n revert(0x1c, 0x04)\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2 + 2` bytes.\n function toHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\".\n /// The output excludes leading \"0\" from the `toHexString` output.\n /// `0x00: \"0x0\", 0x01: \"0x1\", 0x12: \"0x12\", 0x123: \"0x123\"`.\n function toMinimalHexString(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(add(str, o), 0x3078) // Write the \"0x\" prefix, accounting for leading zero.\n str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output excludes leading \"0\" from the `toHexStringNoPrefix` output.\n /// `0x00: \"0\", 0x01: \"1\", 0x12: \"12\", 0x123: \"123\"`.\n function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.\n let strLength := mload(str) // Get the length.\n str := add(str, o) // Move the pointer, accounting for leading zero.\n mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n /// As address are 20 bytes long, the output will left-padded to have\n /// a length of `20 * 2` bytes.\n function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x40 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.\n str := add(mload(0x40), 0x80)\n // Allocate the memory.\n mstore(0x40, add(str, 0x20))\n // Zeroize the slot after the string.\n mstore(str, 0)\n\n // Cache the end to calculate the length later.\n let end := str\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let w := not(1) // Tsk.\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let temp := value } 1 {} {\n str := add(str, w) // `sub(str, 2)`.\n mstore8(add(str, 1), mload(and(temp, 15)))\n mstore8(str, mload(and(shr(4, temp), 15)))\n temp := shr(8, temp)\n if iszero(temp) { break }\n }\n\n // Compute the string's length.\n let strLength := sub(end, str)\n // Move the pointer and write the length.\n str := sub(str, 0x20)\n mstore(str, strLength)\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\", encoded using 2 hexadecimal digits per byte,\n /// and the alphabets are capitalized conditionally according to\n /// https://eips.ethereum.org/EIPS/eip-55\n function toHexStringChecksummed(address value) internal pure returns (string memory str) {\n str = toHexString(value);\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`\n let o := add(str, 0x22)\n let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `\n let t := shl(240, 136) // `0b10001000 << 240`\n for { let i := 0 } 1 {} {\n mstore(add(i, i), mul(t, byte(i, hashed)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))\n o := add(o, 0x20)\n mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is prefixed with \"0x\" and encoded using 2 hexadecimal digits per byte.\n function toHexString(address value) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(value);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hexadecimal representation of `value`.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(address value) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n str := mload(0x40)\n\n // Allocate the memory.\n // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,\n // 0x02 bytes for the prefix, and 0x28 bytes for the digits.\n // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.\n mstore(0x40, add(str, 0x80))\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n str := add(str, 2)\n mstore(str, 40)\n\n let o := add(str, 0x20)\n mstore(add(o, 40), 0)\n\n value := shl(96, value)\n\n // We write the string from rightmost digit to leftmost digit.\n // The following is essentially a do-while loop that also handles the zero case.\n for { let i := 0 } 1 {} {\n let p := add(o, add(i, i))\n let temp := byte(i, value)\n mstore8(add(p, 1), mload(and(temp, 15)))\n mstore8(p, mload(shr(4, temp)))\n i := add(i, 1)\n if eq(i, 20) { break }\n }\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexString(bytes memory raw) internal pure returns (string memory str) {\n str = toHexStringNoPrefix(raw);\n /// @solidity memory-safe-assembly\n assembly {\n let strLength := add(mload(str), 2) // Compute the length.\n mstore(str, 0x3078) // Write the \"0x\" prefix.\n str := sub(str, 2) // Move the pointer.\n mstore(str, strLength) // Write the length.\n }\n }\n\n /// @dev Returns the hex encoded string from the raw bytes.\n /// The output is encoded using 2 hexadecimal digits per byte.\n function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(raw)\n str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.\n mstore(str, add(length, length)) // Store the length of the output.\n\n // Store \"0123456789abcdef\" in scratch space.\n mstore(0x0f, 0x30313233343536373839616263646566)\n\n let o := add(str, 0x20)\n let end := add(raw, length)\n\n for {} iszero(eq(raw, end)) {} {\n raw := add(raw, 1)\n mstore8(add(o, 1), mload(and(mload(raw), 15)))\n mstore8(o, mload(and(shr(4, mload(raw)), 15)))\n o := add(o, 2)\n }\n mstore(o, 0) // Zeroize the slot after the string.\n mstore(0x40, add(o, 0x20)) // Allocate the memory.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* RUNE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the number of UTF characters in the string.\n function runeCount(string memory s) internal pure returns (uint256 result) {\n /// @solidity memory-safe-assembly\n assembly {\n if mload(s) {\n mstore(0x00, div(not(0), 255))\n mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)\n let o := add(s, 0x20)\n let end := add(o, mload(s))\n for { result := 1 } 1 { result := add(result, 1) } {\n o := add(o, byte(0, mload(shr(250, mload(o)))))\n if iszero(lt(o, end)) { break }\n }\n }\n }\n }\n\n /// @dev Returns if this string is a 7-bit ASCII string.\n /// (i.e. all characters codes are in [0..127])\n function is7BitASCII(string memory s) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let mask := shl(7, div(not(0), 255))\n result := 1\n let n := mload(s)\n if n {\n let o := add(s, 0x20)\n let end := add(o, n)\n let last := mload(end)\n mstore(end, 0)\n for {} 1 {} {\n if and(mask, mload(o)) {\n result := 0\n break\n }\n o := add(o, 0x20)\n if iszero(lt(o, end)) { break }\n }\n mstore(end, last)\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* BYTE STRING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // For performance and bytecode compactness, byte string operations are restricted\n // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.\n // Usage of byte string operations on charsets with runes spanning two or more bytes\n // can lead to undefined behavior.\n\n /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.\n function replace(string memory subject, string memory search, string memory replacement)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n let replacementLength := mload(replacement)\n\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n replacement := add(replacement, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectEnd := add(subject, subjectLength)\n if iszero(gt(searchLength, subjectLength)) {\n let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Copy the `replacement` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(result, o), mload(add(replacement, o)))\n o := add(o, 0x20)\n if iszero(lt(o, replacementLength)) { break }\n }\n result := add(result, replacementLength)\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n mstore(result, t)\n result := add(result, 1)\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n }\n\n let resultRemainder := result\n result := add(mload(0x40), 0x20)\n let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))\n // Copy the rest of the string one word at a time.\n for {} lt(subject, subjectEnd) {} {\n mstore(resultRemainder, mload(subject))\n resultRemainder := add(resultRemainder, 0x20)\n subject := add(subject, 0x20)\n }\n result := sub(result, 0x20)\n let last := add(add(result, 0x20), k) // Zeroize the slot after the string.\n mstore(last, 0)\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n mstore(result, k) // Store the length.\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for { let subjectLength := mload(subject) } 1 {} {\n if iszero(mload(search)) {\n if iszero(gt(from, subjectLength)) {\n result := from\n break\n }\n result := subjectLength\n break\n }\n let searchLength := mload(search)\n let subjectStart := add(subject, 0x20)\n\n result := not(0) // Initialize to `NOT_FOUND`.\n\n subject := add(subjectStart, from)\n let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)\n\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(add(search, 0x20))\n\n if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }\n\n if iszero(lt(searchLength, 0x20)) {\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, subjectStart)\n break\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n for {} 1 {} {\n if iszero(shr(m, xor(mload(subject), s))) {\n result := sub(subject, subjectStart)\n break\n }\n subject := add(subject, 1)\n if iszero(lt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from left to right.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function indexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = indexOf(subject, search, 0);\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left, starting from `from`.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search, uint256 from)\n internal\n pure\n returns (uint256 result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n for {} 1 {} {\n result := not(0) // Initialize to `NOT_FOUND`.\n let searchLength := mload(search)\n if gt(searchLength, mload(subject)) { break }\n let w := result\n\n let fromMax := sub(mload(subject), searchLength)\n if iszero(gt(fromMax, from)) { from := fromMax }\n\n let end := add(add(subject, 0x20), w)\n subject := add(add(subject, 0x20), from)\n if iszero(gt(subject, end)) { break }\n // As this function is not too often used,\n // we shall simply use keccak256 for smaller bytecode size.\n for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {\n if eq(keccak256(subject, searchLength), h) {\n result := sub(subject, add(end, 1))\n break\n }\n subject := add(subject, w) // `sub(subject, 1)`.\n if iszero(gt(subject, end)) { break }\n }\n break\n }\n }\n }\n\n /// @dev Returns the byte index of the first location of `search` in `subject`,\n /// searching from right to left.\n /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.\n function lastIndexOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256 result)\n {\n result = lastIndexOf(subject, search, uint256(int256(-1)));\n }\n\n /// @dev Returns true if `search` is found in `subject`, false otherwise.\n function contains(string memory subject, string memory search) internal pure returns (bool) {\n return indexOf(subject, search) != NOT_FOUND;\n }\n\n /// @dev Returns whether `subject` starts with `search`.\n function startsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n iszero(gt(searchLength, mload(subject))),\n eq(\n keccak256(add(subject, 0x20), searchLength),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns whether `subject` ends with `search`.\n function endsWith(string memory subject, string memory search)\n internal\n pure\n returns (bool result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let searchLength := mload(search)\n let subjectLength := mload(subject)\n // Whether `search` is not longer than `subject`.\n let withinRange := iszero(gt(searchLength, subjectLength))\n // Just using keccak256 directly is actually cheaper.\n // forgefmt: disable-next-item\n result := and(\n withinRange,\n eq(\n keccak256(\n // `subject + 0x20 + max(subjectLength - searchLength, 0)`.\n add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),\n searchLength\n ),\n keccak256(add(search, 0x20), searchLength)\n )\n )\n }\n }\n\n /// @dev Returns `subject` repeated `times`.\n function repeat(string memory subject, uint256 times)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(or(iszero(times), iszero(subjectLength))) {\n subject := add(subject, 0x20)\n result := mload(0x40)\n let output := add(result, 0x20)\n for {} 1 {} {\n // Copy the `subject` one word at a time.\n for { let o := 0 } 1 {} {\n mstore(add(output, o), mload(add(subject, o)))\n o := add(o, 0x20)\n if iszero(lt(o, subjectLength)) { break }\n }\n output := add(output, subjectLength)\n times := sub(times, 1)\n if iszero(times) { break }\n }\n mstore(output, 0) // Zeroize the slot after the string.\n let resultLength := sub(output, add(result, 0x20))\n mstore(result, resultLength) // Store the length.\n // Allocate the memory.\n mstore(0x40, add(result, add(resultLength, 0x20)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).\n /// `start` and `end` are byte offsets.\n function slice(string memory subject, uint256 start, uint256 end)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n if iszero(gt(subjectLength, end)) { end := subjectLength }\n if iszero(gt(subjectLength, start)) { start := subjectLength }\n if lt(start, end) {\n result := mload(0x40)\n let resultLength := sub(end, start)\n mstore(result, resultLength)\n subject := add(subject, start)\n let w := not(0x1f)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(resultLength, 0x1f), w) } 1 {} {\n mstore(add(result, o), mload(add(subject, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(result, 0x20), resultLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))\n }\n }\n }\n\n /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.\n /// `start` is a byte offset.\n function slice(string memory subject, uint256 start)\n internal\n pure\n returns (string memory result)\n {\n result = slice(subject, start, uint256(int256(-1)));\n }\n\n /// @dev Returns all the indices of `search` in `subject`.\n /// The indices are byte offsets.\n function indicesOf(string memory subject, string memory search)\n internal\n pure\n returns (uint256[] memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let subjectLength := mload(subject)\n let searchLength := mload(search)\n\n if iszero(gt(searchLength, subjectLength)) {\n subject := add(subject, 0x20)\n search := add(search, 0x20)\n result := add(mload(0x40), 0x20)\n\n let subjectStart := subject\n let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)\n let h := 0\n if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }\n let m := shl(3, sub(0x20, and(searchLength, 0x1f)))\n let s := mload(search)\n for {} 1 {} {\n let t := mload(subject)\n // Whether the first `searchLength % 32` bytes of\n // `subject` and `search` matches.\n if iszero(shr(m, xor(t, s))) {\n if h {\n if iszero(eq(keccak256(subject, searchLength), h)) {\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n // Append to `result`.\n mstore(result, sub(subject, subjectStart))\n result := add(result, 0x20)\n // Advance `subject` by `searchLength`.\n subject := add(subject, searchLength)\n if searchLength {\n if iszero(lt(subject, subjectSearchEnd)) { break }\n continue\n }\n }\n subject := add(subject, 1)\n if iszero(lt(subject, subjectSearchEnd)) { break }\n }\n let resultEnd := result\n // Assign `result` to the free memory pointer.\n result := mload(0x40)\n // Store the length of `result`.\n mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))\n // Allocate memory for result.\n // We allocate one more word, so this array can be recycled for {split}.\n mstore(0x40, add(resultEnd, 0x20))\n }\n }\n }\n\n /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.\n function split(string memory subject, string memory delimiter)\n internal\n pure\n returns (string[] memory result)\n {\n uint256[] memory indices = indicesOf(subject, delimiter);\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n let indexPtr := add(indices, 0x20)\n let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))\n mstore(add(indicesEnd, w), mload(subject))\n mstore(indices, add(mload(indices), 1))\n let prevIndex := 0\n for {} 1 {} {\n let index := mload(indexPtr)\n mstore(indexPtr, 0x60)\n if iszero(eq(index, prevIndex)) {\n let element := mload(0x40)\n let elementLength := sub(index, prevIndex)\n mstore(element, elementLength)\n // Copy the `subject` one word at a time, backwards.\n for { let o := and(add(elementLength, 0x1f), w) } 1 {} {\n mstore(add(element, o), mload(add(add(subject, prevIndex), o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n // Zeroize the slot after the string.\n mstore(add(add(element, 0x20), elementLength), 0)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))\n // Store the `element` into the array.\n mstore(indexPtr, element)\n }\n prevIndex := add(index, mload(delimiter))\n indexPtr := add(indexPtr, 0x20)\n if iszero(lt(indexPtr, indicesEnd)) { break }\n }\n result := indices\n if iszero(mload(delimiter)) {\n result := add(indices, 0x20)\n mstore(result, sub(mload(indices), 2))\n }\n }\n }\n\n /// @dev Returns a concatenated string of `a` and `b`.\n /// Cheaper than `string.concat()` and does not de-align the free memory pointer.\n function concat(string memory a, string memory b)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let w := not(0x1f)\n result := mload(0x40)\n let aLength := mload(a)\n // Copy `a` one word at a time, backwards.\n for { let o := and(add(aLength, 0x20), w) } 1 {} {\n mstore(add(result, o), mload(add(a, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let bLength := mload(b)\n let output := add(result, aLength)\n // Copy `b` one word at a time, backwards.\n for { let o := and(add(bLength, 0x20), w) } 1 {} {\n mstore(add(output, o), mload(add(b, o)))\n o := add(o, w) // `sub(o, 0x20)`.\n if iszero(o) { break }\n }\n let totalLength := add(aLength, bLength)\n let last := add(add(result, 0x20), totalLength)\n // Zeroize the slot after the string.\n mstore(last, 0)\n // Stores the length.\n mstore(result, totalLength)\n // Allocate memory for the length and the bytes,\n // rounded up to a multiple of 32.\n mstore(0x40, and(add(last, 0x1f), w))\n }\n }\n\n /// @dev Returns a copy of the string in either lowercase or UPPERCASE.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function toCase(string memory subject, bool toUpper)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let length := mload(subject)\n if length {\n result := add(mload(0x40), 0x20)\n subject := add(subject, 1)\n let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)\n let w := not(0)\n for { let o := length } 1 {} {\n o := add(o, w)\n let b := and(0xff, mload(add(subject, o)))\n mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))\n if iszero(o) { break }\n }\n result := mload(0x40)\n mstore(result, length) // Store the length.\n let last := add(add(result, 0x20), length)\n mstore(last, 0) // Zeroize the slot after the string.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n }\n\n /// @dev Returns a string from a small bytes32 string.\n /// `s` must be null-terminated, or behavior will be undefined.\n function fromSmallString(bytes32 s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(0x40)\n let n := 0\n for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\\0'.\n mstore(result, n)\n let o := add(result, 0x20)\n mstore(o, s)\n mstore(add(o, n), 0)\n mstore(0x40, add(result, 0x40))\n }\n }\n\n /// @dev Returns the small string, with all bytes after the first null byte zeroized.\n function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\\0'.\n mstore(0x00, s)\n mstore(result, 0x00)\n result := mload(0x00)\n }\n }\n\n /// @dev Returns the string as a normalized null-terminated small string.\n function toSmallString(string memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := mload(s)\n if iszero(lt(result, 33)) {\n mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.\n revert(0x1c, 0x04)\n }\n result := shl(shl(3, sub(32, result)), mload(add(s, result)))\n }\n }\n\n /// @dev Returns a lowercased copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function lower(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, false);\n }\n\n /// @dev Returns an UPPERCASED copy of the string.\n /// WARNING! This function is only compatible with 7-bit ASCII strings.\n function upper(string memory subject) internal pure returns (string memory result) {\n result = toCase(subject, true);\n }\n\n /// @dev Escapes the string to be used within HTML tags.\n function escapeHTML(string memory s) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n // Store the bytes of the packed offsets and strides into the scratch space.\n // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.\n mstore(0x1f, 0x900094)\n mstore(0x08, 0xc0000000a6ab)\n // Store \""&'<>\" into the scratch space.\n mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n // Not in `[\"\\\"\",\"'\",\"&\",\"<\",\">\"]`.\n if iszero(and(shl(c, 1), 0x500000c400000000)) {\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n let t := shr(248, mload(c))\n mstore(result, mload(and(t, 0x1f)))\n result := add(result, shr(5, t))\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.\n function escapeJSON(string memory s, bool addDoubleQuotes)\n internal\n pure\n returns (string memory result)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let end := add(s, mload(s))\n result := add(mload(0x40), 0x20)\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n // Store \"\\\\u0000\" in scratch space.\n // Store \"0123456789abcdef\" in scratch space.\n // Also, store `{0x08:\"b\", 0x09:\"t\", 0x0a:\"n\", 0x0c:\"f\", 0x0d:\"r\"}`.\n // into the scratch space.\n mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)\n // Bitmask for detecting `[\"\\\"\",\"\\\\\"]`.\n let e := or(shl(0x22, 1), shl(0x5c, 1))\n for {} iszero(eq(s, end)) {} {\n s := add(s, 1)\n let c := and(mload(s), 0xff)\n if iszero(lt(c, 0x20)) {\n if iszero(and(shl(c, 1), e)) {\n // Not in `[\"\\\"\",\"\\\\\"]`.\n mstore8(result, c)\n result := add(result, 1)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), c)\n result := add(result, 2)\n continue\n }\n if iszero(and(shl(c, 1), 0x3700)) {\n // Not in `[\"\\b\",\"\\t\",\"\\n\",\"\\f\",\"\\d\"]`.\n mstore8(0x1d, mload(shr(4, c))) // Hex value.\n mstore8(0x1e, mload(and(c, 15))) // Hex value.\n mstore(result, mload(0x19)) // \"\\\\u00XX\".\n result := add(result, 6)\n continue\n }\n mstore8(result, 0x5c) // \"\\\\\".\n mstore8(add(result, 1), mload(add(c, 8)))\n result := add(result, 2)\n }\n if addDoubleQuotes {\n mstore8(result, 34)\n result := add(1, result)\n }\n let last := result\n mstore(last, 0) // Zeroize the slot after the string.\n result := mload(0x40)\n mstore(result, sub(last, add(result, 0x20))) // Store the length.\n mstore(0x40, add(last, 0x20)) // Allocate the memory.\n }\n }\n\n /// @dev Escapes the string to be used within double-quotes in a JSON.\n function escapeJSON(string memory s) internal pure returns (string memory result) {\n result = escapeJSON(s, false);\n }\n\n /// @dev Returns whether `a` equals `b`.\n function eq(string memory a, string memory b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))\n }\n }\n\n /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.\n function eqs(string memory a, bytes32 b) internal pure returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n // These should be evaluated on compile time, as far as possible.\n let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.\n let x := not(or(m, or(b, add(m, and(b, m)))))\n let r := shl(7, iszero(iszero(shr(128, x))))\n r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))\n r := or(r, shl(5, lt(0xffffffff, shr(r, x))))\n r := or(r, shl(4, lt(0xffff, shr(r, x))))\n r := or(r, shl(3, lt(0xff, shr(r, x))))\n // forgefmt: disable-next-item\n result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),\n xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))\n }\n }\n\n /// @dev Packs a single string with its length into a single word.\n /// Returns `bytes32(0)` if the length is zero or greater than 31.\n function packOne(string memory a) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n // We don't need to zero right pad the string,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes.\n mload(add(a, 0x1f)),\n // `length != 0 && length < 32`. Abuses underflow.\n // Assumes that the length is valid and within the block gas limit.\n lt(sub(mload(a), 1), 0x1f)\n )\n }\n }\n\n /// @dev Unpacks a string packed using {packOne}.\n /// Returns the empty string if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packOne}, the output behavior is undefined.\n function unpackOne(bytes32 packed) internal pure returns (string memory result) {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n result := mload(0x40)\n // Allocate 2 words (1 for the length, 1 for the bytes).\n mstore(0x40, add(result, 0x40))\n // Zeroize the length slot.\n mstore(result, 0)\n // Store the length and bytes.\n mstore(add(result, 0x1f), packed)\n // Right pad with zeroes.\n mstore(add(add(result, 0x20), mload(result)), 0)\n }\n }\n\n /// @dev Packs two strings with their lengths into a single word.\n /// Returns `bytes32(0)` if combined length is zero or greater than 30.\n function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let aLength := mload(a)\n // We don't need to zero right pad the strings,\n // since this is our own custom non-standard packing scheme.\n result :=\n mul(\n // Load the length and the bytes of `a` and `b`.\n or(\n shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),\n mload(sub(add(b, 0x1e), aLength))\n ),\n // `totalLength != 0 && totalLength < 31`. Abuses underflow.\n // Assumes that the lengths are valid and within the block gas limit.\n lt(sub(add(aLength, mload(b)), 1), 0x1e)\n )\n }\n }\n\n /// @dev Unpacks strings packed using {packTwo}.\n /// Returns the empty strings if `packed` is `bytes32(0)`.\n /// If `packed` is not an output of {packTwo}, the output behavior is undefined.\n function unpackTwo(bytes32 packed)\n internal\n pure\n returns (string memory resultA, string memory resultB)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Grab the free memory pointer.\n resultA := mload(0x40)\n resultB := add(resultA, 0x40)\n // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.\n mstore(0x40, add(resultB, 0x40))\n // Zeroize the length slots.\n mstore(resultA, 0)\n mstore(resultB, 0)\n // Store the lengths and bytes.\n mstore(add(resultA, 0x1f), packed)\n mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))\n // Right pad with zeroes.\n mstore(add(add(resultA, 0x20), mload(resultA)), 0)\n mstore(add(add(resultB, 0x20), mload(resultB)), 0)\n }\n }\n\n /// @dev Directly returns `a` without copying.\n function directReturn(string memory a) internal pure {\n assembly {\n // Assumes that the string does not start from the scratch space.\n let retStart := sub(a, 0x20)\n let retSize := add(mload(a), 0x40)\n // Right pad with zeroes. Just in case the string is produced\n // by a method that doesn't zero right pad.\n mstore(add(retStart, retSize), 0)\n // Store the return offset.\n mstore(retStart, 0x20)\n // End the transaction, returning the string.\n return(retStart, retSize)\n }\n }\n}\n" + }, + "solidity-rlp/contracts/RLPReader.sol": { + "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * @author Hamdi Allam hamdi.allam97@gmail.com\n * Please reach out with any questions or concerns\n */\npragma solidity >=0.5.10 <0.9.0;\n\nlibrary RLPReader {\n uint8 constant STRING_SHORT_START = 0x80;\n uint8 constant STRING_LONG_START = 0xb8;\n uint8 constant LIST_SHORT_START = 0xc0;\n uint8 constant LIST_LONG_START = 0xf8;\n uint8 constant WORD_SIZE = 32;\n\n struct RLPItem {\n uint256 len;\n uint256 memPtr;\n }\n\n struct Iterator {\n RLPItem item; // Item that's being iterated over.\n uint256 nextPtr; // Position of the next item in the list.\n }\n\n /*\n * @dev Returns the next element in the iteration. Reverts if it has not next element.\n * @param self The iterator.\n * @return The next element in the iteration.\n */\n function next(Iterator memory self) internal pure returns (RLPItem memory) {\n require(hasNext(self));\n\n uint256 ptr = self.nextPtr;\n uint256 itemLength = _itemLength(ptr);\n self.nextPtr = ptr + itemLength;\n\n return RLPItem(itemLength, ptr);\n }\n\n /*\n * @dev Returns true if the iteration has more elements.\n * @param self The iterator.\n * @return true if the iteration has more elements.\n */\n function hasNext(Iterator memory self) internal pure returns (bool) {\n RLPItem memory item = self.item;\n return self.nextPtr < item.memPtr + item.len;\n }\n\n /*\n * @param item RLP encoded bytes\n */\n function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {\n uint256 memPtr;\n assembly {\n memPtr := add(item, 0x20)\n }\n\n return RLPItem(item.length, memPtr);\n }\n\n /*\n * @dev Create an iterator. Reverts if item is not a list.\n * @param self The RLP item.\n * @return An 'Iterator' over the item.\n */\n function iterator(RLPItem memory self) internal pure returns (Iterator memory) {\n require(isList(self));\n\n uint256 ptr = self.memPtr + _payloadOffset(self.memPtr);\n return Iterator(self, ptr);\n }\n\n /*\n * @param the RLP item.\n */\n function rlpLen(RLPItem memory item) internal pure returns (uint256) {\n return item.len;\n }\n\n /*\n * @param the RLP item.\n * @return (memPtr, len) pair: location of the item's payload in memory.\n */\n function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) {\n uint256 offset = _payloadOffset(item.memPtr);\n uint256 memPtr = item.memPtr + offset;\n uint256 len = item.len - offset; // data length\n return (memPtr, len);\n }\n\n /*\n * @param the RLP item.\n */\n function payloadLen(RLPItem memory item) internal pure returns (uint256) {\n (, uint256 len) = payloadLocation(item);\n return len;\n }\n\n /*\n * @param the RLP item containing the encoded list.\n */\n function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {\n require(isList(item));\n\n uint256 items = numItems(item);\n RLPItem[] memory result = new RLPItem[](items);\n\n uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 dataLen;\n for (uint256 i = 0; i < items; i++) {\n dataLen = _itemLength(memPtr);\n result[i] = RLPItem(dataLen, memPtr);\n memPtr = memPtr + dataLen;\n }\n\n return result;\n }\n\n // @return indicator whether encoded payload is a list. negate this function call for isData.\n function isList(RLPItem memory item) internal pure returns (bool) {\n if (item.len == 0) return false;\n\n uint8 byte0;\n uint256 memPtr = item.memPtr;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < LIST_SHORT_START) return false;\n return true;\n }\n\n /*\n * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.\n * @return keccak256 hash of RLP encoded bytes.\n */\n function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n uint256 ptr = item.memPtr;\n uint256 len = item.len;\n bytes32 result;\n assembly {\n result := keccak256(ptr, len)\n }\n return result;\n }\n\n /*\n * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.\n * @return keccak256 hash of the item payload.\n */\n function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) {\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes32 result;\n assembly {\n result := keccak256(memPtr, len)\n }\n return result;\n }\n\n /** RLPItem conversions into data types **/\n\n // @returns raw rlp encoding in bytes\n function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {\n bytes memory result = new bytes(item.len);\n if (result.length == 0) return result;\n\n uint256 ptr;\n assembly {\n ptr := add(0x20, result)\n }\n\n copy(item.memPtr, ptr, item.len);\n return result;\n }\n\n // any non-zero byte except \"0x80\" is considered true\n function toBoolean(RLPItem memory item) internal pure returns (bool) {\n require(item.len == 1);\n uint256 result;\n uint256 memPtr = item.memPtr;\n assembly {\n result := byte(0, mload(memPtr))\n }\n\n // SEE Github Issue #5.\n // Summary: Most commonly used RLP libraries (i.e Geth) will encode\n // \"0\" as \"0x80\" instead of as \"0\". We handle this edge case explicitly\n // here.\n if (result == 0 || result == STRING_SHORT_START) {\n return false;\n } else {\n return true;\n }\n }\n\n function toAddress(RLPItem memory item) internal pure returns (address) {\n // 1 byte for the length prefix\n require(item.len == 21);\n\n return address(uint160(toUint(item)));\n }\n\n function toUint(RLPItem memory item) internal pure returns (uint256) {\n require(item.len > 0 && item.len <= 33);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n\n uint256 result;\n assembly {\n result := mload(memPtr)\n\n // shift to the correct location if neccesary\n if lt(len, 32) {\n result := div(result, exp(256, sub(32, len)))\n }\n }\n\n return result;\n }\n\n // enforces 32 byte length\n function toUintStrict(RLPItem memory item) internal pure returns (uint256) {\n // one byte prefix\n require(item.len == 33);\n\n uint256 result;\n uint256 memPtr = item.memPtr + 1;\n assembly {\n result := mload(memPtr)\n }\n\n return result;\n }\n\n function toBytes(RLPItem memory item) internal pure returns (bytes memory) {\n require(item.len > 0);\n\n (uint256 memPtr, uint256 len) = payloadLocation(item);\n bytes memory result = new bytes(len);\n\n uint256 destPtr;\n assembly {\n destPtr := add(0x20, result)\n }\n\n copy(memPtr, destPtr, len);\n return result;\n }\n\n /*\n * Private Helpers\n */\n\n // @return number of payload items inside an encoded list.\n function numItems(RLPItem memory item) private pure returns (uint256) {\n if (item.len == 0) return 0;\n\n uint256 count = 0;\n uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);\n uint256 endPtr = item.memPtr + item.len;\n while (currPtr < endPtr) {\n currPtr = currPtr + _itemLength(currPtr); // skip over an item\n count++;\n }\n\n return count;\n }\n\n // @return entire rlp item byte length\n function _itemLength(uint256 memPtr) private pure returns (uint256) {\n uint256 itemLen;\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n itemLen = 1;\n } else if (byte0 < STRING_LONG_START) {\n itemLen = byte0 - STRING_SHORT_START + 1;\n } else if (byte0 < LIST_SHORT_START) {\n assembly {\n let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is\n memPtr := add(memPtr, 1) // skip over the first byte\n\n /* 32 byte word size */\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len\n itemLen := add(dataLen, add(byteLen, 1))\n }\n } else if (byte0 < LIST_LONG_START) {\n itemLen = byte0 - LIST_SHORT_START + 1;\n } else {\n assembly {\n let byteLen := sub(byte0, 0xf7)\n memPtr := add(memPtr, 1)\n\n let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length\n itemLen := add(dataLen, add(byteLen, 1))\n }\n }\n\n return itemLen;\n }\n\n // @return number of bytes until the data\n function _payloadOffset(uint256 memPtr) private pure returns (uint256) {\n uint256 byte0;\n assembly {\n byte0 := byte(0, mload(memPtr))\n }\n\n if (byte0 < STRING_SHORT_START) {\n return 0;\n } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) {\n return 1;\n } else if (byte0 < LIST_SHORT_START) {\n // being explicit\n return byte0 - (STRING_LONG_START - 1) + 1;\n } else {\n return byte0 - (LIST_LONG_START - 1) + 1;\n }\n }\n\n /*\n * @param src Pointer to source\n * @param dest Pointer to destination\n * @param len Amount of memory to copy from the source\n */\n function copy(uint256 src, uint256 dest, uint256 len) private pure {\n if (len == 0) return;\n\n // copy as many word sizes as possible\n for (; len >= WORD_SIZE; len -= WORD_SIZE) {\n assembly {\n mstore(dest, mload(src))\n }\n\n src += WORD_SIZE;\n dest += WORD_SIZE;\n }\n\n if (len > 0) {\n // left over bytes. Mask is used to remove unwanted bytes from the word\n uint256 mask = 256**(WORD_SIZE - len) - 1;\n assembly {\n let srcpart := and(mload(src), not(mask)) // zero out src\n let destpart := and(mload(dest), mask) // retrieve the bytes\n mstore(dest, or(destpart, srcpart))\n }\n }\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": false, + "runs": 200 + }, + "outputSelection": { + "*": { + "*": [ + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "storageLayout", + "evm.gasEstimates" + ], + "": [ + "ast" + ] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 7b00c5d..5660b91 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -7,6 +7,7 @@ import 'hardhat-tracer' import 'hardhat-deploy' import { getEnvValSafe } from './src/utils' +import './tasks/oracle-updates' import './tasks/build-blocks' import './tasks/mevshare' import './tasks/adblock' @@ -22,7 +23,7 @@ const RIGIL_RPC = getEnvValSafe('RIGIL_RPC') export default { - solidity: '0.8.8', + solidity: '0.8.13', defaultNetwork: 'suave', namedAccounts: { deployer: { @@ -30,21 +31,27 @@ export default { } }, networks: { + goerli: { + chainId: 5, + url: GOERLI_RPC, + accounts: [ GOERLI_PK ], + }, suave: { chainId: 424242, gasPrice: 0, url: SUAVE_RPC, - accounts: [ SUAVE_PK ] + accounts: [ SUAVE_PK ], + companionNetworks: { + goerli: 'goerli', + }, }, - goerli: { - chainId: 5, - url: GOERLI_RPC, - accounts: [ GOERLI_PK ] - }, rigil: { chainId: 16813125, url: RIGIL_RPC, - accounts: [ RIGIL_PK ] + accounts: [ RIGIL_PK ], + companionNetworks: { + goerli: 'goerli', + }, } } } diff --git a/package.json b/package.json index e752784..ce7d26d 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "ethereum-waffle": "^3.3.0", "ethereumjs-util": "^7.0.10", "ethers": "^5.7.2", + "ethers-suave": "^1.0.3", "eventsource": "^2.0.2", "hardhat": "^2.18.2", "hardhat-abi-exporter": "^2.10.1", @@ -26,8 +27,10 @@ "node-fetch": "2", "prettier": "^3.1.0", "prettier-plugin-solidity": "^1.2.0", + "solady": "^0.0.166", "solhint": "^4.0.0", "solhint-plugin-prettier": "^0.1.0", + "solidity-rlp": "^2.0.8", "ts-node": "^10.9.1", "typescript": "^5.2.2" }, diff --git a/scripts/oracle_updates_rigil.sh b/scripts/oracle_updates_rigil.sh new file mode 100755 index 0000000..b4da79e --- /dev/null +++ b/scripts/oracle_updates_rigil.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +while true; do + npx hardhat oracle-updates --ticker $1 --nblocks 1000000 --network rigil + echo "Script ended or errored out, restarting..." + sleep 1 # Prevents spamming restarts in case of consistent immediate failure +done diff --git a/tasks/oracle-updates.ts b/tasks/oracle-updates.ts new file mode 100644 index 0000000..a280ba8 --- /dev/null +++ b/tasks/oracle-updates.ts @@ -0,0 +1,111 @@ +import { HardhatRuntimeEnvironment as HRE } from 'hardhat/types' +import { task, types } from 'hardhat/config' +import { Wallet } from 'ethers' + +import { SuaveProvider, SuaveWallet, SuaveContract } from 'ethers-suave' +import { SUAVE_CHAIN_ID, RIGIL_CHAIN_ID } from './utils/const' +import * as utils from './utils' + + +task('oracle-updates', 'Send Binance oracle updates for the next N blocks') + .addParam('ticker', 'Binance ticker of the asset to update') + .addOptionalParam('nblocks', 'Number of blocks to send bundles for. Default is two.', 1, types.int) + .addOptionalParam('oracle', 'Address of the oracle contract. By default fetch most recently deployed one.') + .addFlag('privateSubmission', 'Whether to submit the oracle updates via bundles. By default use public RPC.') + .setAction(async function (taskArgs: any, hre: HRE) { + utils.checkChain(hre, [SUAVE_CHAIN_ID, RIGIL_CHAIN_ID]) + + const config = await getConfig(hre, taskArgs) + console.log(`Sending oracle updates for the next ${config.nblocks} blocks`) + console.log(`Goerli signer: ${config.goerliSigner.address}`) + console.log(`Suave signer: ${config.suaveSigner.address}`) + console.log(`Ticker: ${config.ticker}`) + + await submitOracleUpdates(config) + // todo: add another thread that listens for oracle updates on the settlement layer + }) + +async function submitOracleUpdates(c: ITaskConfig) { + const controllerAddress = await c.oracleContract.controller() + let lastGoerliBlock = 0 + for (let i=0; i p.toHexString()) + const nonce = await c.goerliSigner.provider.getTransactionCount(controllerAddress) + const submissionRes = await c.oracleContract.queryAndSubmit.sendConfidentialRequest( + c.ticker, + nonce, + gasPrice, + nextGoerliBlock, + c.privateSubmission + ) + const receipt = await submissionRes.wait() + if (receipt.status === 0) { + throw new Error('Oracle update submission failed') + } + } catch (err) { + console.log(err) + } +} + +interface ITaskConfig { + nblocks: number, + executionNodeAdd: string, + goerliSigner: Wallet, + suaveSigner: SuaveWallet, + oracleContract: SuaveContract, + ticker: string, + privateSubmission: boolean +} + +async function getConfig(hre: HRE, taskArgs: any): Promise { + const { nblocks, ticker, oracleContract: oc, privateSubmission } = await parseTaskArgs(hre, taskArgs) + const executionNodeAdd = utils.getEnvValSafe('EXECUTION_NODE') + const goerliSigner = utils.makeGoerliSigner() + + const networkConfig: any = hre.network.config + const suaveProvider = new SuaveProvider(networkConfig.url, executionNodeAdd) + const suaveSigner = new SuaveWallet(networkConfig.accounts[0], suaveProvider) + + const oracleContract = new SuaveContract( + oc.address, + oc.interface, + suaveSigner + ) + return { + nblocks, + ticker, + executionNodeAdd, + goerliSigner, + suaveSigner, + oracleContract, + privateSubmission + } +} + +async function parseTaskArgs(hre: HRE, taskArgs: any) { + const privateSubmission = taskArgs.privateSubmission + const nblocks = parseInt(taskArgs.nblocks) + const ticker = taskArgs.ticker + if (!ticker) throw new Error('Ticker is required') + + const oracleContract = await (taskArgs.oracle + ? hre.ethers.getContractAt('BinanceOracle', taskArgs.oracle) + : utils.fetchDeployedContract(hre, 'BinanceOracle') + ) + + return { nblocks, ticker, oracleContract, privateSubmission } +} \ No newline at end of file diff --git a/test/oracle.ts b/test/oracle.ts new file mode 100644 index 0000000..d113349 --- /dev/null +++ b/test/oracle.ts @@ -0,0 +1,153 @@ +import { SuaveProvider, SuaveWallet, SuaveContract } from 'ethers-suave' +import { ethers } from 'hardhat' +import { expect } from 'chai' +import * as utils from '../tasks/utils' + + +describe('oracle', async () => { + const executionNodeUrl = utils.getEnvValSafe('SUAVE_RPC') + const goerliUrl = utils.getEnvValSafe('GOERLI_RPC') + const executionNodeAddress = utils.getEnvValSafe('EXECUTION_NODE') + const suaveChainPK = utils.getEnvValSafe('SUAVE_PK') + const goerliPK = utils.getEnvValSafe('GOERLI_PK') + let OracleContract + + before(async () => { + const provider = new ethers.providers.JsonRpcProvider(executionNodeUrl) + const signer = new ethers.Wallet(suaveChainPK, provider) + + let oracleContract + await ethers.getContractFactory('BinanceOracle') + .then(async (factory) => { + oracleContract = await factory.connect(signer).deploy() + await oracleContract.deployTransaction.wait() + }) + .catch((err) => { + console.log(err) + }) + + const suaveProvider = new SuaveProvider(executionNodeUrl, executionNodeAddress) + const suaveSigner = new SuaveWallet(suaveChainPK, suaveProvider) + OracleContract = new SuaveContract( + oracleContract.address, + oracleContract.interface, + suaveSigner + ) + }) + + it('recover address', async () => { + const pk = '1111111111111111111111111111111111111111111111111111111111111111' + const targetAddress = '0x19E7E376E7C213B7E7e7e46cc70A5dD086DAff2A'.toLowerCase() + + const res = await OracleContract.getAddressForPk.sendConfidentialRequest(pk) + const recAddress = '0x' + res.confidentialComputeResult.slice(26) + expect(recAddress).to.equal(targetAddress) + }) + + it('queryLatestPrice', async () => { + const ticker = 'BTCUSDT' + const res = await OracleContract.queryLatestPrice.sendConfidentialRequest(ticker) + const resPrice = parseInt(res.confidentialComputeResult, 16) + expect(resPrice).to.be.greaterThan(0) + expect(resPrice).to.be.lessThan(70_000*10**4) // ikr so pessimistic + }) + + it('sendRawTransaction', async () => { + const goerliProvider = new ethers.providers.JsonRpcProvider(goerliUrl) + const goerliSigner = new ethers.Wallet(goerliPK, goerliProvider) + const signedTx = await goerliSigner.signTransaction({ + to: goerliSigner.address, + data: ethers.utils.toUtf8Bytes('hello'), + gasLimit: 60000, + gasPrice: ethers.utils.parseUnits('80', 'gwei'), + nonce: await goerliSigner.getTransactionCount() + }) + const res = await OracleContract.sendRawTx.sendConfidentialRequest(signedTx) + console.log(res.confidentialComputeResult) + }) + + it('queryAndSubmit', async () => { + const ticker = 'ETHUSDT' + const privateSubmission = true + const goerliProvider = new ethers.providers.JsonRpcProvider(goerliUrl) + const goerliSigner = new ethers.Wallet(goerliPK, goerliProvider) + + // Deploy oracle settlement contract + const settlementContract = await ethers.getContractFactory('OracleSettlementContract') + .then(async (factory) => { + const contract = await factory.connect(goerliSigner).deploy() + const r = await contract.deployTransaction.wait() + expect(r.status).to.equal(1) + return contract + }) + .catch((err) => { + throw new Error(err) + }) + + console.log('Settlement contract: ', settlementContract.address) + + // Init the contract + const initRes = await OracleContract.confidentialConstructor + .sendConfidentialRequest({}) + const receipt = await initRes.wait() + if (receipt.status == 0) + throw new Error('ConfidentialInit callback failed') + const controllerAddress = await OracleContract.controller() + + // Send gas to the controller + const payReceipt = await goerliSigner.sendTransaction({ + to: controllerAddress, + value: ethers.utils.parseEther('0.02') + }).then(tx => tx.wait()) + expect(payReceipt.status).to.equal(1) + + // Register + const registerRes = await OracleContract.registerSettlementContract + .sendConfidentialRequest(settlementContract.address) + const registerReceipt = await registerRes.wait() + if (registerReceipt.status == 0) + throw new Error('ConfidentialInit callback failed') + // eslint-disable-next-line no-constant-condition + while (true) { + const nonce = await goerliProvider.getTransactionCount(controllerAddress) + if (nonce == 1) { + break + } + await sleep(2000) + } + + // Submit oracle updates for the next N blocks + const controllerNonce = 1 + const gasPrice = '0x174876e800' + for (let i=0; i<100; i++) { + const nextGoerliBlock = (await goerliProvider.getBlockNumber()) + 1 + console.log(`${i} | Submitting for Goerli block: ${nextGoerliBlock}`) + const newControllerNonce = await goerliProvider.getTransactionCount(controllerAddress) + // Exit if the settlement tx landed (signer's nonce changed) + if (newControllerNonce == 2) { + return + } + + try { + const submissionRes = await OracleContract.queryAndSubmit.sendConfidentialRequest( + ticker, + controllerNonce, + gasPrice, + nextGoerliBlock, + privateSubmission + ) + const receipt = await submissionRes.wait() + expect(receipt.status).to.equal(1) + } catch (err) { + console.log(err) + } + await sleep(10_000) + } + throw new Error('efforts were to no avail') + }).timeout(1e6) + +}) + +async function sleep(ms) { + new Promise(resolve => setTimeout(resolve, ms)) +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 88347cf..5c71f08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@adraffy/ens-normalize@1.10.0": + version "1.10.0" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" + integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== + "@babel/code-frame@^7.0.0": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" @@ -623,6 +628,13 @@ dependencies: "@noble/hashes" "1.3.1" +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== + dependencies: + "@noble/hashes" "1.3.2" + "@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" @@ -633,7 +645,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== -"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": +"@noble/hashes@1.3.2", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": version "1.3.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== @@ -1209,6 +1221,11 @@ dependencies: undici-types "~5.25.1" +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^12.12.6": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -1459,6 +1476,11 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + aes-js@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" @@ -4134,6 +4156,14 @@ ethereumjs-wallet@0.6.5: utf8 "^3.0.0" uuid "^3.3.2" +ethers-suave@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ethers-suave/-/ethers-suave-1.0.3.tgz#77b71b7446a5b142ec92a40d0aaee76889d6de80" + integrity sha512-nFrZs5s/FMmGE3EtXTvJUQJOMJO2AZIvVI37mv1+bEXE6/55JUxjyD7vcQACBxYq9LzSMjs1JAKeHaeEQOykYA== + dependencies: + ethers "^6.9.0" + typescript "^5.3.2" + ethers@^5.0.1, ethers@^5.0.2, ethers@^5.5.2, ethers@^5.6.1, ethers@^5.7.0, ethers@^5.7.1, ethers@^5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" @@ -4170,6 +4200,19 @@ ethers@^5.0.1, ethers@^5.0.2, ethers@^5.5.2, ethers@^5.6.1, ethers@^5.7.0, ether "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.9.0: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.10.0.tgz#20f3c63c60d59a993f8090ad423d8a3854b3b1cd" + integrity sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -8030,6 +8073,11 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +solady@^0.0.166: + version "0.0.166" + resolved "https://registry.yarnpkg.com/solady/-/solady-0.0.166.tgz#a02b1d6457c717ae806560e07970f94a0add9d8a" + integrity sha512-M6/n9VlfGPzxHNvFFI4ZDsLrJR95VPEkm7+27BPBTVvqO4p2aNIaMR+GbR1h/sh36YcUChHJlO0ubxKGVvWdig== + solc@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" @@ -8134,6 +8182,11 @@ solidity-comments-extractor@^0.0.7: resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19" integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw== +solidity-rlp@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/solidity-rlp/-/solidity-rlp-2.0.8.tgz#1548370b690ef06dbb62af06b7675bc86b19bbe3" + integrity sha512-gzYzHoFKRH1ydJeCfzm3z/BvKrZGK/V9+qbOlNbBcRAYeizjCdDNhLTTE8iIJrHqsRrZRSOo+7mhbnxoBoZvJQ== + source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" @@ -8366,6 +8419,10 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== +"suave-std@https://github.com/flashbots/suave-std": + version "0.0.0" + resolved "https://github.com/flashbots/suave-std#264f908f04f1d55a376b6cfd5a14bd3265fe8a43" + supports-color@8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" @@ -8619,6 +8676,11 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -8765,6 +8827,11 @@ typescript@^5.2.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@^5.3.2: + version "5.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== + typewise-core@^1.2, typewise-core@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" @@ -9375,6 +9442,11 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"