witnet-solidity-bridge
Version:
Witnet Solidity Bridge contracts for EVM-compatible chains
522 lines (521 loc) • 1.37 MB
JSON
{
"contractName": "WitnetBuffer",
"abi": [
{
"inputs": [],
"name": "EmptyBuffer",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "index",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "range",
"type": "uint256"
}
],
"name": "IndexOutOfBounds",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "expected",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "given",
"type": "uint256"
}
],
"name": "MissingArgs",
"type": "error"
}
],
"metadata": "{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"EmptyBuffer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"range\",\"type\":\"uint256\"}],\"name\":\"IndexOutOfBounds\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"expected\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"given\",\"type\":\"uint256\"}],\"name\":\"MissingArgs\",\"type\":\"error\"}],\"devdoc\":{\"author\":\"The Witnet Foundation.\",\"details\":\"`uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.\",\"kind\":\"dev\",\"methods\":{},\"title\":\"A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will start with the byte that goes right after the last one in the previous read.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"project:/contracts/libs/WitnetBuffer.sol\":\"WitnetBuffer\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"project:/contracts/libs/WitnetBuffer.sol\":{\"keccak256\":\"0x8e07aebe2954ab3e6f2d8eceedb12db7cf915c1f3e8630f4fa9999cecb1c78ec\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ed6c54cc901183d61546e8fd15bd5ea8ef238ebc915642946071d435dd7481ea\",\"dweb:/ipfs/Qmcaqta7YjUSBbBUGqoh44bsCS6UqqoyHjBuz4qnKBShXM\"]}},\"version\":1}",
"bytecode": "0x60556032600b8282823980515f1a607314602657634e487b7160e01b5f525f60045260245ffd5b305f52607381538281f3fe730000000000000000000000000000000000000000301460806040525f5ffdfea2646970667358221220b46e49710b1095d8ee91d84474fca0526ddd1f2374d3974202e6655ed5dc878564736f6c634300081e0033",
"deployedBytecode": "0x730000000000000000000000000000000000000000301460806040525f5ffdfea2646970667358221220b46e49710b1095d8ee91d84474fca0526ddd1f2374d3974202e6655ed5dc878564736f6c634300081e0033",
"immutableReferences": {},
"generatedSources": [],
"deployedGeneratedSources": [],
"sourceMap": "644:26479:117:-:0;;;;;;;;;;;;;;;-1:-1:-1;;;644:26479:117;;;;;;;;;;;;;;;;;",
"deployedSourceMap": "644:26479:117:-:0;;;;;;;;",
"source": "// SPDX-License-Identifier: MIT\r\n\r\npragma solidity >=0.8.0 <0.9.0;\r\n\r\n/// @title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface\r\n/// @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will\r\n/// start with the byte that goes right after the last one in the previous read.\r\n/// @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some\r\n/// theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.\r\n/// @author The Witnet Foundation.\r\nlibrary WitnetBuffer {\r\n\r\n error EmptyBuffer();\r\n error IndexOutOfBounds(uint index, uint range);\r\n error MissingArgs(uint expected, uint given);\r\n\r\n /// Iterable bytes buffer.\r\n struct Buffer {\r\n bytes data;\r\n uint cursor;\r\n }\r\n\r\n // Ensures we access an existing index in an array\r\n modifier withinRange(uint index, uint _range) {\r\n if (index > _range) {\r\n revert IndexOutOfBounds(index, _range);\r\n }\r\n _;\r\n }\r\n\r\n /// @notice Concatenate undefinite number of bytes chunks.\r\n /// @dev Faster than looping on `abi.encodePacked(output, _buffs[ix])`.\r\n function concat(bytes[] memory _buffs)\r\n internal pure\r\n returns (bytes memory output)\r\n {\r\n unchecked {\r\n uint destinationPointer;\r\n uint destinationLength;\r\n assembly {\r\n // get safe scratch location\r\n output := mload(0x40)\r\n // set starting destination pointer\r\n destinationPointer := add(output, 32)\r\n } \r\n for (uint ix = 1; ix <= _buffs.length; ix ++) { \r\n uint source;\r\n uint sourceLength;\r\n uint sourcePointer; \r\n assembly {\r\n // load source length pointer\r\n source := mload(add(_buffs, mul(ix, 32)))\r\n // load source length\r\n sourceLength := mload(source)\r\n // sets source memory pointer\r\n sourcePointer := add(source, 32)\r\n }\r\n memcpy(\r\n destinationPointer,\r\n sourcePointer,\r\n sourceLength\r\n );\r\n assembly { \r\n // increase total destination length\r\n destinationLength := add(destinationLength, sourceLength)\r\n // sets destination memory pointer\r\n destinationPointer := add(destinationPointer, sourceLength)\r\n }\r\n }\r\n assembly {\r\n // protect output bytes\r\n mstore(output, destinationLength)\r\n // set final output length\r\n mstore(0x40, add(mload(0x40), add(destinationLength, 32)))\r\n }\r\n }\r\n }\r\n\r\n function fork(WitnetBuffer.Buffer memory buffer)\r\n internal pure\r\n returns (WitnetBuffer.Buffer memory)\r\n {\r\n return Buffer(\r\n buffer.data,\r\n buffer.cursor\r\n );\r\n }\r\n\r\n function mutate(\r\n WitnetBuffer.Buffer memory buffer,\r\n uint length,\r\n bytes memory pokes\r\n )\r\n internal pure\r\n withinRange(length, buffer.data.length - buffer.cursor + 1)\r\n {\r\n bytes[] memory parts = new bytes[](3);\r\n parts[0] = peek(\r\n buffer,\r\n 0,\r\n buffer.cursor\r\n );\r\n parts[1] = pokes;\r\n parts[2] = peek(\r\n buffer,\r\n buffer.cursor + length,\r\n buffer.data.length - buffer.cursor - length\r\n );\r\n buffer.data = concat(parts);\r\n }\r\n\r\n /// @notice Read and consume the next byte from the buffer.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return The next byte in the buffer counting from the cursor position.\r\n function next(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor, buffer.data.length)\r\n returns (bytes1)\r\n {\r\n // Return the byte at the position marked by the cursor and advance the cursor all at once\r\n return buffer.data[buffer.cursor ++];\r\n }\r\n\r\n function peek(\r\n WitnetBuffer.Buffer memory buffer,\r\n uint offset,\r\n uint length\r\n )\r\n internal pure\r\n withinRange(offset + length, buffer.data.length)\r\n returns (bytes memory)\r\n {\r\n bytes memory data = buffer.data;\r\n bytes memory peeks = new bytes(length);\r\n uint destinationPointer;\r\n uint sourcePointer;\r\n assembly {\r\n destinationPointer := add(peeks, 32)\r\n sourcePointer := add(add(data, 32), offset)\r\n }\r\n memcpy(\r\n destinationPointer,\r\n sourcePointer,\r\n length\r\n );\r\n return peeks;\r\n }\r\n\r\n // @notice Extract bytes array from buffer starting from current cursor.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @param length How many bytes to peek from the Buffer.\r\n // solium-disable-next-line security/no-assign-params\r\n function peek(\r\n WitnetBuffer.Buffer memory buffer,\r\n uint length\r\n )\r\n internal pure\r\n withinRange(length, buffer.data.length - buffer.cursor)\r\n returns (bytes memory)\r\n {\r\n return peek(\r\n buffer,\r\n buffer.cursor,\r\n length\r\n );\r\n }\r\n\r\n /// @notice Read and consume a certain amount of bytes from the buffer.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @param length How many bytes to read and consume from the buffer.\r\n /// @return output A `bytes memory` containing the first `length` bytes from the buffer, counting from the cursor position.\r\n function read(Buffer memory buffer, uint length)\r\n internal pure\r\n withinRange(buffer.cursor + length, buffer.data.length)\r\n returns (bytes memory output)\r\n {\r\n // Create a new `bytes memory destination` value\r\n output = new bytes(length);\r\n // Early return in case that bytes length is 0\r\n if (length > 0) {\r\n bytes memory input = buffer.data;\r\n uint offset = buffer.cursor;\r\n // Get raw pointers for source and destination\r\n uint sourcePointer;\r\n uint destinationPointer;\r\n assembly {\r\n sourcePointer := add(add(input, 32), offset)\r\n destinationPointer := add(output, 32)\r\n }\r\n // Copy `length` bytes from source to destination\r\n memcpy(\r\n destinationPointer,\r\n sourcePointer,\r\n length\r\n );\r\n // Move the cursor forward by `length` bytes\r\n seek(\r\n buffer,\r\n length,\r\n true\r\n );\r\n }\r\n }\r\n \r\n /// @notice Read and consume the next 2 bytes from the buffer as an IEEE 754-2008 floating point number enclosed in an\r\n /// `int32`.\r\n /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r\n /// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `float16`\r\n /// use cases. In other words, the integer output of this method is 10,000 times the actual value. The input bytes are\r\n /// expected to follow the 16-bit base-2 format (a.k.a. `binary16`) in the IEEE 754-2008 standard.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return result The `int32` value of the next 4 bytes in the buffer counting from the cursor position.\r\n function readFloat16(Buffer memory buffer)\r\n internal pure\r\n returns (int32 result)\r\n {\r\n uint32 value = readUint16(buffer);\r\n // Get bit at position 0\r\n uint32 sign = value & 0x8000;\r\n // Get bits 1 to 5, then normalize to the [-15, 16] range so as to counterweight the IEEE 754 exponent bias\r\n int32 exponent = (int32(value & 0x7c00) >> 10) - 15;\r\n // Get bits 6 to 15\r\n int32 fraction = int32(value & 0x03ff);\r\n // Add 2^10 to the fraction if exponent is not -15\r\n if (exponent != -15) {\r\n fraction |= 0x400;\r\n } else if (exponent == 16) {\r\n revert(\r\n string(abi.encodePacked(\r\n \"WitnetBuffer.readFloat16: \",\r\n sign != 0 ? \"negative\" : hex\"\",\r\n \" infinity\"\r\n ))\r\n );\r\n }\r\n // Compute `2 ^ exponent · (1 + fraction / 1024)`\r\n if (exponent >= 0) {\r\n result = int32(int(\r\n int(1 << uint256(int256(exponent)))\r\n * 10000\r\n * fraction\r\n ) >> 10);\r\n } else {\r\n result = int32(int(\r\n int(fraction)\r\n * 10000\r\n / int(1 << uint(int(- exponent)))\r\n ) >> 10);\r\n }\r\n // Make the result negative if the sign bit is not 0\r\n if (sign != 0) {\r\n result *= -1;\r\n }\r\n }\r\n\r\n /// @notice Consume the next 4 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.\r\n /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r\n /// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `float32`\r\n /// use cases. In other words, the integer output of this method is 10^9 times the actual value. The input bytes are\r\n /// expected to follow the 64-bit base-2 format (a.k.a. `binary32`) in the IEEE 754-2008 standard.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.\r\n function readFloat32(Buffer memory buffer)\r\n internal pure\r\n returns (int result)\r\n {\r\n uint value = readUint32(buffer);\r\n // Get bit at position 0\r\n uint sign = value & 0x80000000;\r\n // Get bits 1 to 8, then normalize to the [-127, 128] range so as to counterweight the IEEE 754 exponent bias\r\n int exponent = (int(value & 0x7f800000) >> 23) - 127;\r\n // Get bits 9 to 31\r\n int fraction = int(value & 0x007fffff);\r\n // Add 2^23 to the fraction if exponent is not -127\r\n if (exponent != -127) {\r\n fraction |= 0x800000;\r\n } else if (exponent == 128) {\r\n revert(\r\n string(abi.encodePacked(\r\n \"WitnetBuffer.readFloat32: \",\r\n sign != 0 ? \"negative\" : hex\"\",\r\n \" infinity\"\r\n ))\r\n );\r\n }\r\n // Compute `2 ^ exponent · (1 + fraction / 2^23)`\r\n if (exponent >= 0) {\r\n result = (\r\n int(1 << uint(exponent))\r\n * (10 ** 9)\r\n * fraction\r\n ) >> 23;\r\n } else {\r\n result = (\r\n fraction \r\n * (10 ** 9)\r\n / int(1 << uint(-exponent)) \r\n ) >> 23;\r\n }\r\n // Make the result negative if the sign bit is not 0\r\n if (sign != 0) {\r\n result *= -1;\r\n }\r\n }\r\n\r\n /// @notice Consume the next 8 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.\r\n /// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values\r\n /// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `float64`\r\n /// use cases. In other words, the integer output of this method is 10^15 times the actual value. The input bytes are\r\n /// expected to follow the 64-bit base-2 format (a.k.a. `binary64`) in the IEEE 754-2008 standard.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.\r\n function readFloat64(Buffer memory buffer)\r\n internal pure\r\n returns (int result)\r\n {\r\n uint value = readUint64(buffer);\r\n // Get bit at position 0\r\n uint sign = value & 0x8000000000000000;\r\n // Get bits 1 to 12, then normalize to the [-1023, 1024] range so as to counterweight the IEEE 754 exponent bias\r\n int exponent = (int(value & 0x7ff0000000000000) >> 52) - 1023;\r\n // Get bits 6 to 15\r\n int fraction = int(value & 0x000fffffffffffff);\r\n // Add 2^52 to the fraction if exponent is not -1023\r\n if (exponent != -1023) {\r\n fraction |= 0x10000000000000;\r\n } else if (exponent == 1024) {\r\n revert(\r\n string(abi.encodePacked(\r\n \"WitnetBuffer.readFloat64: \",\r\n sign != 0 ? \"negative\" : hex\"\",\r\n \" infinity\"\r\n ))\r\n );\r\n }\r\n // Compute `2 ^ exponent · (1 + fraction / 1024)`\r\n if (exponent >= 0) {\r\n result = (\r\n int(1 << uint(exponent))\r\n * (10 ** 15)\r\n * fraction\r\n ) >> 52;\r\n } else {\r\n result = (\r\n fraction \r\n * (10 ** 15)\r\n / int(1 << uint(-exponent)) \r\n ) >> 52;\r\n }\r\n // Make the result negative if the sign bit is not 0\r\n if (sign != 0) {\r\n result *= -1;\r\n }\r\n }\r\n\r\n // Read a text string of a given length from a buffer. Returns a `bytes memory` value for the sake of genericness,\r\n /// but it can be easily casted into a string with `string(result)`.\r\n // solium-disable-next-line security/no-assign-params\r\n function readText(\r\n WitnetBuffer.Buffer memory buffer,\r\n uint64 length\r\n )\r\n internal pure\r\n returns (bytes memory text)\r\n {\r\n text = new bytes(length);\r\n unchecked {\r\n for (uint64 index = 0; index < length; index ++) {\r\n uint8 char = readUint8(buffer);\r\n if (char & 0x80 != 0) {\r\n if (char < 0xe0) {\r\n char = (char & 0x1f) << 6\r\n | (readUint8(buffer) & 0x3f);\r\n length -= 1;\r\n } else if (char < 0xf0) {\r\n char = (char & 0x0f) << 12\r\n | (readUint8(buffer) & 0x3f) << 6\r\n | (readUint8(buffer) & 0x3f);\r\n length -= 2;\r\n } else {\r\n char = (char & 0x0f) << 18\r\n | (readUint8(buffer) & 0x3f) << 12\r\n | (readUint8(buffer) & 0x3f) << 6 \r\n | (readUint8(buffer) & 0x3f);\r\n length -= 3;\r\n }\r\n }\r\n text[index] = bytes1(char);\r\n }\r\n // Adjust text to actual length:\r\n assembly {\r\n mstore(text, length)\r\n }\r\n }\r\n }\r\n\r\n /// @notice Read and consume the next byte from the buffer as an `uint8`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint8` value of the next byte in the buffer counting from the cursor position.\r\n function readUint8(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor, buffer.data.length)\r\n returns (uint8 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 1), offset))\r\n }\r\n buffer.cursor ++;\r\n }\r\n\r\n /// @notice Read and consume the next 2 bytes from the buffer as an `uint16`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint16` value of the next 2 bytes in the buffer counting from the cursor position.\r\n function readUint16(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor + 2, buffer.data.length)\r\n returns (uint16 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 2), offset))\r\n }\r\n buffer.cursor += 2;\r\n }\r\n\r\n /// @notice Read and consume the next 4 bytes from the buffer as an `uint32`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint32` value of the next 4 bytes in the buffer counting from the cursor position.\r\n function readUint32(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor + 4, buffer.data.length)\r\n returns (uint32 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 4), offset))\r\n }\r\n buffer.cursor += 4;\r\n }\r\n\r\n /// @notice Read and consume the next 8 bytes from the buffer as an `uint64`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint64` value of the next 8 bytes in the buffer counting from the cursor position.\r\n function readUint64(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor + 8, buffer.data.length)\r\n returns (uint64 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 8), offset))\r\n }\r\n buffer.cursor += 8;\r\n }\r\n\r\n /// @notice Read and consume the next 16 bytes from the buffer as an `uint128`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint128` value of the next 16 bytes in the buffer counting from the cursor position.\r\n function readUint128(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor + 16, buffer.data.length)\r\n returns (uint128 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 16), offset))\r\n }\r\n buffer.cursor += 16;\r\n }\r\n\r\n /// @notice Read and consume the next 32 bytes from the buffer as an `uint256`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @return value The `uint256` value of the next 32 bytes in the buffer counting from the cursor position.\r\n function readUint256(Buffer memory buffer)\r\n internal pure\r\n withinRange(buffer.cursor + 32, buffer.data.length)\r\n returns (uint256 value)\r\n {\r\n bytes memory data = buffer.data;\r\n uint offset = buffer.cursor;\r\n assembly {\r\n value := mload(add(add(data, 32), offset))\r\n }\r\n buffer.cursor += 32;\r\n }\r\n\r\n /// @notice Count number of required parameters for given bytes arrays\r\n /// @dev Wildcard format: \"\\#\\\", with # in [\"0\"..\"9\"].\r\n /// @param input Bytes array containing strings.\r\n /// @param count Highest wildcard index found, plus 1.\r\n function argsCountOf(bytes memory input)\r\n internal pure\r\n returns (uint8 count)\r\n {\r\n if (input.length < 3) {\r\n return 0;\r\n }\r\n unchecked {\r\n uint ix = 0; \r\n uint length = input.length - 2;\r\n for (; ix < length; ) {\r\n if (\r\n input[ix] == bytes1(\"\\\\\")\r\n && input[ix + 2] == bytes1(\"\\\\\")\r\n && input[ix + 1] >= bytes1(\"0\")\r\n && input[ix + 1] <= bytes1(\"9\")\r\n ) {\r\n uint8 ax = uint8(uint8(input[ix + 1]) - uint8(bytes1(\"0\")) + 1);\r\n if (ax > count) {\r\n count = ax;\r\n }\r\n ix += 3;\r\n } else {\r\n ix ++;\r\n }\r\n }\r\n }\r\n }\r\n\r\n /// @notice Replace indexed bytes-wildcards by correspondent substrings.\r\n /// @dev Wildcard format: \"\\#\\\", with # in [\"0\"..\"9\"].\r\n /// @param input Bytes array containing strings.\r\n /// @param args Array of substring values for replacing indexed wildcards.\r\n /// @return output Resulting bytes array after replacing all wildcards.\r\n /// @return hits Total number of replaced wildcards.\r\n function replace(bytes memory input, string[] memory args)\r\n internal pure\r\n returns (bytes memory output, uint hits)\r\n {\r\n uint ix = 0; uint lix = 0;\r\n uint inputLength;\r\n uint inputPointer;\r\n uint outputLength;\r\n uint outputPointer; \r\n uint source;\r\n uint sourceLength;\r\n uint sourcePointer;\r\n\r\n if (input.length < 3) {\r\n return (input, 0);\r\n }\r\n \r\n assembly {\r\n // set starting input pointer\r\n inputPointer := add(input, 32)\r\n // get safe output location\r\n output := mload(0x40)\r\n // set starting output pointer\r\n outputPointer := add(output, 32)\r\n } \r\n\r\n unchecked {\r\n uint length = input.length - 2;\r\n for (; ix < length; ) {\r\n if (\r\n input[ix] == bytes1(\"\\\\\")\r\n && input[ix + 2] == bytes1(\"\\\\\")\r\n && input[ix + 1] >= bytes1(\"0\")\r\n && input[ix + 1] <= bytes1(\"9\")\r\n ) {\r\n inputLength = (ix - lix);\r\n if (ix > lix) {\r\n memcpy(\r\n outputPointer,\r\n inputPointer,\r\n inputLength\r\n );\r\n inputPointer += inputLength + 3;\r\n outputPointer += inputLength;\r\n } else {\r\n inputPointer += 3;\r\n }\r\n uint ax = uint(uint8(input[ix + 1]) - uint8(bytes1(\"0\")));\r\n if (ax >= args.length) {\r\n revert MissingArgs(ax + 1, args.length);\r\n }\r\n assembly {\r\n source := mload(add(args, mul(32, add(ax, 1))))\r\n sourceLength := mload(source)\r\n sourcePointer := add(source, 32) \r\n } \r\n memcpy(\r\n outputPointer,\r\n sourcePointer,\r\n sourceLength\r\n );\r\n outputLength += inputLength + sourceLength;\r\n outputPointer += sourceLength;\r\n ix += 3;\r\n lix = ix;\r\n hits ++;\r\n } else {\r\n ix ++;\r\n }\r\n }\r\n ix = input.length; \r\n }\r\n if (outputLength > 0) {\r\n if (ix > lix ) {\r\n memcpy(\r\n outputPointer,\r\n inputPointer,\r\n ix - lix\r\n );\r\n outputLength += (ix - lix);\r\n }\r\n assembly {\r\n // set final output length\r\n mstore(output, outputLength)\r\n // protect output bytes\r\n mstore(0x40, add(mload(0x40), add(outputLength, 32)))\r\n }\r\n }\r\n else {\r\n return (input, 0);\r\n }\r\n }\r\n\r\n /// @notice Replace indexed bytes-wildcard by given substring.\r\n /// @dev Wildcard format: \"\\#\\\", with # in [\"0\"..\"9\"].\r\n /// @param input Bytes array containing strings.\r\n /// @param argIndex Index of the wildcard to be replaced.\r\n /// @param argValue Replacing substring to be used.\r\n /// @return output Resulting bytes array after replacing all wildcards.\r\n /// @return hits Total number of replaced wildcards.\r\n function replace(bytes memory input, uint8 argIndex, string memory argValue)\r\n internal pure\r\n returns (bytes memory output, uint hits)\r\n {\r\n uint ix = 0; uint lix = 0;\r\n uint inputLength;\r\n uint inputPointer;\r\n uint outputLength;\r\n uint outputPointer; \r\n uint argValueLength;\r\n uint argValuePointer;\r\n\r\n if (input.length < 3) {\r\n return (input, 0);\r\n }\r\n \r\n assembly {\r\n // set starting input pointer\r\n inputPointer := add(input, 32)\r\n // get safe output location\r\n output := mload(0x40)\r\n // set starting output pointer\r\n outputPointer := add(output, 32)\r\n // set pointer to arg value substring\r\n argValuePointer := add(argValue, 32)\r\n // set arg value substring length\r\n argValueLength := mload(argValue)\r\n } \r\n\r\n unchecked {\r\n uint length = input.length - 2;\r\n for (; ix < length; ) {\r\n if (\r\n input[ix] == bytes1(\"\\\\\")\r\n && input[ix + 2] == bytes1(\"\\\\\")\r\n && input[ix + 1] >= bytes1(\"0\")\r\n && input[ix + 1] <= bytes1(\"9\")\r\n && uint8(input[ix + 1]) - uint8(bytes1(\"0\")) == argIndex\r\n ) {\r\n inputLength = (ix - lix);\r\n if (ix > lix) {\r\n memcpy(\r\n outputPointer,\r\n inputPointer,\r\n inputLength\r\n );\r\n inputPointer += inputLength + 3;\r\n outputPointer += inputLength;\r\n } else {\r\n inputPointer += 3;\r\n }\r\n memcpy(\r\n outputPointer,\r\n argValuePointer,\r\n argValueLength\r\n );\r\n outputLength += inputLength + argValueLength;\r\n outputPointer += argValueLength;\r\n ix += 3;\r\n lix = ix;\r\n hits ++;\r\n } else {\r\n ix ++;\r\n }\r\n }\r\n ix = input.length; \r\n }\r\n if (outputLength > 0) {\r\n if (ix > lix ) {\r\n memcpy(\r\n outputPointer,\r\n inputPointer,\r\n ix - lix\r\n );\r\n outputLength += (ix - lix);\r\n }\r\n assembly {\r\n // set final output length\r\n mstore(output, outputLength)\r\n // protect output bytes\r\n mstore(0x40, add(mload(0x40), add(outputLength, 32)))\r\n }\r\n }\r\n else {\r\n return (input, 0);\r\n }\r\n }\r\n\r\n /// @notice Replace indexed string wildcards by correspondent substrings.\r\n /// @dev Wildcard format: \"\\#\\\", with # in [\"0\"..\"9\"].\r\n /// @param input String potentially containing wildcards.\r\n /// @param args Array of substring values for replacing indexed wildcards.\r\n /// @return output Resulting string after replacing all wildcards.\r\n function replace(string memory input, string[] memory args)\r\n internal pure\r\n returns (string memory)\r\n {\r\n (bytes memory _outputBytes, ) = replace(bytes(input), args);\r\n return string(_outputBytes);\r\n }\r\n\r\n /// @notice Replace last indexed wildcard by given substring.\r\n /// @dev Wildcard format: \"\\#\\\", with # in [\"0\"..\"9\"].\r\n /// @param input String potentially containing wildcards.\r\n /// @param argIndex Index of the wildcard to be replaced.\r\n /// @param argValue Replacing string to be used.\r\n /// @return output Resulting string after replacing all wildcards.\r\n function replace(string memory input, uint8 argIndex, string memory argValue)\r\n internal pure\r\n returns (string memory)\r\n {\r\n (bytes memory _outputBytes, ) = replace(bytes(input), argIndex, argValue);\r\n return string(_outputBytes);\r\n }\r\n\r\n /// @notice Move the inner cursor of the buffer to a relative or absolute position.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @param offset How many bytes to move the cursor forward.\r\n /// @param relative Whether to count `offset` from the last position of the cursor (`true`) or the beginning of the\r\n /// buffer (`true`).\r\n /// @return The final position of the cursor (will equal `offset` if `relative` is `false`).\r\n // solium-disable-next-line security/no-assign-params\r\n function seek(\r\n Buffer memory buffer,\r\n uint offset,\r\n bool relative\r\n )\r\n internal pure\r\n withinRange(offset, buffer.data.length)\r\n returns (uint)\r\n {\r\n // Deal with relative offsets\r\n if (relative) {\r\n offset += buffer.cursor;\r\n }\r\n buffer.cursor = offset;\r\n return offset;\r\n }\r\n\r\n /// @notice Move the inner cursor a number of bytes forward.\r\n /// @dev This is a simple wrapper around the relative offset case of `seek()`.\r\n /// @param buffer An instance of `Buffer`.\r\n /// @param relativeOffset How many bytes to move the cursor forward.\r\n /// @return The final position of the cursor.\r\n function seek(\r\n Buffer memory buffer,\r\n uint relativeOffset\r\n )\r\n internal pure\r\n returns (uint)\r\n {\r\n return seek(\r\n buffer,\r\n relativeOffset,\r\n true\r\n );\r\n }\r\n\r\n /// @notice Copy bytes from one memory address into another.\r\n /// @dev This function was borrowed from Nick Johnson's `solidity-stringutils` lib, and reproduced here under the terms\r\n /// of [Apache License 2.0](https://github.com/Arachnid/solidity-stringutils/blob/master/LICENSE).\r\n /// @param dest Address of the destination memory.\r\n /// @param src Address to the source memory.\r\n /// @param len How many bytes to copy.\r\n // solium-disable-next-line security/no-assign-params\r\n function memcpy(\r\n uint dest,\r\n uint src,\r\n uint len\r\n )\r\n private pure\r\n {\r\n unchecked {\r\n // Copy word-length chunks while possible\r\n for (; len >= 32; len -= 32) {\r\n assembly {\r\n mstore(dest, mload(src))\r\n }\r\n dest += 32;\r\n src += 32;\r\n }\r\n if (len > 0) {\r\n // Copy remaining bytes\r\n uint _mask = 256 ** (32 - len) - 1;\r\n assembly {\r\n let srcpart := and(mload(src), not(_mask))\r\n let destpart := and(mload(dest), _mask)\r\n mstore(dest, or(destpart, srcpart))\r\n }\r\n }\r\n }\r\n }\r\n\r\n}",
"sourcePath": "C:\\Users\\guill\\github\\guidiaz\\witnet-solidity-bridge\\contracts\\libs\\WitnetBuffer.sol",
"ast": {
"absolutePath": "project:/contracts/libs/WitnetBuffer.sol",
"exportedSymbols": {
"WitnetBuffer": [
42631
]
},
"id": 42632,
"license": "MIT",
"nodeType": "SourceUnit",
"nodes": [
{
"id": 40743,
"literals": [
"solidity",
">=",
"0.8",
".0",
"<",
"0.9",
".0"
],
"nodeType": "PragmaDirective",
"src": "35:31:117"
},
{
"abstract": false,
"baseContracts": [],
"canonicalName": "WitnetBuffer",
"contractDependencies": [],
"contractKind": "library",
"documentation": {
"id": 40744,
"nodeType": "StructuredDocumentation",
"src": "70:574:117",
"text": "@title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface\n @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will\n start with the byte that goes right after the last one in the previous read.\n @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some\n theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.\n @author The Witnet Foundation."
},
"fullyImplemented": true,
"id": 42631,
"linearizedBaseContracts": [
42631
],
"name": "WitnetBuffer",
"nameLocation": "652:12:117",
"nodeType": "ContractDefinition",
"nodes": [
{
"errorSelector": "240db51c",
"id": 40746,
"name": "EmptyBuffer",
"nameLocation": "678:11:117",
"nodeType": "ErrorDefinition",
"parameters": {
"id": 40745,
"nodeType": "ParameterList",
"parameters": [],
"src": "689:2:117"
},
"src": "672:20:117"
},
{
"errorSelector": "63a056dd",
"id": 40752,
"name": "IndexOutOfBounds",
"nameLocation": "702:16:117",
"nodeType": "ErrorDefinition",
"parameters": {
"id": 40751,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 40748,
"mutability": "mutable",
"name": "index",
"nameLocation": "724:5:117",
"nodeType": "VariableDeclaration",
"scope": 40752,
"src": "719:10:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40747,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "719:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 40750,
"mutability": "mutable",
"name": "range",
"nameLocation": "736:5:117",
"nodeType": "VariableDeclaration",
"scope": 40752,
"src": "731:10:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40749,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "731:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "718:24:117"
},
"src": "696:47:117"
},
{
"errorSelector": "19e1b81c",
"id": 40758,
"name": "MissingArgs",
"nameLocation": "753:11:117",
"nodeType": "ErrorDefinition",
"parameters": {
"id": 40757,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 40754,
"mutability": "mutable",
"name": "expected",
"nameLocation": "770:8:117",
"nodeType": "VariableDeclaration",
"scope": 40758,
"src": "765:13:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40753,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "765:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 40756,
"mutability": "mutable",
"name": "given",
"nameLocation": "785:5:117",
"nodeType": "VariableDeclaration",
"scope": 40758,
"src": "780:10:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40755,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "780:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "764:27:117"
},
"src": "747:45:117"
},
{
"canonicalName": "WitnetBuffer.Buffer",
"documentation": {
"id": 40759,
"nodeType": "StructuredDocumentation",
"src": "798:26:117",
"text": "Iterable bytes buffer."
},
"id": 40764,
"members": [
{
"constant": false,
"id": 40761,
"mutability": "mutable",
"name": "data",
"nameLocation": "857:4:117",
"nodeType": "VariableDeclaration",
"scope": 40764,
"src": "851:10:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
},
"typeName": {
"id": 40760,
"name": "bytes",
"nodeType": "ElementaryTypeName",
"src": "851:5:117",
"typeDescriptions": {
"typeIdentifier": "t_bytes_storage_ptr",
"typeString": "bytes"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 40763,
"mutability": "mutable",
"name": "cursor",
"nameLocation": "875:6:117",
"nodeType": "VariableDeclaration",
"scope": 40764,
"src": "870:11:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40762,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "870:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"name": "Buffer",
"nameLocation": "835:6:117",
"nodeType": "StructDefinition",
"scope": 42631,
"src": "828:59:117",
"visibility": "public"
},
{
"body": {
"id": 40781,
"nodeType": "Block",
"src": "993:95:117",
"statements": [
{
"condition": {
"commonType": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"id": 40772,
"isConstant": false,
"isLValue": false,
"isPure": false,
"lValueRequested": false,
"leftExpression": {
"id": 40770,
"name": "index",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40766,
"src": "1004:5:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"nodeType": "BinaryOperation",
"operator": ">",
"rightExpression": {
"id": 40771,
"name": "_range",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40768,
"src": "1012:6:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"src": "1004:14:117",
"typeDescriptions": {
"typeIdentifier": "t_bool",
"typeString": "bool"
}
},
"id": 40779,
"nodeType": "IfStatement",
"src": "1000:75:117",
"trueBody": {
"id": 40778,
"nodeType": "Block",
"src": "1020:55:117",
"statements": [
{
"errorCall": {
"arguments": [
{
"id": 40774,
"name": "index",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40766,
"src": "1053:5:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
{
"id": 40775,
"name": "_range",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40768,
"src": "1060:6:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
}
],
"expression": {
"argumentTypes": [
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
],
"id": 40773,
"name": "IndexOutOfBounds",
"nodeType": "Identifier",
"overloadedDeclarations": [],
"referencedDeclaration": 40752,
"src": "1036:16:117",
"typeDescriptions": {
"typeIdentifier": "t_function_error_pure$_t_uint256_$_t_uint256_$returns$_t_error_$",
"typeString": "function (uint256,uint256) pure returns (error)"
}
},
"id": 40776,
"isConstant": false,
"isLValue": false,
"isPure": false,
"kind": "functionCall",
"lValueRequested": false,
"nameLocations": [],
"names": [],
"nodeType": "FunctionCall",
"src": "1036:31:117",
"tryCall": false,
"typeDescriptions": {
"typeIdentifier": "t_error",
"typeString": "error"
}
},
"id": 40777,
"nodeType": "RevertStatement",
"src": "1029:38:117"
}
]
}
},
{
"id": 40780,
"nodeType": "PlaceholderStatement",
"src": "1081:1:117"
}
]
},
"id": 40782,
"name": "withinRange",
"nameLocation": "956:11:117",
"nodeType": "ModifierDefinition",
"parameters": {
"id": 40769,
"nodeType": "ParameterList",
"parameters": [
{
"constant": false,
"id": 40766,
"mutability": "mutable",
"name": "index",
"nameLocation": "973:5:117",
"nodeType": "VariableDeclaration",
"scope": 40782,
"src": "968:10:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40765,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "968:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
},
{
"constant": false,
"id": 40768,
"mutability": "mutable",
"name": "_range",
"nameLocation": "985:6:117",
"nodeType": "VariableDeclaration",
"scope": 40782,
"src": "980:11:117",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName": {
"id": 40767,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "980:4:117",
"typeDescriptions": {
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],