feat(libraries): add byte slicing and multi-hop path encoding

This commit is contained in:
dualfroz committed 2026-08-25 11:44:00 +02:00
1 parent 25bb567003
commit 54b5377369
2 files changed
+90

No files matched your search

+53
View File
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.36;
/// @title Slicing and word reads over tightly packed calldata paths.
library BytesLib {
function slice(bytes memory source, uint256 start, uint256 length) internal pure returns (bytes memory) {
require(length + 31 >= length, "BytesLib: SLICE_OVERFLOW");
require(source.length >= start + length, "BytesLib: SLICE_OOB");
bytes memory result;
assembly {
switch iszero(length)
case 0 {
result := mload(0x40)
let lengthmod := and(length, 31)
let mc := add(add(result, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, length)
for {
let cc := add(add(add(source, lengthmod), mul(0x20, iszero(lengthmod))), start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} { mstore(mc, mload(cc)) }
mstore(result, length)
mstore(0x40, and(add(mc, 31), not(31)))
}
default {
result := mload(0x40)
mstore(result, 0)
mstore(0x40, add(result, 0x20))
}
}
return result;
}
function toAddress(bytes memory source, uint256 start) internal pure returns (address) {
require(source.length >= start + 20, "BytesLib: ADDRESS_OOB");
address result;
assembly {
result := div(mload(add(add(source, 0x20), start)), 0x1000000000000000000000000)
}
return result;
}
function toUint24(bytes memory source, uint256 start) internal pure returns (uint24) {
require(source.length >= start + 3, "BytesLib: UINT24_OOB");
uint24 result;
assembly {
result := mload(add(add(source, 0x3), start))
}
return result;
}
}
+37
View File
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.36;
import {BytesLib} from "./BytesLib.sol";
/// @title Encoding of multi-hop swap paths as packed token/fee/token sequences.
library Path {
using BytesLib for bytes;
uint256 private constant addrSize = 20;
uint256 private constant feeSize = 3;
uint256 private constant nextOffset = addrSize + feeSize;
uint256 private constant popOffset = nextOffset + addrSize;
uint256 private constant multiplePoolsMinLength = popOffset + nextOffset;
function hasMultiplePools(bytes memory path) internal pure returns (bool) {
return path.length >= multiplePoolsMinLength;
}
function numPools(bytes memory path) internal pure returns (uint256) {
return (path.length - addrSize) / nextOffset;
}
function decodeFirstPool(bytes memory path) internal pure returns (address tokenA, address tokenB, uint24 fee) {
tokenA = path.toAddress(0);
fee = path.toUint24(addrSize);
tokenB = path.toAddress(nextOffset);
}
function getFirstPool(bytes memory path) internal pure returns (bytes memory) {
return path.slice(0, popOffset);
}
function skipToken(bytes memory path) internal pure returns (bytes memory) {
return path.slice(nextOffset, path.length - nextOffset);
}
}