BalancerV3: SwapAdapter and Substreams (#126)
* feat: add balancer swapAdapter and Substreams * fix: undo tycho-substreams logs, ignore abi on rustmft * ci: prevent warnings from failing CI * ci: skip size check on CI * chore: forge fmt * feat: vault balance from storage Vault contract tokenBalance message are set according to the vault storage changes in the `_reserveOf` storage variable VaultStorage.sol contract This was the culprit that caused the failure in simulation since balancer enforces the invariant that `token.balanceOf(vault_addr) == _reservesOf[token]` * ci: warnings * fix: avoid duplicated balance changes * fix: order by ordinal * chore: format * feat: extract new contracts before extracting balance changes * feat: skip unnecessary steps if no balance change is found * refactor: filter out account balances for tokens that aren't part of any protocol components. On the indexer side, when we receive an account balance, we need to know about the token. This commit ensure that the token was introduced before we emit any account balance with it. * refactor: don't index liquidity buffers. Liquidity buffers rely on rate providers. Therefore we need DCI (feature to be able to index previously created contract) to deal with them. * refactor: cleanup tests and add docstrings * chore: lock tycho-substreams version * ci: set Foundry workflow to use stable foundry * feat(DCI): Add DCI Entrypoints to BalancerV3 components (#218) * refactor: fix typo in weighted_pool_factory_contract name * feat: add rate_providers static attributes * feat: add DCI entrypoints to BalancerV3 components * fix: set default trade price to Fraction(0, 1) * feat: remove buffers as components Buffers are to be used internally by Boosted pools (stable/weighted pools that use ERC4626 tokens). They are not to be treated as a separate swap component. * test: update test blocks Extend tests some tests block range to ensure liquidity was added to the pool and can be simulated on * feat: remove buffers as components Remove balance updates for buffer components * feat: listen for pool pause/unpause events * chore: formating * fix: encoding call data * test: update Balancer V3 tests to use DCI * test: set indexer log level to info * docs: add comment on support of boosted pools * feat: update balancer v3 package version --------- Co-authored-by: Thales <thales@datarevenue.com> Co-authored-by: zizou <111426680+flopell@users.noreply.github.com> Co-authored-by: Louise Poole <louise@datarevenue.com> Co-authored-by: Louise Poole <louisecarmenpoole@gmail.com>
This commit is contained in:
108
evm/src/libraries/CustomBytesAppend.sol
Normal file
108
evm/src/libraries/CustomBytesAppend.sol
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
library CustomBytesAppend {
|
||||
// Constants for the custom prefix used in the bytes32 format
|
||||
string private constant CUSTOM = "_CUSTOM_";
|
||||
|
||||
/**
|
||||
* @dev Extracts an address from a bytes32 input, assuming it is either
|
||||
* prepended or appended with `_CUSTOM_`.
|
||||
* @param input The bytes32 input containing the address and custom
|
||||
* prefix/suffix.
|
||||
* @return extractedAddress The extracted address.
|
||||
*/
|
||||
function extractAddress(bytes32 input)
|
||||
public
|
||||
pure
|
||||
returns (address extractedAddress)
|
||||
{
|
||||
// Convert the bytes32 input into a dynamic bytes array for manipulation
|
||||
bytes memory inputBytes = abi.encodePacked(input);
|
||||
|
||||
// Check if the bytes contain the custom prefix
|
||||
if (hasPrefix(inputBytes)) {
|
||||
// If prefixed, extract the 20 bytes after the prefix as the address
|
||||
extractedAddress =
|
||||
bytesToAddress(slice(inputBytes, bytes(CUSTOM).length, 20));
|
||||
}
|
||||
// Check if the bytes contain the custom suffix
|
||||
else if (hasSuffix(inputBytes)) {
|
||||
// If suffixed, extract the first 20 bytes as the address
|
||||
extractedAddress = bytesToAddress(slice(inputBytes, 0, 20));
|
||||
} else {
|
||||
// Revert if neither prefix nor suffix is found
|
||||
revert("Invalid input format");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if the bytes data has the custom prefix.
|
||||
* @param data The bytes array to check.
|
||||
* @return True if the prefix matches, false otherwise.
|
||||
*/
|
||||
function hasPrefix(bytes memory data) internal pure returns (bool) {
|
||||
// Compare the first bytes of the input with the prefix using keccak256
|
||||
// for hashing
|
||||
return keccak256(slice(data, 0, bytes(CUSTOM).length))
|
||||
== keccak256(bytes(CUSTOM));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Checks if the bytes data has the custom suffix.
|
||||
* @param data The bytes array to check.
|
||||
* @return True if the suffix matches, false otherwise.
|
||||
*/
|
||||
function hasSuffix(bytes memory data) internal pure returns (bool) {
|
||||
// Compare the last bytes of the input with the suffix using keccak256
|
||||
// for hashing
|
||||
return keccak256(
|
||||
slice(
|
||||
data, data.length - bytes(CUSTOM).length, bytes(CUSTOM).length
|
||||
)
|
||||
) == keccak256(bytes(CUSTOM));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Slices a bytes array.
|
||||
* @param data The bytes array to slice.
|
||||
* @param start The starting index of the slice.
|
||||
* @param length The length of the slice.
|
||||
* @return The sliced bytes array.
|
||||
*/
|
||||
function slice(bytes memory data, uint256 start, uint256 length)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
// Ensure the slice operation does not exceed the bounds of the array
|
||||
require(data.length >= start + length, "Invalid slice");
|
||||
|
||||
// Create a new bytes array to hold the sliced data
|
||||
bytes memory result = new bytes(length);
|
||||
for (uint256 i = 0; i < length; i++) {
|
||||
result[i] = data[start + i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Converts a bytes array of length 20 into an address.
|
||||
* @param data The bytes array (must be 20 bytes long).
|
||||
* @return addr The converted address.
|
||||
*/
|
||||
function bytesToAddress(bytes memory data)
|
||||
internal
|
||||
pure
|
||||
returns (address addr)
|
||||
{
|
||||
// Ensure the input length is exactly 20 bytes (size of an Ethereum
|
||||
// address)
|
||||
require(data.length == 20, "Invalid address length");
|
||||
|
||||
// Use inline assembly to efficiently convert the bytes to an address
|
||||
assembly {
|
||||
addr := mload(add(data, 20))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user