Skip to content

Instantly share code, notes, and snippets.

@k06a
Last active May 28, 2020 15:17
Show Gist options
  • Save k06a/097dcac25d33aea6cacc94752a415cb2 to your computer and use it in GitHub Desktop.
Save k06a/097dcac25d33aea6cacc94752a415cb2 to your computer and use it in GitHub Desktop.
function compressCall(encodedCall) {
let zippedBytes = '0x';
for (let i = 2; i < encodedCall.length; i += 2) {
let length = 1;
if (encodedCall[i] === '0' && encodedCall[i + 1] == '0') {
while (
length < 127 &&
i + length*2 < encodedCall.length &&
encodedCall[i + length*2] === '0' && encodedCall[i + length*2 + 1] === '0')
{
length += 1;
}
zippedBytes += (length + 128).toString(16).padStart(2, '0');
i += (length - 1) * 2;
}
else {
while (
length < 127 &&
i + length*2 < encodedCall.length &&
(encodedCall[i + length*2] !== '0' || encodedCall[i + length*2 + 1] !== '0'))
{
length += 1;
}
zippedBytes += length.toString(16).padStart(2, '0') + encodedCall.substr(i, length * 2);
i += (length - 1) * 2;
}
}
return zippedBytes;
}
pragma solidity ^0.5.0;
contract CompressedCaller {
function compressedCall(
address target,
uint256 totalLength,
bytes memory zipped
)
public
payable
returns (bytes memory result)
{
(bytes memory data, uint decompressedLength) = decompress(totalLength, zipped);
require(decompressedLength == totalLength, "Uncompress error");
bool success;
(success, result) = target.call.value(msg.value)(data);
require(success, "Decompressed call failed");
}
function decompress(
uint256 totalLength,
bytes memory zipped
)
public
pure
returns (
bytes memory data,
uint256 index
)
{
data = new bytes(totalLength);
for (uint i = 0; i < zipped.length; i++) {
uint len = uint(uint8(zipped[i]) & 0x7F);
if ((zipped[i] & 0x80) == 0) {
memcpy(data, index, zipped, i + 1, len);
i += len;
}
index += len;
}
}
//
// Modified version of:
// https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol#L45
//
function memcpy(
bytes memory destMem,
uint dest,
bytes memory srcMem,
uint src,
uint len
)
private
pure
{
uint mask = 256 ** (32 - len % 32) - 1;
assembly {
dest := add(add(destMem, 32), dest)
src := add(add(srcMem, 32), src)
// Copy word-length chunks while possible
for { } gt(len, 31) { len := sub(len, 32) } { // (!<) is the same as (>=)
mstore(dest, mload(src))
dest := add(dest, 32)
src := add(src, 32)
}
// Copy remaining bytes
let srcPart := and(mload(src), not(mask))
let destPart := and(mload(dest), mask)
mstore(dest, or(destPart, srcPart))
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment