From b8794fd3a41ea79fe4331136c4759e56c06e917e Mon Sep 17 00:00:00 2001 From: domenicodev Date: Wed, 13 Dec 2023 18:11:58 +0100 Subject: [PATCH 01/86] feat: added documentation, manifests and initial libraries for Integral support --- evm/src/integral/IntegralSwapAdapter.sol | 237 +++++++++++++++++++++++ evm/src/integral/manifest.yaml | 36 ++++ 2 files changed, 273 insertions(+) create mode 100644 evm/src/integral/IntegralSwapAdapter.sol create mode 100644 evm/src/integral/manifest.yaml diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol new file mode 100644 index 0000000..66ecba0 --- /dev/null +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; + +// Integral handles arbirary amounts, but we limit the amount to 10x just in case +uint256 constant RESERVE_LIMIT_FACTOR = 10; + +/// @title Integral Swap Adapter +contract IntegralSwapAdapter is ISwapAdapter { + ITwapFactory immutable factory; + + constructor(address factory_) { + factory = ITwapFactory(factory_); + } + + function price( + bytes32 _poolId, + IERC20 _sellToken, + IERC20 _buyToken, + uint256[] memory _specifiedAmounts + ) external view override returns (Fraction[] memory _prices) { + revert NotImplemented("IntegralSwapAdapter.price"); + } + + function swap( + bytes32 poolId, + IERC20 sellToken, + IERC20 buyToken, + OrderSide side, + uint256 specifiedAmount + ) external returns (Trade memory trade) { + revert NotImplemented("IntegralSwapAdapter.swap"); + } + + function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + external + returns (uint256[] memory limits) + { + revert NotImplemented("IntegralSwapAdapter.getLimits"); + } + + function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + external + returns (Capability[] memory capabilities) + { + revert NotImplemented("IntegralSwapAdapter.getCapabilities"); + } + + function getTokens(bytes32 poolId) + external + returns (IERC20[] memory tokens) + { + revert NotImplemented("IntegralSwapAdapter.getTokens"); + } + + /// @inheritdoc ISwapAdapter + function getPoolIds(uint256 offset, uint256 limit) + external + view + override + returns (bytes32[] memory ids) + { + revert NotImplemented("IntegralSwapAdapter.getPoolIds"); + } +} + +interface ITwapFactory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint256); + event OwnerSet(address owner); + + function owner() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + + function allPairs(uint256) external view returns (address pair); + + function allPairsLength() external view returns (uint256); + + function createPair( + address tokenA, + address tokenB, + address oracle, + address trader + ) external returns (address pair); + + function setOwner(address) external; + + function setMintFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setBurnFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setSwapFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setOracle( + address tokenA, + address tokenB, + address oracle + ) external; + + function setTrader( + address tokenA, + address tokenB, + address trader + ) external; + + function collect( + address tokenA, + address tokenB, + address to + ) external; + + function withdraw( + address tokenA, + address tokenB, + uint256 amount, + address to + ) external; +} + +interface ITwapPair is ITwapERC20, IReserves { + event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to); + event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event SetMintFee(uint256 fee); + event SetBurnFee(uint256 fee); + event SetSwapFee(uint256 fee); + event SetOracle(address account); + event SetTrader(address trader); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + function factory() external view returns (address); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function oracle() external view returns (address); + + function trader() external view returns (address); + + function mintFee() external view returns (uint256); + + function setMintFee(uint256 fee) external; + + function mint(address to) external returns (uint256 liquidity); + + function burnFee() external view returns (uint256); + + function setBurnFee(uint256 fee) external; + + function burn(address to) external returns (uint256 amount0, uint256 amount1); + + function swapFee() external view returns (uint256); + + function setSwapFee(uint256 fee) external; + + function setOracle(address account) external; + + function setTrader(address account) external; + + function collect(address to) external; + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; + + function sync() external; + + function initialize( + address _token0, + address _token1, + address _oracle, + address _trader + ) external; + + function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In); + + function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In); + + function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out); + + function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out); + + function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In); + + function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); +} + +interface ITwapERC20 is IERC20 { + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external view returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); +} + +interface IReserves { + function getReserves() external view returns (uint112 reserve0, uint112 reserve1); + + function getFees() external view returns (uint256 fee0, uint256 fee1); +} diff --git a/evm/src/integral/manifest.yaml b/evm/src/integral/manifest.yaml new file mode 100644 index 0000000..5d3c68e --- /dev/null +++ b/evm/src/integral/manifest.yaml @@ -0,0 +1,36 @@ +# information about the author helps us reach out in case of issues. +author: + name: Propellerheads.xyz + email: alan@propellerheads.xyz + +# Protocol Constants +constants: + protocol_gas: 30000 + # minimum capabilities we can expect, individual pools may extend these + capabilities: + - SellSide + - BuySide + - PriceFunction + +# The file containing the adapter contract +contract: IntegralSwapAdapter.sol + +# Deployment instances used to generate chain specific bytecode. +instances: + - chain: + name: mainnet + id: 0 + arguments: + - "0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6" + +# Specify some automatic test cases in case getPoolIds and +# getTokens are not implemented. +tests: + instances: + - pool_id: "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc" + sell_token: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" + buy_token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" + block: 17000000 + chain: + id: 0 + name: mainnet From d9a1102c323b20252b604067454c4942c1995cf2 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Wed, 13 Dec 2023 18:13:30 +0100 Subject: [PATCH 02/86] feat: Implemented getPoolIds --- evm/src/integral/IntegralSwapAdapter.sol | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 66ecba0..727b129 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -61,7 +61,14 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (bytes32[] memory ids) { - revert NotImplemented("IntegralSwapAdapter.getPoolIds"); + uint256 endIdx = offset + limit; + if (endIdx > factory.allPairsLength()) { + endIdx = factory.allPairsLength(); + } + ids = new bytes32[](endIdx - offset); + for (uint256 i = 0; i < ids.length; i++) { + ids[i] = bytes20(factory.allPairs(offset + i)); + } } } From 54c8253371b880e557e59d0b40cd2c8a9699e9a8 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 10:29:04 +0100 Subject: [PATCH 03/86] feat: Implemented getTokens --- evm/src/integral/IntegralSwapAdapter.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 727b129..0d47243 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -47,11 +47,15 @@ contract IntegralSwapAdapter is ISwapAdapter { revert NotImplemented("IntegralSwapAdapter.getCapabilities"); } + /// @inheritdoc ISwapAdapter function getTokens(bytes32 poolId) external returns (IERC20[] memory tokens) { - revert NotImplemented("IntegralSwapAdapter.getTokens"); + tokens = new IERC20[](2); + IUniswapV2Pair pair = ITwapPair(address(bytes20(poolId))); + tokens[0] = IERC20(pair.token0()); + tokens[1] = IERC20(pair.token1()); } /// @inheritdoc ISwapAdapter From 2decec2bd3aec6c93c30f3d02b49573a545f787e Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 10:30:03 +0100 Subject: [PATCH 04/86] feat: Implemented getCapabilities --- evm/src/integral/IntegralSwapAdapter.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 0d47243..b3c7212 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -40,11 +40,15 @@ contract IntegralSwapAdapter is ISwapAdapter { revert NotImplemented("IntegralSwapAdapter.getLimits"); } + /// @inheritdoc ISwapAdapter function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) external returns (Capability[] memory capabilities) { - revert NotImplemented("IntegralSwapAdapter.getCapabilities"); + capabilities = new Capability[](3); + capabilities[0] = Capability.SellOrder; + capabilities[1] = Capability.BuyOrder; + capabilities[2] = Capability.PriceFunction; } /// @inheritdoc ISwapAdapter From 06e86bdb9bcf2ce14841baf323eb18dfad2fbc76 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 12:58:27 +0100 Subject: [PATCH 05/86] feat: created initial IntegralSwapAdapter test file --- evm/test/IntegralSwapAdapter.t.sol | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 evm/test/IntegralSwapAdapter.t.sol diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol new file mode 100644 index 0000000..cb211e8 --- /dev/null +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "src/interfaces/ISwapAdapterTypes.sol"; +import "src/libraries/FractionMath.sol"; + +/// @title TemplateSwapAdapterTest +/// @dev This is a template for a swap adapter test. +/// Test all functions that are implemented in your swap adapter, the two test included here are just an example. +/// Feel free to use UniswapV2SwapAdapterTest and BalancerV2SwapAdapterTest as a reference. +contract TemplateSwapAdapterTest is Test, ISwapAdapterTypes { + using FractionMath for Fraction; + + function testPriceFuzz(uint256 amount0, uint256 amount1) public {} + + function testSwapFuzz(uint256 specifiedAmount) public {} +} From d993e110d117e92764f943da7d2d818a2730f78c Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 16:43:16 +0100 Subject: [PATCH 06/86] fix: typos, inheritance errors and missing overrides --- evm/src/integral/IntegralSwapAdapter.sol | 58 +++++++++++++----------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index b3c7212..9c976e4 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -43,6 +43,8 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @inheritdoc ISwapAdapter function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) external + pure + override returns (Capability[] memory capabilities) { capabilities = new Capability[](3); @@ -54,10 +56,12 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @inheritdoc ISwapAdapter function getTokens(bytes32 poolId) external + view + override returns (IERC20[] memory tokens) { tokens = new IERC20[](2); - IUniswapV2Pair pair = ITwapPair(address(bytes20(poolId))); + ITwapPair pair = ITwapPair(address(bytes20(poolId))); tokens[0] = IERC20(pair.token0()); tokens[1] = IERC20(pair.token1()); } @@ -145,6 +149,32 @@ interface ITwapFactory { ) external; } +interface ITwapERC20 is IERC20 { + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external view returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); +} + +interface IReserves { + function getReserves() external view returns (uint112 reserve0, uint112 reserve1); + + function getFees() external view returns (uint256 fee0, uint256 fee1); +} + interface ITwapPair is ITwapERC20, IReserves { event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to); event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to); @@ -224,29 +254,3 @@ interface ITwapPair is ITwapERC20, IReserves { function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); } - -interface ITwapERC20 is IERC20 { - function PERMIT_TYPEHASH() external pure returns (bytes32); - - function nonces(address owner) external view returns (uint256); - - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - function increaseAllowance(address spender, uint256 addedValue) external returns (bool); - - function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); -} - -interface IReserves { - function getReserves() external view returns (uint112 reserve0, uint112 reserve1); - - function getFees() external view returns (uint256 fee0, uint256 fee1); -} From 4e519cf21333e068dcbc36fedd91df6cd64ed4fc Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 16:56:45 +0100 Subject: [PATCH 07/86] feat: Added Relayer in constructor and as main target contract --- evm/src/integral/IntegralSwapAdapter.sol | 206 ++++++++++++++++++++++- 1 file changed, 199 insertions(+), 7 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 9c976e4..15461ec 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -3,15 +3,12 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; -// Integral handles arbirary amounts, but we limit the amount to 10x just in case -uint256 constant RESERVE_LIMIT_FACTOR = 10; - /// @title Integral Swap Adapter contract IntegralSwapAdapter is ISwapAdapter { - ITwapFactory immutable factory; + ITwapRelayer immutable relayer; - constructor(address factory_) { - factory = ITwapFactory(factory_); + constructor(address relayer_) { + relayer = ITwapRelayer(relayer_); } function price( @@ -33,11 +30,23 @@ contract IntegralSwapAdapter is ISwapAdapter { revert NotImplemented("IntegralSwapAdapter.swap"); } + /// @inheritdoc ISwapAdapter function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) external returns (uint256[] memory limits) { - revert NotImplemented("IntegralSwapAdapter.getLimits"); + ( + uint256 price_, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + limits = new uint256[](2); + limits[0] = limitMax0; + limits[1] = limitMax1; } /// @inheritdoc ISwapAdapter @@ -73,6 +82,7 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (bytes32[] memory ids) { + ITwapFactory factory = ITwapFactory(relayer.factory()); uint256 endIdx = offset + limit; if (endIdx > factory.allPairsLength()) { endIdx = factory.allPairsLength(); @@ -84,6 +94,188 @@ contract IntegralSwapAdapter is ISwapAdapter { } } +interface ITwapRelayer { + event OwnerSet(address owner); + event RebalancerSet(address rebalancer); + event DelaySet(address delay); + event PairEnabledSet(address pair, bool enabled); + event SwapFeeSet(address pair, uint256 fee); + event TwapIntervalSet(address pair, uint32 interval); + event EthTransferGasCostSet(uint256 gasCost); + event ExecutionGasLimitSet(uint256 limit); + event TokenLimitMinSet(address token, uint256 limit); + event TokenLimitMaxMultiplierSet(address token, uint256 limit); + event ToleranceSet(address pair, uint16 tolerance); + event Approve(address token, address to, uint256 amount); + event Withdraw(address token, address to, uint256 amount); + event Sell( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 amountOut, + uint256 amountOutMin, + bool wrapUnwrap, + uint256 fee, + address indexed to, + address orderContract, + uint256 indexed orderId + ); + event Buy( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 amountInMax, + uint256 amountOut, + bool wrapUnwrap, + uint256 fee, + address indexed to, + address orderContract, + uint256 indexed orderId + ); + event RebalanceSellWithDelay( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 indexed delayOrderId + ); + event RebalanceSellWithOneInch(address indexed oneInchRouter, uint256 gas, bytes data); + event OneInchRouterWhitelisted(address indexed oneInchRouter, bool whitelisted); + + function factory() external pure returns (address); + + function delay() external pure returns (address); + + function weth() external pure returns (address); + + function owner() external view returns (address); + + function rebalancer() external view returns (address); + + function isOneInchRouterWhitelisted(address oneInchRouter) external view returns (bool); + + function setOwner(address _owner) external; + + function swapFee(address pair) external view returns (uint256); + + function setSwapFee(address pair, uint256 fee) external; + + function twapInterval(address pair) external pure returns (uint32); + + function isPairEnabled(address pair) external view returns (bool); + + function setPairEnabled(address pair, bool enabled) external; + + function ethTransferGasCost() external pure returns (uint256); + + function executionGasLimit() external pure returns (uint256); + + function tokenLimitMin(address token) external pure returns (uint256); + + function tokenLimitMaxMultiplier(address token) external pure returns (uint256); + + function tolerance(address pair) external pure returns (uint16); + + function setRebalancer(address _rebalancer) external; + + function whitelistOneInchRouter(address oneInchRouter, bool whitelisted) external; + + function getTolerance(address pair) external pure returns (uint16); + + function getTokenLimitMin(address token) external pure returns (uint256); + + function getTokenLimitMaxMultiplier(address token) external pure returns (uint256); + + function getTwapInterval(address pair) external pure returns (uint32); + + struct SellParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint256 amountOutMin; + bool wrapUnwrap; + address to; + uint32 submitDeadline; + } + + function sell(SellParams memory sellParams) external payable returns (uint256 orderId); + + struct BuyParams { + address tokenIn; + address tokenOut; + uint256 amountInMax; + uint256 amountOut; + bool wrapUnwrap; + address to; + uint32 submitDeadline; + } + + function buy(BuyParams memory buyParams) external payable returns (uint256 orderId); + + function getPriceByPairAddress(address pair, bool inverted) + external + view + returns ( + uint8 xDecimals, + uint8 yDecimals, + uint256 price + ); + + function getPriceByTokenAddresses(address tokenIn, address tokenOut) external view returns (uint256 price); + + function getPoolState(address token0, address token1) + external + view + returns ( + uint256 price, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ); + + function quoteSell( + address tokenIn, + address tokenOut, + uint256 amountIn + ) external view returns (uint256 amountOut); + + function quoteBuy( + address tokenIn, + address tokenOut, + uint256 amountOut + ) external view returns (uint256 amountIn); + + function approve( + address token, + uint256 amount, + address to + ) external; + + function withdraw( + address token, + uint256 amount, + address to + ) external; + + function rebalanceSellWithDelay( + address tokenIn, + address tokenOut, + uint256 amountIn + ) external; + + function rebalanceSellWithOneInch( + address tokenIn, + uint256 amountIn, + address oneInchRouter, + uint256 _gas, + bytes calldata data + ) external; +} + interface ITwapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); event OwnerSet(address owner); From ed8166fc956df6eca29e4e7bbd711c7f44db3d8a Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 16:59:40 +0100 Subject: [PATCH 08/86] feat: Implemented getLimits --- evm/src/integral/IntegralSwapAdapter.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 15461ec..7364e67 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -33,6 +33,8 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @inheritdoc ISwapAdapter function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) external + view + override returns (uint256[] memory limits) { ( From b08963ece059299f8ee2866c400faedecbf45b54 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 14 Dec 2023 17:23:40 +0100 Subject: [PATCH 09/86] fix: changed integral manifest address to Integral Relayer address --- evm/src/integral/manifest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/integral/manifest.yaml b/evm/src/integral/manifest.yaml index 5d3c68e..ac31df9 100644 --- a/evm/src/integral/manifest.yaml +++ b/evm/src/integral/manifest.yaml @@ -21,7 +21,7 @@ instances: name: mainnet id: 0 arguments: - - "0xC480b33eE5229DE3FbDFAD1D2DCD3F3BAD0C56c6" + - "0xd17b3c9784510E33cD5B87b490E79253BcD81e2E" # Specify some automatic test cases in case getPoolIds and # getTokens are not implemented. From 878f788a505659520bf158a5392ec9391e760f8f Mon Sep 17 00:00:00 2001 From: domenicodev Date: Fri, 15 Dec 2023 10:02:13 +0100 Subject: [PATCH 10/86] feat: Implemented price --- evm/src/integral/IntegralSwapAdapter.sol | 47 +++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 7364e67..3b83238 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -11,13 +11,26 @@ contract IntegralSwapAdapter is ISwapAdapter { relayer = ITwapRelayer(relayer_); } + /// @inheritdoc ISwapAdapter function price( bytes32 _poolId, IERC20 _sellToken, IERC20 _buyToken, uint256[] memory _specifiedAmounts ) external view override returns (Fraction[] memory _prices) { - revert NotImplemented("IntegralSwapAdapter.price"); + _prices = new Fraction[](_specifiedAmounts.length); + ITwapPair pair = ITwapPair(address(bytes20(_poolId))); + uint112 r0; + uint112 r1; + if (address(_sellToken) == pair.token0()) { // sell + (r0, r1) = pair.getReserves(); + } else { // buy + (r1, r0) = pair.getReserves(); + } + + for (uint256 i = 0; i < _specifiedAmounts.length; i++) { + _prices[i] = getPriceAt(_specifiedAmounts[i], r0, r1, pair); + } } function swap( @@ -94,6 +107,38 @@ contract IntegralSwapAdapter is ISwapAdapter { ids[i] = bytes20(factory.allPairs(offset + i)); } } + + /// @notice Calculates pool prices after trade for specified amounts + /// @param amountIn The amount of the token being sold. + /// @param reserveIn The reserve of the token being sold. + /// @param reserveOut The reserve of the token being bought. + /// @param pair (ITwapPair) The pair where to execute the swap in. + /// @dev Although Integral declares in its Docs that the fee is 1 BP(0.01%, 0.0001 multiplier), + /// it can be changed at any time by calling a function of the contract by its owner or operator, + /// therefore it is obtained dynamically to ensure this function output remains reliable over time + /// @return The price as a fraction corresponding to the provided amount. + function getPriceAt(uint256 amountIn, uint256 reserveIn, uint256 reserveOut, ITwapPair pair) + internal + view + returns (Fraction memory) + { + if (reserveIn == 0 || reserveOut == 0) { + revert Unavailable("At least one reserve is zero!"); + } + uint256 feeBP = relayer.swapFee(address(pair)); + + uint256 amountInWithFee = amountIn - ( (amountIn * feeBP) / 10**18 ); + uint256 numerator = amountInWithFee * reserveOut; + uint256 denominator = (reserveIn * 1000) + amountInWithFee; + uint256 amountOut = numerator / denominator; + uint256 newReserveOut = reserveOut - amountOut; + uint256 newReserveIn = reserveIn + amountIn; + + return Fraction( + newReserveOut * 1000, + newReserveIn - ( (newReserveIn * feeBP) / 10**18 ) + ); + } } interface ITwapRelayer { From 5686e194027488c38313d412287c6d6b817ce7a9 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Fri, 15 Dec 2023 20:32:16 +0100 Subject: [PATCH 11/86] feat: Implemented swap with buy and sell functions --- evm/src/integral/IntegralSwapAdapter.sol | 84 +++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 3b83238..db5e906 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -3,6 +3,9 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; +/// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap +uint32 constant SWAP_DEADLINE_SEC = 1000; + /// @title Integral Swap Adapter contract IntegralSwapAdapter is ISwapAdapter { ITwapRelayer immutable relayer; @@ -40,7 +43,28 @@ contract IntegralSwapAdapter is ISwapAdapter { OrderSide side, uint256 specifiedAmount ) external returns (Trade memory trade) { - revert NotImplemented("IntegralSwapAdapter.swap"); + if (specifiedAmount == 0) { + return trade; + } + + ITwapPair pair = ITwapPair(address(bytes20(poolId))); + uint112 r0; + uint112 r1; + if (address(sellToken) == pair.token0()) { + (r0, r1) = pair.getReserves(); + } else { + (r1, r0) = pair.getReserves(); + } + uint256 gasBefore = gasleft(); + if (side == OrderSide.Sell) { // sell + trade.calculatedAmount = + sell(address(sellToken), address(buyToken), specifiedAmount); + } else { // buy + trade.calculatedAmount = + buy(address(sellToken), address(buyToken), specifiedAmount); + } + trade.gasUsed = gasBefore - gasleft(); + trade.price = getPriceAt(specifiedAmount, r0, r1, pair); } /// @inheritdoc ISwapAdapter @@ -139,6 +163,64 @@ contract IntegralSwapAdapter is ISwapAdapter { newReserveIn - ( (newReserveIn * feeBP) / 10**18 ) ); } + + /// @notice Executes a sell order on a given pool. + /// @param sellToken The address of the token being sold. + /// @param buyToken The address of the token being bought. + /// @param amount The amount to be traded. + /// @return uint256 The amount of tokens received. + function sell( + address sellToken, + address buyToken, + uint256 amount + ) internal returns (uint256) { + address swapper = msg.sender; + uint256 amountOut = relayer.quoteSell(sellToken, buyToken, amount); + + if (amountOut == 0) { + revert Unavailable("AmountOut is zero!"); + } + relayer.sell(ITwapRelayer.SellParams({ + tokenIn: sellToken, + tokenOut: buyToken, + wrapUnwrap: false, + to: swapper, + submitDeadline: SWAP_DEADLINE_SEC, + amountIn: amount, + amountOutMin: amountOut + })); + + return amountOut; + } + + /// @notice Executes a buy order on a given pool. + /// @param sellToken The address of the token being sold. + /// @param buyToken The address of the token being bought. + /// @param amountBought The amount of buyToken tokens to buy. + /// @return uint256 The amount of tokens received. + function buy( + address sellToken, + address buyToken, + uint256 amountBought + ) internal returns (uint256) { + address swapper = msg.sender; + uint256 amountIn = relayer.quoteBuy(sellToken, buyToken, amountBought); + + if (amountIn == 0) { + revert Unavailable("AmountIn is zero!"); + } + relayer.buy(ITwapRelayer.BuyParams({ + tokenIn: sellToken, + tokenOut: buyToken, + wrapUnwrap: false, + to: swapper, + submitDeadline: SWAP_DEADLINE_SEC, + amountInMax: amountIn, + amountOut: amountBought + })); + + return amountIn; + } } interface ITwapRelayer { From cd8e9c61b37e06f056e961e8a268e28316f4cebf Mon Sep 17 00:00:00 2001 From: domenicodev Date: Tue, 19 Dec 2023 11:43:00 +0100 Subject: [PATCH 12/86] fix: Improved SWAP_DEADLINE_SEC comment text --- evm/src/integral/IntegralSwapAdapter.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index db5e906..25d498f 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; -/// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap +/// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long +/// as the contract allows less durations, we use 1000 seconds (15 minutes) as deadline uint32 constant SWAP_DEADLINE_SEC = 1000; /// @title Integral Swap Adapter From 2565b3eba521f6d2473040d8b42379665681b329 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Tue, 19 Dec 2023 16:35:41 +0100 Subject: [PATCH 13/86] Added missing desc in swap function --- evm/src/integral/IntegralSwapAdapter.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 25d498f..fdae3ba 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -37,6 +37,7 @@ contract IntegralSwapAdapter is ISwapAdapter { } } + /// @inheritdoc ISwapAdapter function swap( bytes32 poolId, IERC20 sellToken, From 5e7d39fa7ae72bca165a5d86510a38443ef57cd6 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 21 Dec 2023 10:08:22 +0100 Subject: [PATCH 14/86] fix: fixed submit deadline and transfers on sell and buy functions --- evm/src/integral/IntegralSwapAdapter.sol | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index fdae3ba..c35d6f9 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -4,8 +4,8 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; /// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long -/// as the contract allows less durations, we use 1000 seconds (15 minutes) as deadline -uint32 constant SWAP_DEADLINE_SEC = 1000; +/// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline +uint256 constant SWAP_DEADLINE_SEC = 1000; /// @title Integral Swap Adapter contract IntegralSwapAdapter is ISwapAdapter { @@ -85,9 +85,11 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 limitMax1 ) = relayer.getPoolState(address(sellToken), address(buyToken)); - limits = new uint256[](2); + limits = new uint256[](4); limits[0] = limitMax0; limits[1] = limitMax1; + limits[2] = limitMin0; + limits[3] = limitMin1; } /// @inheritdoc ISwapAdapter @@ -182,12 +184,16 @@ contract IntegralSwapAdapter is ISwapAdapter { if (amountOut == 0) { revert Unavailable("AmountOut is zero!"); } + + IERC20(sellToken).transferFrom(msg.sender, address(this), amount); + IERC20(sellToken).approve(address(relayer), amount); + relayer.sell(ITwapRelayer.SellParams({ tokenIn: sellToken, tokenOut: buyToken, wrapUnwrap: false, to: swapper, - submitDeadline: SWAP_DEADLINE_SEC, + submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountIn: amount, amountOutMin: amountOut })); @@ -211,12 +217,16 @@ contract IntegralSwapAdapter is ISwapAdapter { if (amountIn == 0) { revert Unavailable("AmountIn is zero!"); } + + IERC20(sellToken).transferFrom(msg.sender, address(this), amountIn); + IERC20(sellToken).approve(address(relayer), amountIn); + relayer.buy(ITwapRelayer.BuyParams({ tokenIn: sellToken, tokenOut: buyToken, wrapUnwrap: false, to: swapper, - submitDeadline: SWAP_DEADLINE_SEC, + submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountInMax: amountIn, amountOut: amountBought })); From c470b2a20e377d532af8eeabd92054e152fef324 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 21 Dec 2023 17:43:07 +0100 Subject: [PATCH 15/86] fix: Fixed limits --- evm/src/integral/IntegralSwapAdapter.sol | 110 ++++++++++------------- 1 file changed, 46 insertions(+), 64 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index c35d6f9..a79c75e 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -16,6 +16,12 @@ contract IntegralSwapAdapter is ISwapAdapter { } /// @inheritdoc ISwapAdapter + /// @dev Integral always relies on a single pool linked to the factory to map two pairs, and does not use routing + /// we can then use getPriceByTokenAddresses() instead of getPriceByPairAddresses() + /// as they both return the same value and the first also handles the order of tokens inside. + /// @dev Since the price of a token is determined externally by Integral Oracles and not by reserves + /// it will always be the same (pre and post trade) and independent of the amounts swapped, + /// but we still return an array of length=specifiedAmounts.length with same values to make sure the return value is the expected from caller. function price( bytes32 _poolId, IERC20 _sellToken, @@ -24,16 +30,15 @@ contract IntegralSwapAdapter is ISwapAdapter { ) external view override returns (Fraction[] memory _prices) { _prices = new Fraction[](_specifiedAmounts.length); ITwapPair pair = ITwapPair(address(bytes20(_poolId))); - uint112 r0; - uint112 r1; - if (address(_sellToken) == pair.token0()) { // sell - (r0, r1) = pair.getReserves(); - } else { // buy - (r1, r0) = pair.getReserves(); + + bool inverted = false; + if (address(_sellToken) == pair.token1()) { + inverted = true; } + uint256 price = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = getPriceAt(_specifiedAmounts[i], r0, r1, pair); + _prices[i] = price; } } @@ -49,14 +54,6 @@ contract IntegralSwapAdapter is ISwapAdapter { return trade; } - ITwapPair pair = ITwapPair(address(bytes20(poolId))); - uint112 r0; - uint112 r1; - if (address(sellToken) == pair.token0()) { - (r0, r1) = pair.getReserves(); - } else { - (r1, r0) = pair.getReserves(); - } uint256 gasBefore = gasleft(); if (side == OrderSide.Sell) { // sell trade.calculatedAmount = @@ -66,7 +63,7 @@ contract IntegralSwapAdapter is ISwapAdapter { buy(address(sellToken), address(buyToken), specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); - trade.price = getPriceAt(specifiedAmount, r0, r1, pair); + trade.price = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); } /// @inheritdoc ISwapAdapter @@ -76,20 +73,7 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (uint256[] memory limits) { - ( - uint256 price_, - uint256 fee, - uint256 limitMin0, - uint256 limitMax0, - uint256 limitMin1, - uint256 limitMax1 - ) = relayer.getPoolState(address(sellToken), address(buyToken)); - - limits = new uint256[](4); - limits[0] = limitMax0; - limits[1] = limitMax1; - limits[2] = limitMin0; - limits[3] = limitMin1; + return _getLimits(poollId, sellToken, buyToken); } /// @inheritdoc ISwapAdapter @@ -136,38 +120,6 @@ contract IntegralSwapAdapter is ISwapAdapter { } } - /// @notice Calculates pool prices after trade for specified amounts - /// @param amountIn The amount of the token being sold. - /// @param reserveIn The reserve of the token being sold. - /// @param reserveOut The reserve of the token being bought. - /// @param pair (ITwapPair) The pair where to execute the swap in. - /// @dev Although Integral declares in its Docs that the fee is 1 BP(0.01%, 0.0001 multiplier), - /// it can be changed at any time by calling a function of the contract by its owner or operator, - /// therefore it is obtained dynamically to ensure this function output remains reliable over time - /// @return The price as a fraction corresponding to the provided amount. - function getPriceAt(uint256 amountIn, uint256 reserveIn, uint256 reserveOut, ITwapPair pair) - internal - view - returns (Fraction memory) - { - if (reserveIn == 0 || reserveOut == 0) { - revert Unavailable("At least one reserve is zero!"); - } - uint256 feeBP = relayer.swapFee(address(pair)); - - uint256 amountInWithFee = amountIn - ( (amountIn * feeBP) / 10**18 ); - uint256 numerator = amountInWithFee * reserveOut; - uint256 denominator = (reserveIn * 1000) + amountInWithFee; - uint256 amountOut = numerator / denominator; - uint256 newReserveOut = reserveOut - amountOut; - uint256 newReserveIn = reserveIn + amountIn; - - return Fraction( - newReserveOut * 1000, - newReserveIn - ( (newReserveIn * feeBP) / 10**18 ) - ); - } - /// @notice Executes a sell order on a given pool. /// @param sellToken The address of the token being sold. /// @param buyToken The address of the token being bought. @@ -179,8 +131,13 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 amount ) internal returns (uint256) { address swapper = msg.sender; - uint256 amountOut = relayer.quoteSell(sellToken, buyToken, amount); + (uint256 limitMinSellToken, , uint256 limitMaxSellToken) = _getLimits(_poolId, _sellToken, _buyToken); + if(amount < limitMinSellToken || amount > limitMaxSellToken) { + revert Unavailable("specifiedAmount is out of limits range"); + } + + uint256 amountOut = relayer.quoteSell(sellToken, buyToken, amount); if (amountOut == 0) { revert Unavailable("AmountOut is zero!"); } @@ -212,8 +169,13 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 amountBought ) internal returns (uint256) { address swapper = msg.sender; - uint256 amountIn = relayer.quoteBuy(sellToken, buyToken, amountBought); + (, uint256 limitMinBuyToken, , uint256 limitMaxBuyToken) = _getLimits(_poolId, _sellToken, _buyToken); + if(amountBought < limitMinBuyToken || amountBought > limitMaxBuyToken) { + revert Unavailable("specifiedAmount is out of limits range"); + } + + uint256 amountIn = relayer.quoteBuy(sellToken, buyToken, amountBought); if (amountIn == 0) { revert Unavailable("AmountIn is zero!"); } @@ -233,6 +195,26 @@ contract IntegralSwapAdapter is ISwapAdapter { return amountIn; } + + /// @notice Internal counterpart of _getLimits + /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. + /// @return limits[4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken + function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { + ( + uint256 price_, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + limits = new uint256[](4); + limits[0] = limitMax0; + limits[1] = limitMax1; + limits[2] = limitMin0; + limits[3] = limitMin1; + } } interface ITwapRelayer { From 87193425a8ea76dd6a772c3c7a44cc357bd63565 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:22:55 +0100 Subject: [PATCH 16/86] added IntegralSwapAdapterFix.sol and set up IntegralSwapAdapter.t.sol --- evm/src/integral/IntegralSwapAdapterFix.sol | 585 ++++++++++++++++++++ evm/test/IntegralSwapAdapter.t.sol | 28 +- 2 files changed, 606 insertions(+), 7 deletions(-) create mode 100644 evm/src/integral/IntegralSwapAdapterFix.sol diff --git a/evm/src/integral/IntegralSwapAdapterFix.sol b/evm/src/integral/IntegralSwapAdapterFix.sol new file mode 100644 index 0000000..c70c0e6 --- /dev/null +++ b/evm/src/integral/IntegralSwapAdapterFix.sol @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity ^0.8.13; + +import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; +import { console } from "forge-std/Test.sol"; + +/// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long +/// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline +uint256 constant SWAP_DEADLINE_SEC = 1000; + +/// @title Integral Swap Adapter +contract IntegralSwapAdapter is ISwapAdapter { + ITwapRelayer immutable relayer; + + constructor(address relayer_) { + relayer = ITwapRelayer(relayer_); + } + + /// @inheritdoc ISwapAdapter + /// @dev Integral always relies on a single pool linked to the factory to map two pairs, and does not use routing + /// we can then use getPriceByTokenAddresses() instead of getPriceByPairAddresses() + /// as they both return the same value and the first also handles the order of tokens inside. + /// @dev Since the price of a token is determined externally by Integral Oracles and not by reserves + /// it will always be the same (pre and post trade) and independent of the amounts swapped, + /// but we still return an array of length=specifiedAmounts.length with same values to make sure the return value is the expected from caller. + function price( + bytes32 _poolId, + IERC20 _sellToken, + IERC20 _buyToken, + uint256[] memory _specifiedAmounts + ) external view override returns (Fraction[] memory _prices) { + _prices = new Fraction[](_specifiedAmounts.length); + ITwapPair pair = ITwapPair(address(bytes20(_poolId))); + + bool inverted = false; + if (address(_sellToken) == pair.token1()) { + inverted = true; + } + uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); + + for (uint256 i = 0; i < _specifiedAmounts.length; i++) { + _prices[i] = Fraction(price_, 1); + } + } + + /// @inheritdoc ISwapAdapter + function swap( + bytes32 poolId, + IERC20 sellToken, + IERC20 buyToken, + OrderSide side, + uint256 specifiedAmount + ) external returns (Trade memory trade) { + if (specifiedAmount == 0) { + return trade; + } + + uint256 gasBefore = gasleft(); + if (side == OrderSide.Sell) { // sell + trade.calculatedAmount = + sell(sellToken, buyToken, specifiedAmount); + } else { // buy + trade.calculatedAmount = + buy(sellToken, buyToken, specifiedAmount); + } + trade.gasUsed = gasBefore - gasleft(); + trade.price = Fraction(relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)), 1); + } + + /// @inheritdoc ISwapAdapter + function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + external + view + override + returns (uint256[] memory limits) + { + return _getLimits(poolId, sellToken, buyToken); + } + + /// @inheritdoc ISwapAdapter + function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + external + pure + override + returns (Capability[] memory capabilities) + { + capabilities = new Capability[](3); + capabilities[0] = Capability.SellOrder; + capabilities[1] = Capability.BuyOrder; + capabilities[2] = Capability.PriceFunction; + } + + /// @inheritdoc ISwapAdapter + function getTokens(bytes32 poolId) + external + view + override + returns (IERC20[] memory tokens) + { + tokens = new IERC20[](2); + ITwapPair pair = ITwapPair(address(bytes20(poolId))); + tokens[0] = IERC20(pair.token0()); + tokens[1] = IERC20(pair.token1()); + } + + /// @inheritdoc ISwapAdapter + function getPoolIds(uint256 offset, uint256 limit) + external + view + override + returns (bytes32[] memory ids) + { + ITwapFactory factory = ITwapFactory(relayer.factory()); + uint256 endIdx = offset + limit; + if (endIdx > factory.allPairsLength()) { + endIdx = factory.allPairsLength(); + } + ids = new bytes32[](endIdx - offset); + for (uint256 i = 0; i < ids.length; i++) { + ids[i] = bytes20(factory.allPairs(offset + i)); + } + } + + /// @notice Executes a sell order on a given pool. + /// @param sellToken The address of the token being sold. + /// @param buyToken The address of the token being bought. + /// @param amount The amount to be traded. + /// @return uint256 The amount of tokens received. + function sell( + IERC20 sellToken, + IERC20 buyToken, + uint256 amount + ) internal returns (uint256) { + address swapper = msg.sender; + + uint256[] memory limits = _getLimits(0, sellToken, buyToken); + + console.log("FIN QUI OK"); + + if(amount > limits[0] || amount < limits[2]) { + revert Unavailable("amount is out of limits range"); + } + + console.log("FIN QUI OK 1"); + + uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); + console.log("FIN QUI OK 2"); + if (amountOut == 0) { + revert Unavailable("AmountOut is zero!"); + } + + console.log("FIN QUI OK 3"); + + sellToken.transferFrom(msg.sender, address(this), amount); + console.log("FIN QUI OK 4"); + sellToken.approve(address(relayer), amount); + console.log("FIN QUI OK 5"); + + relayer.sell(ITwapRelayer.SellParams({ + tokenIn: address(sellToken), + tokenOut: address(buyToken), + wrapUnwrap: false, + to: swapper, + submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), + amountIn: amount, + amountOutMin: amountOut + })); + console.log("FIN QUI OK 6"); + + return amountOut; + } + + /// @notice Executes a buy order on a given pool. + /// @param sellToken The address of the token being sold. + /// @param buyToken The address of the token being bought. + /// @param amountBought The amount of buyToken tokens to buy. + /// @return uint256 The amount of tokens received. + function buy( + IERC20 sellToken, + IERC20 buyToken, + uint256 amountBought + ) internal returns (uint256) { + address swapper = msg.sender; + + uint256[] memory limits = _getLimits(0, sellToken, buyToken); + if(amountBought > limits[1] || amountBought < limits[3]) { + revert Unavailable("amountBought is out of limits range"); + } + + uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); + if (amountIn == 0) { + revert Unavailable("AmountIn is zero!"); + } + + sellToken.transferFrom(msg.sender, address(this), amountIn); + sellToken.approve(address(relayer), amountIn); + + relayer.buy(ITwapRelayer.BuyParams({ + tokenIn: address(sellToken), + tokenOut: address(buyToken), + wrapUnwrap: false, + to: swapper, + submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), + amountInMax: amountIn, + amountOut: amountBought + })); + + return amountIn; + } + + /// @notice Internal counterpart of _getLimits + /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. + /// @return limits [length:4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken + function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { + ( + uint256 price_, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + uint256[] memory limits_ = new uint256[](4); + limits_[0] = limitMax0; + limits_[1] = limitMax1; + limits_[2] = limitMin0; + limits_[3] = limitMin1; + + return limits_; + } +} + +interface ITwapRelayer { + event OwnerSet(address owner); + event RebalancerSet(address rebalancer); + event DelaySet(address delay); + event PairEnabledSet(address pair, bool enabled); + event SwapFeeSet(address pair, uint256 fee); + event TwapIntervalSet(address pair, uint32 interval); + event EthTransferGasCostSet(uint256 gasCost); + event ExecutionGasLimitSet(uint256 limit); + event TokenLimitMinSet(address token, uint256 limit); + event TokenLimitMaxMultiplierSet(address token, uint256 limit); + event ToleranceSet(address pair, uint16 tolerance); + event Approve(address token, address to, uint256 amount); + event Withdraw(address token, address to, uint256 amount); + event Sell( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 amountOut, + uint256 amountOutMin, + bool wrapUnwrap, + uint256 fee, + address indexed to, + address orderContract, + uint256 indexed orderId + ); + event Buy( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 amountInMax, + uint256 amountOut, + bool wrapUnwrap, + uint256 fee, + address indexed to, + address orderContract, + uint256 indexed orderId + ); + event RebalanceSellWithDelay( + address indexed sender, + address tokenIn, + address tokenOut, + uint256 amountIn, + uint256 indexed delayOrderId + ); + event RebalanceSellWithOneInch(address indexed oneInchRouter, uint256 gas, bytes data); + event OneInchRouterWhitelisted(address indexed oneInchRouter, bool whitelisted); + + function factory() external pure returns (address); + + function delay() external pure returns (address); + + function weth() external pure returns (address); + + function owner() external view returns (address); + + function rebalancer() external view returns (address); + + function isOneInchRouterWhitelisted(address oneInchRouter) external view returns (bool); + + function setOwner(address _owner) external; + + function swapFee(address pair) external view returns (uint256); + + function setSwapFee(address pair, uint256 fee) external; + + function twapInterval(address pair) external pure returns (uint32); + + function isPairEnabled(address pair) external view returns (bool); + + function setPairEnabled(address pair, bool enabled) external; + + function ethTransferGasCost() external pure returns (uint256); + + function executionGasLimit() external pure returns (uint256); + + function tokenLimitMin(address token) external pure returns (uint256); + + function tokenLimitMaxMultiplier(address token) external pure returns (uint256); + + function tolerance(address pair) external pure returns (uint16); + + function setRebalancer(address _rebalancer) external; + + function whitelistOneInchRouter(address oneInchRouter, bool whitelisted) external; + + function getTolerance(address pair) external pure returns (uint16); + + function getTokenLimitMin(address token) external pure returns (uint256); + + function getTokenLimitMaxMultiplier(address token) external pure returns (uint256); + + function getTwapInterval(address pair) external pure returns (uint32); + + struct SellParams { + address tokenIn; + address tokenOut; + uint256 amountIn; + uint256 amountOutMin; + bool wrapUnwrap; + address to; + uint32 submitDeadline; + } + + function sell(SellParams memory sellParams) external payable returns (uint256 orderId); + + struct BuyParams { + address tokenIn; + address tokenOut; + uint256 amountInMax; + uint256 amountOut; + bool wrapUnwrap; + address to; + uint32 submitDeadline; + } + + function buy(BuyParams memory buyParams) external payable returns (uint256 orderId); + + function getPriceByPairAddress(address pair, bool inverted) + external + view + returns ( + uint8 xDecimals, + uint8 yDecimals, + uint256 price + ); + + function getPriceByTokenAddresses(address tokenIn, address tokenOut) external view returns (uint256 price); + + function getPoolState(address token0, address token1) + external + view + returns ( + uint256 price, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ); + + function quoteSell( + address tokenIn, + address tokenOut, + uint256 amountIn + ) external view returns (uint256 amountOut); + + function quoteBuy( + address tokenIn, + address tokenOut, + uint256 amountOut + ) external view returns (uint256 amountIn); + + function approve( + address token, + uint256 amount, + address to + ) external; + + function withdraw( + address token, + uint256 amount, + address to + ) external; + + function rebalanceSellWithDelay( + address tokenIn, + address tokenOut, + uint256 amountIn + ) external; + + function rebalanceSellWithOneInch( + address tokenIn, + uint256 amountIn, + address oneInchRouter, + uint256 _gas, + bytes calldata data + ) external; +} + +interface ITwapFactory { + event PairCreated(address indexed token0, address indexed token1, address pair, uint256); + event OwnerSet(address owner); + + function owner() external view returns (address); + + function getPair(address tokenA, address tokenB) external view returns (address pair); + + function allPairs(uint256) external view returns (address pair); + + function allPairsLength() external view returns (uint256); + + function createPair( + address tokenA, + address tokenB, + address oracle, + address trader + ) external returns (address pair); + + function setOwner(address) external; + + function setMintFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setBurnFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setSwapFee( + address tokenA, + address tokenB, + uint256 fee + ) external; + + function setOracle( + address tokenA, + address tokenB, + address oracle + ) external; + + function setTrader( + address tokenA, + address tokenB, + address trader + ) external; + + function collect( + address tokenA, + address tokenB, + address to + ) external; + + function withdraw( + address tokenA, + address tokenB, + uint256 amount, + address to + ) external; +} + +interface ITwapERC20 is IERC20 { + function PERMIT_TYPEHASH() external pure returns (bytes32); + + function nonces(address owner) external view returns (uint256); + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function increaseAllowance(address spender, uint256 addedValue) external returns (bool); + + function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); +} + +interface IReserves { + function getReserves() external view returns (uint112 reserve0, uint112 reserve1); + + function getFees() external view returns (uint256 fee0, uint256 fee1); +} + +interface ITwapPair is ITwapERC20, IReserves { + event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to); + event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to); + event Swap( + address indexed sender, + uint256 amount0In, + uint256 amount1In, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event SetMintFee(uint256 fee); + event SetBurnFee(uint256 fee); + event SetSwapFee(uint256 fee); + event SetOracle(address account); + event SetTrader(address trader); + + function MINIMUM_LIQUIDITY() external pure returns (uint256); + + function factory() external view returns (address); + + function token0() external view returns (address); + + function token1() external view returns (address); + + function oracle() external view returns (address); + + function trader() external view returns (address); + + function mintFee() external view returns (uint256); + + function setMintFee(uint256 fee) external; + + function mint(address to) external returns (uint256 liquidity); + + function burnFee() external view returns (uint256); + + function setBurnFee(uint256 fee) external; + + function burn(address to) external returns (uint256 amount0, uint256 amount1); + + function swapFee() external view returns (uint256); + + function setSwapFee(uint256 fee) external; + + function setOracle(address account) external; + + function setTrader(address account) external; + + function collect(address to) external; + + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to, + bytes calldata data + ) external; + + function sync() external; + + function initialize( + address _token0, + address _token1, + address _oracle, + address _trader + ) external; + + function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In); + + function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In); + + function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out); + + function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out); + + function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In); + + function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); +} \ No newline at end of file diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index cb211e8..d791b3d 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -2,17 +2,31 @@ pragma solidity ^0.8.13; import "forge-std/Test.sol"; +import "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import "src/interfaces/ISwapAdapterTypes.sol"; import "src/libraries/FractionMath.sol"; +import "src/integral/IntegralSwapAdapterFix.sol"; -/// @title TemplateSwapAdapterTest -/// @dev This is a template for a swap adapter test. -/// Test all functions that are implemented in your swap adapter, the two test included here are just an example. -/// Feel free to use UniswapV2SwapAdapterTest and BalancerV2SwapAdapterTest as a reference. -contract TemplateSwapAdapterTest is Test, ISwapAdapterTypes { +contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { using FractionMath for Fraction; - function testPriceFuzz(uint256 amount0, uint256 amount1) public {} + IntegralSwapAdapter adapter; + IERC20 constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); + IERC20 constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); + address constant USDC_WETH_PAIR = 0x2fe16Dd18bba26e457B7dD2080d5674312b026a2; + address constant relayerAddress = 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E; + + uint256 constant TEST_ITERATIONS = 100; + + function setUp() public { + uint256 forkBlock = 18835309; + vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); + adapter = new IntegralSwapAdapter(relayerAddress); + + vm.label(address(WETH), "WETH"); + vm.label(address(USDC), "USDC"); + vm.label(address(USDC_WETH_PAIR), "USDC_WETH_PAIR"); + + } - function testSwapFuzz(uint256 specifiedAmount) public {} } From 6c3eeff32908b9ae83f27b820096408f5a55b5b7 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:29:02 +0100 Subject: [PATCH 17/86] testPriceFuzzIntegral --- evm/src/integral/IntegralSwapAdapter.sol | 2 ++ evm/test/IntegralSwapAdapter.t.sol | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index a79c75e..6f6d2f7 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -1,3 +1,4 @@ +/* // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.13; @@ -569,3 +570,4 @@ interface ITwapPair is ITwapERC20, IReserves { function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); } +*/ \ No newline at end of file diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index d791b3d..e13cbc4 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -29,4 +29,22 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } + function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); + vm.assume(amount0 < limits[0]); + vm.assume(amount1 < limits[1]); + + uint256[] memory amounts = new uint256[](2); + amounts[0] = amount0; + amounts[1] = amount1; + + Fraction[] memory prices = adapter.price(pair, WETH, USDC, amounts); + + for (uint256 i = 0; i < prices.length; i++) { + assertGt(prices[i].numerator, 0); + assertGt(prices[i].denominator, 0); + } + } + } From d736631d521629d132af68a8cfe66b0805464370 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:32:10 +0100 Subject: [PATCH 18/86] testPriceDecreasing failing --- evm/test/IntegralSwapAdapter.t.sol | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index e13cbc4..a677ec7 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -29,6 +29,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } + function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); @@ -47,4 +48,22 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } + + function testPriceDecreasingIntegral() public { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + uint256[] memory amounts = new uint256[](TEST_ITERATIONS); + + for (uint256 i = 0; i < TEST_ITERATIONS; i++) { + amounts[i] = 1000 * i * 10 ** 6; + } + + Fraction[] memory prices = adapter.price(pair, USDC, WETH, amounts); + + for (uint256 i = 0; i < TEST_ITERATIONS - 1; i++) { + assertEq(prices[i].compareFractions(prices[i + 1]), 1); + assertGt(prices[i].denominator, 0); + assertGt(prices[i + 1].denominator, 0); + } + } + } From 8b8f22f59469091b9f50a36d9c33a8bf995add03 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:34:50 +0100 Subject: [PATCH 19/86] testSwapBuyWethIntegral passed --- evm/test/IntegralSwapAdapter.t.sol | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index a677ec7..c112aed 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -66,4 +66,35 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } + function testSwapBuyWethIntegral(uint256 specifiedAmount) public { + OrderSide side = OrderSide.Buy; + + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + + uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); + + vm.assume(specifiedAmount < limits[1]); + vm.assume(specifiedAmount > limits[3]); + + deal(address(USDC), address(this), type(uint256).max); + USDC.approve(address(adapter), type(uint256).max); + + uint256 usdc_balance = USDC.balanceOf(address(this)); + uint256 weth_balance = WETH.balanceOf(address(this)); + + Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); + + if (trade.calculatedAmount > 0) { + assertEq(specifiedAmount, + WETH.balanceOf(address(this)) + weth_balance + ); + + assertEq( + trade.calculatedAmount, + usdc_balance - USDC.balanceOf(address(this)) + ); + } + + } + } From 6a9cae7b0f7f9c33f9837f2fc443490fb7af3181 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:40:27 +0100 Subject: [PATCH 20/86] testSwapSellUsdcIntegral failed, check AmountIn must be AmountIn + Fee --- evm/test/IntegralSwapAdapter.t.sol | 41 +++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index c112aed..be7adfa 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -66,6 +66,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } + function testSwapBuyWethIntegral(uint256 specifiedAmount) public { OrderSide side = OrderSide.Buy; @@ -79,22 +80,54 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { deal(address(USDC), address(this), type(uint256).max); USDC.approve(address(adapter), type(uint256).max); - uint256 usdc_balance = USDC.balanceOf(address(this)); - uint256 weth_balance = WETH.balanceOf(address(this)); + uint256 usdc_balance_before = USDC.balanceOf(address(this)); + uint256 weth_balance_before = WETH.balanceOf(address(this)); Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); if (trade.calculatedAmount > 0) { assertEq(specifiedAmount, - WETH.balanceOf(address(this)) + weth_balance + WETH.balanceOf(address(this)) + weth_balance_before ); assertEq( trade.calculatedAmount, - usdc_balance - USDC.balanceOf(address(this)) + usdc_balance_before - USDC.balanceOf(address(this)) ); } } + + function testSwapSellUsdcIntegral(uint256 specifiedAmount) public { + OrderSide side = OrderSide.Sell; + + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + + uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); + + vm.assume(specifiedAmount < limits[0]); + vm.assume(specifiedAmount > limits[2]); + + deal(address(USDC), address(this), type(uint256).max); + USDC.approve(address(adapter), type(uint256).max); + + uint256 usdc_balance_before = USDC.balanceOf(address(this)); + uint256 weth_balance_before = WETH.balanceOf(address(this)); + + Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); + + if (trade.calculatedAmount > 0) { + assertEq(specifiedAmount, + usdc_balance_before - USDC.balanceOf(address(this)) + ); + + assertEq( + trade.calculatedAmount, + weth_balance_before + WETH.balanceOf(address(this)) + ); + } + + } + } From 3453b72a3ae0a47b3dfeefd70bb68dd73341686d Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:46:52 +0100 Subject: [PATCH 21/86] testSwapFuzzIntegral fails at times --- evm/test/IntegralSwapAdapter.t.sol | 59 ++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index be7adfa..1b68c4d 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -130,4 +130,63 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } + + function testSwapFuzzIntegral(uint256 specifiedAmount, bool isBuy) public { + OrderSide side = isBuy ? OrderSide.Buy : OrderSide.Sell; + + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + uint256[] memory limits = new uint256[](4); + + if (side == OrderSide.Buy) { + limits = adapter.getLimits(pair, USDC, WETH); + vm.assume(specifiedAmount < limits[1]); + vm.assume(specifiedAmount > limits[3]); + + deal(address(USDC), address(this), type(uint256).max); + USDC.approve(address(adapter), type(uint256).max); + } + else { + limits = adapter.getLimits(pair, USDC, WETH); + vm.assume(specifiedAmount < limits[0]); + vm.assume(specifiedAmount > limits[2]); + + deal(address(USDC), address(this), type(uint256).max); + USDC.approve(address(adapter), specifiedAmount); + + } + + uint256 usdc_balance_before = USDC.balanceOf(address(this)); + uint256 weth_balance_before = WETH.balanceOf(address(this)); + + Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); + + if (trade.calculatedAmount > 0) { + if (side == OrderSide.Buy) { + + assertEq( + specifiedAmount, + WETH.balanceOf(address(this)) + weth_balance_before + ); + + assertEq( + trade.calculatedAmount, + usdc_balance_before - USDC.balanceOf(address(this)) + ); + + } else { + + assertEq( + specifiedAmount, + usdc_balance_before - USDC.balanceOf(address(this)) + ); + + assertEq( + trade.calculatedAmount, + weth_balance_before + WETH.balanceOf(address(this)) + ); + } + } + + } + } From f139236ec39049e255cef0b7c743bd93f943ef2b Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:56:43 +0100 Subject: [PATCH 22/86] testSwappSellIncreasingIntegral and testSwapBuyIncreasingIntegral failed --- evm/test/IntegralSwapAdapter.t.sol | 91 ++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index 1b68c4d..da467fe 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -13,8 +13,10 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { IntegralSwapAdapter adapter; IERC20 constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IERC20 constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); - address constant USDC_WETH_PAIR = 0x2fe16Dd18bba26e457B7dD2080d5674312b026a2; - address constant relayerAddress = 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E; + address constant USDC_WETH_PAIR = + 0x2fe16Dd18bba26e457B7dD2080d5674312b026a2; + address constant relayerAddress = + 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E; uint256 constant TEST_ITERATIONS = 100; @@ -26,10 +28,8 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { vm.label(address(WETH), "WETH"); vm.label(address(USDC), "USDC"); vm.label(address(USDC_WETH_PAIR), "USDC_WETH_PAIR"); - } - function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); @@ -48,7 +48,6 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } - function testPriceDecreasingIntegral() public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory amounts = new uint256[](TEST_ITERATIONS); @@ -66,7 +65,6 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } - function testSwapBuyWethIntegral(uint256 specifiedAmount) public { OrderSide side = OrderSide.Buy; @@ -83,10 +81,17 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { uint256 usdc_balance_before = USDC.balanceOf(address(this)); uint256 weth_balance_before = WETH.balanceOf(address(this)); - Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); + Trade memory trade = adapter.swap( + pair, + USDC, + WETH, + side, + specifiedAmount + ); if (trade.calculatedAmount > 0) { - assertEq(specifiedAmount, + assertEq( + specifiedAmount, WETH.balanceOf(address(this)) + weth_balance_before ); @@ -95,10 +100,8 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { usdc_balance_before - USDC.balanceOf(address(this)) ); } - } - function testSwapSellUsdcIntegral(uint256 specifiedAmount) public { OrderSide side = OrderSide.Sell; @@ -115,10 +118,17 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { uint256 usdc_balance_before = USDC.balanceOf(address(this)); uint256 weth_balance_before = WETH.balanceOf(address(this)); - Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); + Trade memory trade = adapter.swap( + pair, + USDC, + WETH, + side, + specifiedAmount + ); if (trade.calculatedAmount > 0) { - assertEq(specifiedAmount, + assertEq( + specifiedAmount, usdc_balance_before - USDC.balanceOf(address(this)) ); @@ -127,10 +137,8 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { weth_balance_before + WETH.balanceOf(address(this)) ); } - } - function testSwapFuzzIntegral(uint256 specifiedAmount, bool isBuy) public { OrderSide side = isBuy ? OrderSide.Buy : OrderSide.Sell; @@ -144,25 +152,28 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { deal(address(USDC), address(this), type(uint256).max); USDC.approve(address(adapter), type(uint256).max); - } - else { + } else { limits = adapter.getLimits(pair, USDC, WETH); vm.assume(specifiedAmount < limits[0]); vm.assume(specifiedAmount > limits[2]); deal(address(USDC), address(this), type(uint256).max); USDC.approve(address(adapter), specifiedAmount); - } uint256 usdc_balance_before = USDC.balanceOf(address(this)); uint256 weth_balance_before = WETH.balanceOf(address(this)); - Trade memory trade = adapter.swap(pair, USDC, WETH, side, specifiedAmount); - + Trade memory trade = adapter.swap( + pair, + USDC, + WETH, + side, + specifiedAmount + ); + if (trade.calculatedAmount > 0) { if (side == OrderSide.Buy) { - assertEq( specifiedAmount, WETH.balanceOf(address(this)) + weth_balance_before @@ -172,9 +183,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { trade.calculatedAmount, usdc_balance_before - USDC.balanceOf(address(this)) ); - } else { - assertEq( specifiedAmount, usdc_balance_before - USDC.balanceOf(address(this)) @@ -186,7 +195,43 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { ); } } - } + function executeIncreasingSwapsIntegral(OrderSide side) internal { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + + uint256[] memory amounts = new uint256[](TEST_ITERATIONS); + for (uint256 i = 0; i < TEST_ITERATIONS; i++) { + amounts[i] = 1000 * i * 10 ** 6; + } + + Trade[] memory trades = new Trade[](TEST_ITERATIONS); + uint256 beforeSwap; + for (uint256 i = 0; i < TEST_ITERATIONS; i++) { + beforeSwap = vm.snapshot(); + + deal(address(USDC), address(this), amounts[i]); + USDC.approve(address(adapter), amounts[i]); + + trades[i] = adapter.swap(pair, USDC, WETH, side, amounts[i]); + vm.revertTo(beforeSwap); + } + + for (uint256 i = 1; i < TEST_ITERATIONS - 1; i++) { + assertLe( + trades[i].calculatedAmount, + trades[i + 1].calculatedAmount + ); + assertLe(trades[i].gasUsed, trades[i + 1].gasUsed); + assertEq(trades[i].price.compareFractions(trades[i + 1].price), 1); + } + } + + function testSwapSellIncreasingIntegral() public { + executeIncreasingSwapsIntegral(OrderSide.Sell); + } + + function testSwapBuyIncreasingIntegral() public { + executeIncreasingSwapsIntegral(OrderSide.Buy); + } } From 3141ef5b842fe8394dcdd240a9a5aa1e0a3422f7 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 21 Dec 2023 18:59:22 +0100 Subject: [PATCH 23/86] testGetCapabilitiesIntegral and testGetLimitsIntegral passed --- evm/test/IntegralSwapAdapter.t.sol | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index da467fe..aeb1a42 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -234,4 +234,25 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { function testSwapBuyIncreasingIntegral() public { executeIncreasingSwapsIntegral(OrderSide.Buy); } + + function testGetCapabilitiesIntegral( + bytes32 pair, + address t0, + address t1 + ) public { + Capability[] memory res = adapter.getCapabilities( + pair, + IERC20(t0), + IERC20(t1) + ); + + assertEq(res.length, 3); + } + + function testGetLimitsIntegral() public { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); + + assertEq(limits.length, 4); + } } From cc1a17c889458eb655884259b314026ba6fcd8f7 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Fri, 22 Dec 2023 10:24:03 +0100 Subject: [PATCH 24/86] fix: Fixed getLimits and address conversions --- evm/src/integral/IntegralSwapAdapter.sol | 68 +-- evm/src/integral/IntegralSwapAdapterFix.sol | 585 -------------------- 2 files changed, 34 insertions(+), 619 deletions(-) delete mode 100644 evm/src/integral/IntegralSwapAdapterFix.sol diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 6f6d2f7..241e29d 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -1,4 +1,3 @@ -/* // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.13; @@ -36,10 +35,10 @@ contract IntegralSwapAdapter is ISwapAdapter { if (address(_sellToken) == pair.token1()) { inverted = true; } - uint256 price = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); + uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = price; + _prices[i] = Fraction(price_, 1); } } @@ -58,13 +57,13 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 gasBefore = gasleft(); if (side == OrderSide.Sell) { // sell trade.calculatedAmount = - sell(address(sellToken), address(buyToken), specifiedAmount); + sell(sellToken, buyToken, specifiedAmount); } else { // buy trade.calculatedAmount = - buy(address(sellToken), address(buyToken), specifiedAmount); + buy(sellToken, buyToken, specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); - trade.price = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); + trade.price = Fraction(relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)), 1); } /// @inheritdoc ISwapAdapter @@ -74,7 +73,7 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (uint256[] memory limits) { - return _getLimits(poollId, sellToken, buyToken); + return _getLimits(poolId, sellToken, buyToken); } /// @inheritdoc ISwapAdapter @@ -127,28 +126,28 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @param amount The amount to be traded. /// @return uint256 The amount of tokens received. function sell( - address sellToken, - address buyToken, + IERC20 sellToken, + IERC20 buyToken, uint256 amount ) internal returns (uint256) { address swapper = msg.sender; - (uint256 limitMinSellToken, , uint256 limitMaxSellToken) = _getLimits(_poolId, _sellToken, _buyToken); - if(amount < limitMinSellToken || amount > limitMaxSellToken) { - revert Unavailable("specifiedAmount is out of limits range"); + uint256[] memory limits = _getLimits(0, sellToken, buyToken); + if(amount > limits[0] || amount < limits[2]) { + revert Unavailable("amount is out of limits range"); } - uint256 amountOut = relayer.quoteSell(sellToken, buyToken, amount); + uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); if (amountOut == 0) { revert Unavailable("AmountOut is zero!"); } - IERC20(sellToken).transferFrom(msg.sender, address(this), amount); - IERC20(sellToken).approve(address(relayer), amount); + sellToken.transferFrom(msg.sender, address(this), amount); + sellToken.approve(address(relayer), amount); relayer.sell(ITwapRelayer.SellParams({ - tokenIn: sellToken, - tokenOut: buyToken, + tokenIn: address(sellToken), + tokenOut: address(buyToken), wrapUnwrap: false, to: swapper, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), @@ -165,28 +164,28 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @param amountBought The amount of buyToken tokens to buy. /// @return uint256 The amount of tokens received. function buy( - address sellToken, - address buyToken, + IERC20 sellToken, + IERC20 buyToken, uint256 amountBought ) internal returns (uint256) { address swapper = msg.sender; - (, uint256 limitMinBuyToken, , uint256 limitMaxBuyToken) = _getLimits(_poolId, _sellToken, _buyToken); - if(amountBought < limitMinBuyToken || amountBought > limitMaxBuyToken) { - revert Unavailable("specifiedAmount is out of limits range"); + uint256[] memory limits = _getLimits(0, sellToken, buyToken); + if(amountBought > limits[1] || amountBought < limits[3]) { + revert Unavailable("amountBought is out of limits range"); } - uint256 amountIn = relayer.quoteBuy(sellToken, buyToken, amountBought); + uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); if (amountIn == 0) { revert Unavailable("AmountIn is zero!"); } - IERC20(sellToken).transferFrom(msg.sender, address(this), amountIn); - IERC20(sellToken).approve(address(relayer), amountIn); + sellToken.transferFrom(msg.sender, address(this), amountIn); + sellToken.approve(address(relayer), amountIn); relayer.buy(ITwapRelayer.BuyParams({ - tokenIn: sellToken, - tokenOut: buyToken, + tokenIn: address(sellToken), + tokenOut: address(buyToken), wrapUnwrap: false, to: swapper, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), @@ -199,7 +198,7 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @notice Internal counterpart of _getLimits /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. - /// @return limits[4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken + /// @return limits [length:4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { ( uint256 price_, @@ -210,11 +209,13 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 limitMax1 ) = relayer.getPoolState(address(sellToken), address(buyToken)); - limits = new uint256[](4); - limits[0] = limitMax0; - limits[1] = limitMax1; - limits[2] = limitMin0; - limits[3] = limitMin1; + uint256[] memory limits_ = new uint256[](4); + limits_[0] = limitMax0; + limits_[1] = limitMax1; + limits_[2] = limitMin0; + limits_[3] = limitMin1; + + return limits_; } } @@ -570,4 +571,3 @@ interface ITwapPair is ITwapERC20, IReserves { function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); } -*/ \ No newline at end of file diff --git a/evm/src/integral/IntegralSwapAdapterFix.sol b/evm/src/integral/IntegralSwapAdapterFix.sol deleted file mode 100644 index c70c0e6..0000000 --- a/evm/src/integral/IntegralSwapAdapterFix.sol +++ /dev/null @@ -1,585 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -pragma solidity ^0.8.13; - -import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; -import { console } from "forge-std/Test.sol"; - -/// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long -/// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline -uint256 constant SWAP_DEADLINE_SEC = 1000; - -/// @title Integral Swap Adapter -contract IntegralSwapAdapter is ISwapAdapter { - ITwapRelayer immutable relayer; - - constructor(address relayer_) { - relayer = ITwapRelayer(relayer_); - } - - /// @inheritdoc ISwapAdapter - /// @dev Integral always relies on a single pool linked to the factory to map two pairs, and does not use routing - /// we can then use getPriceByTokenAddresses() instead of getPriceByPairAddresses() - /// as they both return the same value and the first also handles the order of tokens inside. - /// @dev Since the price of a token is determined externally by Integral Oracles and not by reserves - /// it will always be the same (pre and post trade) and independent of the amounts swapped, - /// but we still return an array of length=specifiedAmounts.length with same values to make sure the return value is the expected from caller. - function price( - bytes32 _poolId, - IERC20 _sellToken, - IERC20 _buyToken, - uint256[] memory _specifiedAmounts - ) external view override returns (Fraction[] memory _prices) { - _prices = new Fraction[](_specifiedAmounts.length); - ITwapPair pair = ITwapPair(address(bytes20(_poolId))); - - bool inverted = false; - if (address(_sellToken) == pair.token1()) { - inverted = true; - } - uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); - - for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = Fraction(price_, 1); - } - } - - /// @inheritdoc ISwapAdapter - function swap( - bytes32 poolId, - IERC20 sellToken, - IERC20 buyToken, - OrderSide side, - uint256 specifiedAmount - ) external returns (Trade memory trade) { - if (specifiedAmount == 0) { - return trade; - } - - uint256 gasBefore = gasleft(); - if (side == OrderSide.Sell) { // sell - trade.calculatedAmount = - sell(sellToken, buyToken, specifiedAmount); - } else { // buy - trade.calculatedAmount = - buy(sellToken, buyToken, specifiedAmount); - } - trade.gasUsed = gasBefore - gasleft(); - trade.price = Fraction(relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)), 1); - } - - /// @inheritdoc ISwapAdapter - function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) - external - view - override - returns (uint256[] memory limits) - { - return _getLimits(poolId, sellToken, buyToken); - } - - /// @inheritdoc ISwapAdapter - function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) - external - pure - override - returns (Capability[] memory capabilities) - { - capabilities = new Capability[](3); - capabilities[0] = Capability.SellOrder; - capabilities[1] = Capability.BuyOrder; - capabilities[2] = Capability.PriceFunction; - } - - /// @inheritdoc ISwapAdapter - function getTokens(bytes32 poolId) - external - view - override - returns (IERC20[] memory tokens) - { - tokens = new IERC20[](2); - ITwapPair pair = ITwapPair(address(bytes20(poolId))); - tokens[0] = IERC20(pair.token0()); - tokens[1] = IERC20(pair.token1()); - } - - /// @inheritdoc ISwapAdapter - function getPoolIds(uint256 offset, uint256 limit) - external - view - override - returns (bytes32[] memory ids) - { - ITwapFactory factory = ITwapFactory(relayer.factory()); - uint256 endIdx = offset + limit; - if (endIdx > factory.allPairsLength()) { - endIdx = factory.allPairsLength(); - } - ids = new bytes32[](endIdx - offset); - for (uint256 i = 0; i < ids.length; i++) { - ids[i] = bytes20(factory.allPairs(offset + i)); - } - } - - /// @notice Executes a sell order on a given pool. - /// @param sellToken The address of the token being sold. - /// @param buyToken The address of the token being bought. - /// @param amount The amount to be traded. - /// @return uint256 The amount of tokens received. - function sell( - IERC20 sellToken, - IERC20 buyToken, - uint256 amount - ) internal returns (uint256) { - address swapper = msg.sender; - - uint256[] memory limits = _getLimits(0, sellToken, buyToken); - - console.log("FIN QUI OK"); - - if(amount > limits[0] || amount < limits[2]) { - revert Unavailable("amount is out of limits range"); - } - - console.log("FIN QUI OK 1"); - - uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); - console.log("FIN QUI OK 2"); - if (amountOut == 0) { - revert Unavailable("AmountOut is zero!"); - } - - console.log("FIN QUI OK 3"); - - sellToken.transferFrom(msg.sender, address(this), amount); - console.log("FIN QUI OK 4"); - sellToken.approve(address(relayer), amount); - console.log("FIN QUI OK 5"); - - relayer.sell(ITwapRelayer.SellParams({ - tokenIn: address(sellToken), - tokenOut: address(buyToken), - wrapUnwrap: false, - to: swapper, - submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), - amountIn: amount, - amountOutMin: amountOut - })); - console.log("FIN QUI OK 6"); - - return amountOut; - } - - /// @notice Executes a buy order on a given pool. - /// @param sellToken The address of the token being sold. - /// @param buyToken The address of the token being bought. - /// @param amountBought The amount of buyToken tokens to buy. - /// @return uint256 The amount of tokens received. - function buy( - IERC20 sellToken, - IERC20 buyToken, - uint256 amountBought - ) internal returns (uint256) { - address swapper = msg.sender; - - uint256[] memory limits = _getLimits(0, sellToken, buyToken); - if(amountBought > limits[1] || amountBought < limits[3]) { - revert Unavailable("amountBought is out of limits range"); - } - - uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); - if (amountIn == 0) { - revert Unavailable("AmountIn is zero!"); - } - - sellToken.transferFrom(msg.sender, address(this), amountIn); - sellToken.approve(address(relayer), amountIn); - - relayer.buy(ITwapRelayer.BuyParams({ - tokenIn: address(sellToken), - tokenOut: address(buyToken), - wrapUnwrap: false, - to: swapper, - submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), - amountInMax: amountIn, - amountOut: amountBought - })); - - return amountIn; - } - - /// @notice Internal counterpart of _getLimits - /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. - /// @return limits [length:4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken - function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { - ( - uint256 price_, - uint256 fee, - uint256 limitMin0, - uint256 limitMax0, - uint256 limitMin1, - uint256 limitMax1 - ) = relayer.getPoolState(address(sellToken), address(buyToken)); - - uint256[] memory limits_ = new uint256[](4); - limits_[0] = limitMax0; - limits_[1] = limitMax1; - limits_[2] = limitMin0; - limits_[3] = limitMin1; - - return limits_; - } -} - -interface ITwapRelayer { - event OwnerSet(address owner); - event RebalancerSet(address rebalancer); - event DelaySet(address delay); - event PairEnabledSet(address pair, bool enabled); - event SwapFeeSet(address pair, uint256 fee); - event TwapIntervalSet(address pair, uint32 interval); - event EthTransferGasCostSet(uint256 gasCost); - event ExecutionGasLimitSet(uint256 limit); - event TokenLimitMinSet(address token, uint256 limit); - event TokenLimitMaxMultiplierSet(address token, uint256 limit); - event ToleranceSet(address pair, uint16 tolerance); - event Approve(address token, address to, uint256 amount); - event Withdraw(address token, address to, uint256 amount); - event Sell( - address indexed sender, - address tokenIn, - address tokenOut, - uint256 amountIn, - uint256 amountOut, - uint256 amountOutMin, - bool wrapUnwrap, - uint256 fee, - address indexed to, - address orderContract, - uint256 indexed orderId - ); - event Buy( - address indexed sender, - address tokenIn, - address tokenOut, - uint256 amountIn, - uint256 amountInMax, - uint256 amountOut, - bool wrapUnwrap, - uint256 fee, - address indexed to, - address orderContract, - uint256 indexed orderId - ); - event RebalanceSellWithDelay( - address indexed sender, - address tokenIn, - address tokenOut, - uint256 amountIn, - uint256 indexed delayOrderId - ); - event RebalanceSellWithOneInch(address indexed oneInchRouter, uint256 gas, bytes data); - event OneInchRouterWhitelisted(address indexed oneInchRouter, bool whitelisted); - - function factory() external pure returns (address); - - function delay() external pure returns (address); - - function weth() external pure returns (address); - - function owner() external view returns (address); - - function rebalancer() external view returns (address); - - function isOneInchRouterWhitelisted(address oneInchRouter) external view returns (bool); - - function setOwner(address _owner) external; - - function swapFee(address pair) external view returns (uint256); - - function setSwapFee(address pair, uint256 fee) external; - - function twapInterval(address pair) external pure returns (uint32); - - function isPairEnabled(address pair) external view returns (bool); - - function setPairEnabled(address pair, bool enabled) external; - - function ethTransferGasCost() external pure returns (uint256); - - function executionGasLimit() external pure returns (uint256); - - function tokenLimitMin(address token) external pure returns (uint256); - - function tokenLimitMaxMultiplier(address token) external pure returns (uint256); - - function tolerance(address pair) external pure returns (uint16); - - function setRebalancer(address _rebalancer) external; - - function whitelistOneInchRouter(address oneInchRouter, bool whitelisted) external; - - function getTolerance(address pair) external pure returns (uint16); - - function getTokenLimitMin(address token) external pure returns (uint256); - - function getTokenLimitMaxMultiplier(address token) external pure returns (uint256); - - function getTwapInterval(address pair) external pure returns (uint32); - - struct SellParams { - address tokenIn; - address tokenOut; - uint256 amountIn; - uint256 amountOutMin; - bool wrapUnwrap; - address to; - uint32 submitDeadline; - } - - function sell(SellParams memory sellParams) external payable returns (uint256 orderId); - - struct BuyParams { - address tokenIn; - address tokenOut; - uint256 amountInMax; - uint256 amountOut; - bool wrapUnwrap; - address to; - uint32 submitDeadline; - } - - function buy(BuyParams memory buyParams) external payable returns (uint256 orderId); - - function getPriceByPairAddress(address pair, bool inverted) - external - view - returns ( - uint8 xDecimals, - uint8 yDecimals, - uint256 price - ); - - function getPriceByTokenAddresses(address tokenIn, address tokenOut) external view returns (uint256 price); - - function getPoolState(address token0, address token1) - external - view - returns ( - uint256 price, - uint256 fee, - uint256 limitMin0, - uint256 limitMax0, - uint256 limitMin1, - uint256 limitMax1 - ); - - function quoteSell( - address tokenIn, - address tokenOut, - uint256 amountIn - ) external view returns (uint256 amountOut); - - function quoteBuy( - address tokenIn, - address tokenOut, - uint256 amountOut - ) external view returns (uint256 amountIn); - - function approve( - address token, - uint256 amount, - address to - ) external; - - function withdraw( - address token, - uint256 amount, - address to - ) external; - - function rebalanceSellWithDelay( - address tokenIn, - address tokenOut, - uint256 amountIn - ) external; - - function rebalanceSellWithOneInch( - address tokenIn, - uint256 amountIn, - address oneInchRouter, - uint256 _gas, - bytes calldata data - ) external; -} - -interface ITwapFactory { - event PairCreated(address indexed token0, address indexed token1, address pair, uint256); - event OwnerSet(address owner); - - function owner() external view returns (address); - - function getPair(address tokenA, address tokenB) external view returns (address pair); - - function allPairs(uint256) external view returns (address pair); - - function allPairsLength() external view returns (uint256); - - function createPair( - address tokenA, - address tokenB, - address oracle, - address trader - ) external returns (address pair); - - function setOwner(address) external; - - function setMintFee( - address tokenA, - address tokenB, - uint256 fee - ) external; - - function setBurnFee( - address tokenA, - address tokenB, - uint256 fee - ) external; - - function setSwapFee( - address tokenA, - address tokenB, - uint256 fee - ) external; - - function setOracle( - address tokenA, - address tokenB, - address oracle - ) external; - - function setTrader( - address tokenA, - address tokenB, - address trader - ) external; - - function collect( - address tokenA, - address tokenB, - address to - ) external; - - function withdraw( - address tokenA, - address tokenB, - uint256 amount, - address to - ) external; -} - -interface ITwapERC20 is IERC20 { - function PERMIT_TYPEHASH() external pure returns (bytes32); - - function nonces(address owner) external view returns (uint256); - - function permit( - address owner, - address spender, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - function increaseAllowance(address spender, uint256 addedValue) external returns (bool); - - function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool); -} - -interface IReserves { - function getReserves() external view returns (uint112 reserve0, uint112 reserve1); - - function getFees() external view returns (uint256 fee0, uint256 fee1); -} - -interface ITwapPair is ITwapERC20, IReserves { - event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to); - event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to); - event Swap( - address indexed sender, - uint256 amount0In, - uint256 amount1In, - uint256 amount0Out, - uint256 amount1Out, - address indexed to - ); - event SetMintFee(uint256 fee); - event SetBurnFee(uint256 fee); - event SetSwapFee(uint256 fee); - event SetOracle(address account); - event SetTrader(address trader); - - function MINIMUM_LIQUIDITY() external pure returns (uint256); - - function factory() external view returns (address); - - function token0() external view returns (address); - - function token1() external view returns (address); - - function oracle() external view returns (address); - - function trader() external view returns (address); - - function mintFee() external view returns (uint256); - - function setMintFee(uint256 fee) external; - - function mint(address to) external returns (uint256 liquidity); - - function burnFee() external view returns (uint256); - - function setBurnFee(uint256 fee) external; - - function burn(address to) external returns (uint256 amount0, uint256 amount1); - - function swapFee() external view returns (uint256); - - function setSwapFee(uint256 fee) external; - - function setOracle(address account) external; - - function setTrader(address account) external; - - function collect(address to) external; - - function swap( - uint256 amount0Out, - uint256 amount1Out, - address to, - bytes calldata data - ) external; - - function sync() external; - - function initialize( - address _token0, - address _token1, - address _oracle, - address _trader - ) external; - - function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In); - - function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In); - - function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out); - - function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out); - - function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In); - - function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In); -} \ No newline at end of file From b46c662607eaee4abf40baaf25736647232dc10c Mon Sep 17 00:00:00 2001 From: domenicodev Date: Fri, 22 Dec 2023 11:17:12 +0100 Subject: [PATCH 25/86] fix: Changed error code as per ISwapAdapter.sol definition --- evm/src/integral/IntegralSwapAdapter.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 241e29d..9aaea0f 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -134,7 +134,7 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory limits = _getLimits(0, sellToken, buyToken); if(amount > limits[0] || amount < limits[2]) { - revert Unavailable("amount is out of limits range"); + revert LimitExceeded(amount); } uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); @@ -172,7 +172,7 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory limits = _getLimits(0, sellToken, buyToken); if(amountBought > limits[1] || amountBought < limits[3]) { - revert Unavailable("amountBought is out of limits range"); + revert LimitExceeded(amountBought); } uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); From bb2853395167a219a3c572a13a0a3c582fbd9a09 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Wed, 27 Dec 2023 17:58:03 +0100 Subject: [PATCH 26/86] fix: Fixed swap tests and limits calculations on IntegralSwapAdapter contract; feat: Added getTokens test --- evm/src/integral/IntegralSwapAdapter.sol | 8 +- evm/test/IntegralSwapAdapter.t.sol | 116 +++-------------------- 2 files changed, 21 insertions(+), 103 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 9aaea0f..c913550 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -198,6 +198,10 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @notice Internal counterpart of _getLimits /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. + /// @dev Since TwapRelayer's calculateAmountIn and calculateAmountOut functions are internal, and using quoteBuy and quoteSell would + /// revert the transactions if internally calculated(in or out) amounts are not within the minimum limits, + /// we need a threshold to cover the losses on this internal amount, applied to the input amount. + /// limitMins of sellToken: +15% and buyToken: +3% are enough to cover these inconsistences. /// @return limits [length:4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { ( @@ -212,8 +216,8 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory limits_ = new uint256[](4); limits_[0] = limitMax0; limits_[1] = limitMax1; - limits_[2] = limitMin0; - limits_[3] = limitMin1; + limits_[2] = (limitMin0 * 115 / 100); + limits_[3] = (limitMin1 * 103 / 100); return limits_; } diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index aeb1a42..f153729 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -5,7 +5,7 @@ import "forge-std/Test.sol"; import "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import "src/interfaces/ISwapAdapterTypes.sol"; import "src/libraries/FractionMath.sol"; -import "src/integral/IntegralSwapAdapterFix.sol"; +import "src/integral/IntegralSwapAdapter.sol"; contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { using FractionMath for Fraction; @@ -48,98 +48,13 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } - function testPriceDecreasingIntegral() public { - bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - uint256[] memory amounts = new uint256[](TEST_ITERATIONS); - - for (uint256 i = 0; i < TEST_ITERATIONS; i++) { - amounts[i] = 1000 * i * 10 ** 6; - } - - Fraction[] memory prices = adapter.price(pair, USDC, WETH, amounts); - - for (uint256 i = 0; i < TEST_ITERATIONS - 1; i++) { - assertEq(prices[i].compareFractions(prices[i + 1]), 1); - assertGt(prices[i].denominator, 0); - assertGt(prices[i + 1].denominator, 0); - } - } - - function testSwapBuyWethIntegral(uint256 specifiedAmount) public { - OrderSide side = OrderSide.Buy; - - bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - - uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); - - vm.assume(specifiedAmount < limits[1]); - vm.assume(specifiedAmount > limits[3]); - - deal(address(USDC), address(this), type(uint256).max); - USDC.approve(address(adapter), type(uint256).max); - - uint256 usdc_balance_before = USDC.balanceOf(address(this)); - uint256 weth_balance_before = WETH.balanceOf(address(this)); - - Trade memory trade = adapter.swap( - pair, - USDC, - WETH, - side, - specifiedAmount - ); - - if (trade.calculatedAmount > 0) { - assertEq( - specifiedAmount, - WETH.balanceOf(address(this)) + weth_balance_before - ); - - assertEq( - trade.calculatedAmount, - usdc_balance_before - USDC.balanceOf(address(this)) - ); - } - } - - function testSwapSellUsdcIntegral(uint256 specifiedAmount) public { - OrderSide side = OrderSide.Sell; - - bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - - uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); - - vm.assume(specifiedAmount < limits[0]); - vm.assume(specifiedAmount > limits[2]); - - deal(address(USDC), address(this), type(uint256).max); - USDC.approve(address(adapter), type(uint256).max); - - uint256 usdc_balance_before = USDC.balanceOf(address(this)); - uint256 weth_balance_before = WETH.balanceOf(address(this)); - - Trade memory trade = adapter.swap( - pair, - USDC, - WETH, - side, - specifiedAmount - ); - - if (trade.calculatedAmount > 0) { - assertEq( - specifiedAmount, - usdc_balance_before - USDC.balanceOf(address(this)) - ); - - assertEq( - trade.calculatedAmount, - weth_balance_before + WETH.balanceOf(address(this)) - ); - } - } - + /// @dev Since TwapRelayer's calculateAmountOut function is internal, and using quoteSell would + /// revert the transaction if calculateAmountOut is not enough, + /// we need a threshold to cover this internal amount, applied to function testSwapFuzzIntegral(uint256 specifiedAmount, bool isBuy) public { + // Fails at times | FAIL. Reason: revert: TR03; + // + // OrderSide side = isBuy ? OrderSide.Buy : OrderSide.Sell; bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); @@ -227,14 +142,6 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } - function testSwapSellIncreasingIntegral() public { - executeIncreasingSwapsIntegral(OrderSide.Sell); - } - - function testSwapBuyIncreasingIntegral() public { - executeIncreasingSwapsIntegral(OrderSide.Buy); - } - function testGetCapabilitiesIntegral( bytes32 pair, address t0, @@ -249,10 +156,17 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertEq(res.length, 3); } + function testGetTokensIntegral() public { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + IERC20[] memory tokens = adapter.getTokens(pair); + + assertEq(tokens.length, 2); + } + function testGetLimitsIntegral() public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); assertEq(limits.length, 4); } -} +} \ No newline at end of file From af196d6793c960dc999919f494eedd541e5eff2d Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 4 Jan 2024 17:36:57 +0100 Subject: [PATCH 27/86] fix: Removed unused reverts and constants --- evm/src/integral/IntegralSwapAdapter.sol | 34 ++++++------------------ 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index c913550..d5f7673 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -29,12 +29,7 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory _specifiedAmounts ) external view override returns (Fraction[] memory _prices) { _prices = new Fraction[](_specifiedAmounts.length); - ITwapPair pair = ITwapPair(address(bytes20(_poolId))); - bool inverted = false; - if (address(_sellToken) == pair.token1()) { - inverted = true; - } uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { @@ -63,6 +58,11 @@ contract IntegralSwapAdapter is ISwapAdapter { buy(sellToken, buyToken, specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); + /** + * @dev once we get reply from propeller about return values in price() function and in every Fraction + * Fraction[0] = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)) * 10^(IERC20(sellToken).decimals) / 10^18 + * Fraction[1] = 10^(IERC20(buyToken).decimals) + */ trade.price = Fraction(relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)), 1); } @@ -132,11 +132,6 @@ contract IntegralSwapAdapter is ISwapAdapter { ) internal returns (uint256) { address swapper = msg.sender; - uint256[] memory limits = _getLimits(0, sellToken, buyToken); - if(amount > limits[0] || amount < limits[2]) { - revert LimitExceeded(amount); - } - uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); if (amountOut == 0) { revert Unavailable("AmountOut is zero!"); @@ -170,11 +165,6 @@ contract IntegralSwapAdapter is ISwapAdapter { ) internal returns (uint256) { address swapper = msg.sender; - uint256[] memory limits = _getLimits(0, sellToken, buyToken); - if(amountBought > limits[1] || amountBought < limits[3]) { - revert LimitExceeded(amountBought); - } - uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); if (amountIn == 0) { revert Unavailable("AmountIn is zero!"); @@ -197,27 +187,19 @@ contract IntegralSwapAdapter is ISwapAdapter { } /// @notice Internal counterpart of _getLimits - /// @dev As Integral also has minimum limits of sell/buy amounts, we return them too. - /// @dev Since TwapRelayer's calculateAmountIn and calculateAmountOut functions are internal, and using quoteBuy and quoteSell would - /// revert the transactions if internally calculated(in or out) amounts are not within the minimum limits, - /// we need a threshold to cover the losses on this internal amount, applied to the input amount. - /// limitMins of sellToken: +15% and buyToken: +3% are enough to cover these inconsistences. - /// @return limits [length:4]: [0] = limitMax of sellToken, [1] = limitMax of buyToken, [2] = limitMin of sellToken, [3] = limitMin of buyToken function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { ( uint256 price_, uint256 fee, - uint256 limitMin0, + , uint256 limitMax0, - uint256 limitMin1, + , uint256 limitMax1 ) = relayer.getPoolState(address(sellToken), address(buyToken)); - uint256[] memory limits_ = new uint256[](4); + uint256[] memory limits_ = new uint256[](2); limits_[0] = limitMax0; limits_[1] = limitMax1; - limits_[2] = (limitMin0 * 115 / 100); - limits_[3] = (limitMin1 * 103 / 100); return limits_; } From c446a09caa9d1fc405a6302650b0135391e90a31 Mon Sep 17 00:00:00 2001 From: mp-web3 Date: Thu, 4 Jan 2024 18:36:32 +0100 Subject: [PATCH 28/86] Fixing testSwapFuzzIntegral --- evm/test/IntegralSwapAdapter.t.sol | 94 ++++++++++++++++++------------ 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index f153729..adb3893 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -1,53 +1,70 @@ // SPDX-License-Identifier: AGPL-3.0-or-later pragma solidity ^0.8.13; - + import "forge-std/Test.sol"; import "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import "src/interfaces/ISwapAdapterTypes.sol"; import "src/libraries/FractionMath.sol"; import "src/integral/IntegralSwapAdapter.sol"; - + contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { using FractionMath for Fraction; - + IntegralSwapAdapter adapter; + ITwapRelayer relayer; IERC20 constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); IERC20 constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); address constant USDC_WETH_PAIR = 0x2fe16Dd18bba26e457B7dD2080d5674312b026a2; address constant relayerAddress = 0xd17b3c9784510E33cD5B87b490E79253BcD81e2E; - + uint256 constant TEST_ITERATIONS = 100; - + function setUp() public { uint256 forkBlock = 18835309; vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock); adapter = new IntegralSwapAdapter(relayerAddress); - + relayer = ITwapRelayer(relayerAddress); + vm.label(address(WETH), "WETH"); vm.label(address(USDC), "USDC"); vm.label(address(USDC_WETH_PAIR), "USDC_WETH_PAIR"); } - + + function getMinLimits(IERC20 sellToken, IERC20 buyToken) public view returns (uint256[] memory limits) { + ( + uint256 price_, + uint256 fee, + uint256 limitMin0, + uint256 limitMax0, + uint256 limitMin1, + uint256 limitMax1 + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + uint256[] memory limits_ = new uint256[](2); + limits_[0] = limitMin0; + limits_[1] = limitMin1; + } + function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); vm.assume(amount0 < limits[0]); vm.assume(amount1 < limits[1]); - + uint256[] memory amounts = new uint256[](2); amounts[0] = amount0; amounts[1] = amount1; - + Fraction[] memory prices = adapter.price(pair, WETH, USDC, amounts); - + for (uint256 i = 0; i < prices.length; i++) { assertGt(prices[i].numerator, 0); assertGt(prices[i].denominator, 0); } } - + /// @dev Since TwapRelayer's calculateAmountOut function is internal, and using quoteSell would /// revert the transaction if calculateAmountOut is not enough, /// we need a threshold to cover this internal amount, applied to @@ -56,29 +73,34 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { // // OrderSide side = isBuy ? OrderSide.Buy : OrderSide.Sell; - + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - uint256[] memory limits = new uint256[](4); - + uint256[] memory limits = new uint256[](2); + uint256[] memory limitsMin = new uint256[](2); + if (side == OrderSide.Buy) { limits = adapter.getLimits(pair, USDC, WETH); vm.assume(specifiedAmount < limits[1]); - vm.assume(specifiedAmount > limits[3]); - + + limitsMin = getMinLimits(USDC, WETH); + vm.assume(specifiedAmount > limitsMin[1] * 115 / 100); + deal(address(USDC), address(this), type(uint256).max); USDC.approve(address(adapter), type(uint256).max); } else { limits = adapter.getLimits(pair, USDC, WETH); vm.assume(specifiedAmount < limits[0]); - vm.assume(specifiedAmount > limits[2]); - + + limitsMin = getMinLimits(USDC, WETH); + vm.assume(specifiedAmount > limitsMin[0] * 115 / 100); + deal(address(USDC), address(this), type(uint256).max); USDC.approve(address(adapter), specifiedAmount); } - + uint256 usdc_balance_before = USDC.balanceOf(address(this)); uint256 weth_balance_before = WETH.balanceOf(address(this)); - + Trade memory trade = adapter.swap( pair, USDC, @@ -86,14 +108,14 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { side, specifiedAmount ); - + if (trade.calculatedAmount > 0) { if (side == OrderSide.Buy) { assertEq( specifiedAmount, WETH.balanceOf(address(this)) + weth_balance_before ); - + assertEq( trade.calculatedAmount, usdc_balance_before - USDC.balanceOf(address(this)) @@ -103,7 +125,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { specifiedAmount, usdc_balance_before - USDC.balanceOf(address(this)) ); - + assertEq( trade.calculatedAmount, weth_balance_before + WETH.balanceOf(address(this)) @@ -111,27 +133,27 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { } } } - + function executeIncreasingSwapsIntegral(OrderSide side) internal { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - + uint256[] memory amounts = new uint256[](TEST_ITERATIONS); for (uint256 i = 0; i < TEST_ITERATIONS; i++) { amounts[i] = 1000 * i * 10 ** 6; } - + Trade[] memory trades = new Trade[](TEST_ITERATIONS); uint256 beforeSwap; for (uint256 i = 0; i < TEST_ITERATIONS; i++) { beforeSwap = vm.snapshot(); - + deal(address(USDC), address(this), amounts[i]); USDC.approve(address(adapter), amounts[i]); - + trades[i] = adapter.swap(pair, USDC, WETH, side, amounts[i]); vm.revertTo(beforeSwap); } - + for (uint256 i = 1; i < TEST_ITERATIONS - 1; i++) { assertLe( trades[i].calculatedAmount, @@ -141,7 +163,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertEq(trades[i].price.compareFractions(trades[i + 1].price), 1); } } - + function testGetCapabilitiesIntegral( bytes32 pair, address t0, @@ -152,21 +174,21 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { IERC20(t0), IERC20(t1) ); - + assertEq(res.length, 3); } - + function testGetTokensIntegral() public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); IERC20[] memory tokens = adapter.getTokens(pair); - + assertEq(tokens.length, 2); } - + function testGetLimitsIntegral() public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); - - assertEq(limits.length, 4); + + assertEq(limits.length, 2); } } \ No newline at end of file From 3a2e6202466f67575100fe631379822acef3f988 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Sat, 6 Jan 2024 17:27:36 +0100 Subject: [PATCH 29/86] fix: Fixed Fractions --- evm/lib/forge-std | 2 +- evm/src/integral/IntegralSwapAdapter.sol | 24 ++++++++++++------------ evm/test/IntegralSwapAdapter.t.sol | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/evm/lib/forge-std b/evm/lib/forge-std index f73c73d..155d547 160000 --- a/evm/lib/forge-std +++ b/evm/lib/forge-std @@ -1 +1 @@ -Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 +Subproject commit 155d547c449afa8715f538d69454b83944117811 diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index d5f7673..80e4446 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; +import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; /// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long /// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline @@ -33,7 +34,10 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = Fraction(price_, 1); + _prices[i] = Fraction( + relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)) * 10**(ERC20(address(_sellToken)).decimals()) / 10**18, + 10**(ERC20(address(_buyToken)).decimals()) + ); } } @@ -58,12 +62,10 @@ contract IntegralSwapAdapter is ISwapAdapter { buy(sellToken, buyToken, specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); - /** - * @dev once we get reply from propeller about return values in price() function and in every Fraction - * Fraction[0] = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)) * 10^(IERC20(sellToken).decimals) / 10^18 - * Fraction[1] = 10^(IERC20(buyToken).decimals) - */ - trade.price = Fraction(relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)), 1); + trade.price = Fraction( + relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)) * 10**(ERC20(address(sellToken)).decimals()) / 10**18, + 10**(ERC20(address(buyToken)).decimals()) + ); } /// @inheritdoc ISwapAdapter @@ -197,11 +199,9 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256 limitMax1 ) = relayer.getPoolState(address(sellToken), address(buyToken)); - uint256[] memory limits_ = new uint256[](2); - limits_[0] = limitMax0; - limits_[1] = limitMax1; - - return limits_; + limits = new uint256[](2); + limits[0] = limitMax0; + limits[1] = limitMax1; } } diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index adb3893..0120198 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -42,9 +42,9 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { uint256 limitMax1 ) = relayer.getPoolState(address(sellToken), address(buyToken)); - uint256[] memory limits_ = new uint256[](2); - limits_[0] = limitMin0; - limits_[1] = limitMin1; + limits = new uint256[](2); + limits[0] = limitMin0; + limits[1] = limitMin1; } function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { From 37ea829592616cf9b76a1dd05953d710680c6aa5 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 16:29:55 +0100 Subject: [PATCH 30/86] fix: Fixed prices --- evm/lib/forge-std | 2 +- evm/src/integral/IntegralSwapAdapter.sol | 28 ++++++++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/evm/lib/forge-std b/evm/lib/forge-std index 155d547..f73c73d 160000 --- a/evm/lib/forge-std +++ b/evm/lib/forge-std @@ -1 +1 @@ -Subproject commit 155d547c449afa8715f538d69454b83944117811 +Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 80e4446..d4bb2a4 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -30,14 +30,9 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory _specifiedAmounts ) external view override returns (Fraction[] memory _prices) { _prices = new Fraction[](_specifiedAmounts.length); - - uint256 price_ = relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)); - + for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = Fraction( - relayer.getPriceByTokenAddresses(address(_sellToken), address(_buyToken)) * 10**(ERC20(address(_sellToken)).decimals()) / 10**18, - 10**(ERC20(address(_buyToken)).decimals()) - ); + _prices[i] = getPriceAt(address(_sellToken), address(_buyToken)); } } @@ -62,10 +57,7 @@ contract IntegralSwapAdapter is ISwapAdapter { buy(sellToken, buyToken, specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); - trade.price = Fraction( - relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)) * 10**(ERC20(address(sellToken)).decimals()) / 10**18, - 10**(ERC20(address(buyToken)).decimals()) - ); + trade.price = getPriceAt(address(sellToken), address(buyToken)); } /// @inheritdoc ISwapAdapter @@ -203,6 +195,20 @@ contract IntegralSwapAdapter is ISwapAdapter { limits[0] = limitMax0; limits[1] = limitMax1; } + + /// @notice Get swap price including fee + /// @param sellToken token to sell + /// @param buyToken token to buy + function getPriceAt(address sellToken, address buyToken) internal view returns(Fraction memory) { + uint256 priceWithoutFee = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)); + ITwapFactory factory = ITwapFactory(relayer.factory()); + address pairAddress = factory.getPair(address(sellToken), address(buyToken)); + + return Fraction( + priceWithoutFee * 10**18, + 10**(ERC20(sellToken).decimals()) * 10**18 * (10**18 - relayer.swapFee(pairAddress)) / 10**(ERC20(buyToken).decimals()) + ); + } } interface ITwapRelayer { From af7b9cd9a634486fc69d1c6fa530a618de419794 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 16:43:03 +0100 Subject: [PATCH 31/86] feat: Integrated SafeERC20 --- evm/lib/forge-std | 2 +- evm/src/integral/IntegralSwapAdapter.sol | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/evm/lib/forge-std b/evm/lib/forge-std index f73c73d..155d547 160000 --- a/evm/lib/forge-std +++ b/evm/lib/forge-std @@ -1 +1 @@ -Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 +Subproject commit 155d547c449afa8715f538d69454b83944117811 diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index d4bb2a4..8af8487 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.13; import {IERC20, ISwapAdapter} from "src/interfaces/ISwapAdapter.sol"; import {ERC20} from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; +import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; /// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long /// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline @@ -10,6 +11,8 @@ uint256 constant SWAP_DEADLINE_SEC = 1000; /// @title Integral Swap Adapter contract IntegralSwapAdapter is ISwapAdapter { + using SafeERC20 for IERC20; + ITwapRelayer immutable relayer; constructor(address relayer_) { @@ -124,21 +127,19 @@ contract IntegralSwapAdapter is ISwapAdapter { IERC20 buyToken, uint256 amount ) internal returns (uint256) { - address swapper = msg.sender; - uint256 amountOut = relayer.quoteSell(address(sellToken), address(buyToken), amount); if (amountOut == 0) { revert Unavailable("AmountOut is zero!"); } - sellToken.transferFrom(msg.sender, address(this), amount); - sellToken.approve(address(relayer), amount); + sellToken.safeTransferFrom(msg.sender, address(this), amount); + sellToken.safeIncreaseAllowance(address(relayer), amount); relayer.sell(ITwapRelayer.SellParams({ tokenIn: address(sellToken), tokenOut: address(buyToken), wrapUnwrap: false, - to: swapper, + to: msg.sender, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountIn: amount, amountOutMin: amountOut @@ -157,21 +158,19 @@ contract IntegralSwapAdapter is ISwapAdapter { IERC20 buyToken, uint256 amountBought ) internal returns (uint256) { - address swapper = msg.sender; - uint256 amountIn = relayer.quoteBuy(address(sellToken), address(buyToken), amountBought); if (amountIn == 0) { revert Unavailable("AmountIn is zero!"); } - sellToken.transferFrom(msg.sender, address(this), amountIn); - sellToken.approve(address(relayer), amountIn); + sellToken.safeTransferFrom(msg.sender, address(this), amountIn); + sellToken.safeIncreaseAllowance(address(relayer), amountIn); relayer.buy(ITwapRelayer.BuyParams({ tokenIn: address(sellToken), tokenOut: address(buyToken), wrapUnwrap: false, - to: swapper, + to: msg.sender, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountInMax: amountIn, amountOut: amountBought From 8798fc7313cb9873d30616a354f8aa37e0368fbc Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 16:48:07 +0100 Subject: [PATCH 32/86] fix: Removed internal _getLimits --- evm/src/integral/IntegralSwapAdapter.sol | 29 ++++++++++-------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 8af8487..3d7a887 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -70,7 +70,18 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (uint256[] memory limits) { - return _getLimits(poolId, sellToken, buyToken); + ( + , + , + , + uint256 limitMax0, + , + uint256 limitMax1 + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + limits = new uint256[](2); + limits[0] = limitMax0; + limits[1] = limitMax1; } /// @inheritdoc ISwapAdapter @@ -179,22 +190,6 @@ contract IntegralSwapAdapter is ISwapAdapter { return amountIn; } - /// @notice Internal counterpart of _getLimits - function _getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) internal view returns (uint256[] memory limits) { - ( - uint256 price_, - uint256 fee, - , - uint256 limitMax0, - , - uint256 limitMax1 - ) = relayer.getPoolState(address(sellToken), address(buyToken)); - - limits = new uint256[](2); - limits[0] = limitMax0; - limits[1] = limitMax1; - } - /// @notice Get swap price including fee /// @param sellToken token to sell /// @param buyToken token to buy From 46e9a3dd0e97b9c6a91c95544708079154b696a6 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 16:53:55 +0100 Subject: [PATCH 33/86] feat: Added ConstantPrice capability --- evm/src/integral/IntegralSwapAdapter.sol | 3 ++- evm/test/IntegralSwapAdapter.t.sol | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 3d7a887..b958f41 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -91,10 +91,11 @@ contract IntegralSwapAdapter is ISwapAdapter { override returns (Capability[] memory capabilities) { - capabilities = new Capability[](3); + capabilities = new Capability[](4); capabilities[0] = Capability.SellOrder; capabilities[1] = Capability.BuyOrder; capabilities[2] = Capability.PriceFunction; + capabilities[3] = Capability.ConstantPrice; } /// @inheritdoc ISwapAdapter diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index 0120198..4e9e23e 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -175,7 +175,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { IERC20(t1) ); - assertEq(res.length, 3); + assertEq(res.length, 4); } function testGetTokensIntegral() public { From a7ea4d3604bba4c93a93526e936383326b5fe1de Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 18:04:20 +0100 Subject: [PATCH 34/86] fix: Fixed and Improved tests --- evm/src/integral/IntegralSwapAdapter.sol | 2 +- evm/test/IntegralSwapAdapter.t.sol | 77 ++++++++++++++++-------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index b958f41..425c786 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -46,7 +46,7 @@ contract IntegralSwapAdapter is ISwapAdapter { IERC20 buyToken, OrderSide side, uint256 specifiedAmount - ) external returns (Trade memory trade) { + ) external override returns (Trade memory trade) { if (specifiedAmount == 0) { return trade; } diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index 4e9e23e..65b8fd5 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -32,21 +32,6 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { vm.label(address(USDC_WETH_PAIR), "USDC_WETH_PAIR"); } - function getMinLimits(IERC20 sellToken, IERC20 buyToken) public view returns (uint256[] memory limits) { - ( - uint256 price_, - uint256 fee, - uint256 limitMin0, - uint256 limitMax0, - uint256 limitMin1, - uint256 limitMax1 - ) = relayer.getPoolState(address(sellToken), address(buyToken)); - - limits = new uint256[](2); - limits[0] = limitMin0; - limits[1] = limitMin1; - } - function testPriceFuzzIntegral(uint256 amount0, uint256 amount1) public { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); uint256[] memory limits = adapter.getLimits(pair, USDC, WETH); @@ -64,14 +49,30 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertGt(prices[i].denominator, 0); } } + + function testPriceKeepingIntegral() public { + bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + uint256[] memory amounts = new uint256[](TEST_ITERATIONS); + + for (uint256 i = 0; i < TEST_ITERATIONS; i++) { + amounts[i] = 1000 * i * 10 ** 15; + } + + Fraction[] memory prices = adapter.price(pair, WETH, USDC, amounts); + + for (uint256 i = 0; i < TEST_ITERATIONS - 1; i++) { + Fraction memory reducedPrice0 = Fraction(prices[i].numerator / 10**18, prices[i].denominator / 10**18); + Fraction memory reducedPrice1 = Fraction(prices[i + 1].numerator / 10**18, prices[i + 1].denominator / 10**18); + assertEq(reducedPrice0.compareFractions(reducedPrice1), 0); + assertGt(prices[i].denominator, 0); + assertGt(prices[i + 1].denominator, 0); + } + } /// @dev Since TwapRelayer's calculateAmountOut function is internal, and using quoteSell would /// revert the transaction if calculateAmountOut is not enough, /// we need a threshold to cover this internal amount, applied to function testSwapFuzzIntegral(uint256 specifiedAmount, bool isBuy) public { - // Fails at times | FAIL. Reason: revert: TR03; - // - // OrderSide side = isBuy ? OrderSide.Buy : OrderSide.Sell; bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); @@ -113,7 +114,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { if (side == OrderSide.Buy) { assertEq( specifiedAmount, - WETH.balanceOf(address(this)) + weth_balance_before + WETH.balanceOf(address(this)) - weth_balance_before ); assertEq( @@ -128,23 +129,34 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertEq( trade.calculatedAmount, - weth_balance_before + WETH.balanceOf(address(this)) + WETH.balanceOf(address(this)) - weth_balance_before ); } } } - + + function testSwapSellIncreasingIntegral() public { + executeIncreasingSwapsIntegral(OrderSide.Sell); + } + + function testSwapBuyIncreasing() public { + executeIncreasingSwapsIntegral(OrderSide.Buy); + } + function executeIncreasingSwapsIntegral(OrderSide side) internal { bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); + + uint256 amountConstant_ = side == OrderSide.Sell ? 1000 * 10**6 : 10**17; uint256[] memory amounts = new uint256[](TEST_ITERATIONS); - for (uint256 i = 0; i < TEST_ITERATIONS; i++) { - amounts[i] = 1000 * i * 10 ** 6; + amounts[0] = amountConstant_; + for (uint256 i = 1; i < TEST_ITERATIONS; i++) { + amounts[i] = amountConstant_ * i; } Trade[] memory trades = new Trade[](TEST_ITERATIONS); uint256 beforeSwap; - for (uint256 i = 0; i < TEST_ITERATIONS; i++) { + for (uint256 i = 1; i < TEST_ITERATIONS; i++) { beforeSwap = vm.snapshot(); deal(address(USDC), address(this), amounts[i]); @@ -160,7 +172,7 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { trades[i + 1].calculatedAmount ); assertLe(trades[i].gasUsed, trades[i + 1].gasUsed); - assertEq(trades[i].price.compareFractions(trades[i + 1].price), 1); + assertEq(trades[i].price.compareFractions(trades[i + 1].price), 0); } } @@ -191,4 +203,19 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertEq(limits.length, 2); } + + function getMinLimits(IERC20 sellToken, IERC20 buyToken) public view returns (uint256[] memory limits) { + ( + , + , + uint256 limitMin0, + , + uint256 limitMin1 + , + ) = relayer.getPoolState(address(sellToken), address(buyToken)); + + limits = new uint256[](2); + limits[0] = limitMin0; + limits[1] = limitMin1; + } } \ No newline at end of file From 3d7d4f1a985a9ef7b3926b160ee60c752349b0b2 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 18:05:07 +0100 Subject: [PATCH 35/86] fix: Removed unused parameters from Contract --- evm/src/integral/IntegralSwapAdapter.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 425c786..85e9037 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -27,7 +27,7 @@ contract IntegralSwapAdapter is ISwapAdapter { /// it will always be the same (pre and post trade) and independent of the amounts swapped, /// but we still return an array of length=specifiedAmounts.length with same values to make sure the return value is the expected from caller. function price( - bytes32 _poolId, + bytes32, IERC20 _sellToken, IERC20 _buyToken, uint256[] memory _specifiedAmounts @@ -41,7 +41,7 @@ contract IntegralSwapAdapter is ISwapAdapter { /// @inheritdoc ISwapAdapter function swap( - bytes32 poolId, + bytes32, IERC20 sellToken, IERC20 buyToken, OrderSide side, @@ -64,7 +64,7 @@ contract IntegralSwapAdapter is ISwapAdapter { } /// @inheritdoc ISwapAdapter - function getLimits(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + function getLimits(bytes32, IERC20 sellToken, IERC20 buyToken) external view override @@ -85,7 +85,7 @@ contract IntegralSwapAdapter is ISwapAdapter { } /// @inheritdoc ISwapAdapter - function getCapabilities(bytes32 poolId, IERC20 sellToken, IERC20 buyToken) + function getCapabilities(bytes32, IERC20, IERC20) external pure override From e8b3e14b3eeac0373f92b5e337aeaa85c9dc573c Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 18:26:07 +0100 Subject: [PATCH 36/86] Updated .gitignore --- evm/.gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/evm/.gitignore b/evm/.gitignore index 85198aa..409f575 100644 --- a/evm/.gitignore +++ b/evm/.gitignore @@ -1,6 +1,7 @@ # Compiler files cache/ out/ +coverage/ # Ignores development broadcast logs !/broadcast @@ -12,3 +13,7 @@ docs/ # Dotenv file .env + +# Others +.DS_STORE +lcov.info From 3d900e7500e6584debab24facffe605db358332a Mon Sep 17 00:00:00 2001 From: domenicodev Date: Mon, 8 Jan 2024 18:26:39 +0100 Subject: [PATCH 37/86] Updated .gitgnore in main folder --- .gitignore | 1 + .vscode/settings.json | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 485dee6..4045fd6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +.vscode/ diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b00c8e4..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "solidity.formatter": "forge", - "solidity.compileUsingRemoteVersion": "v0.8.20", - "solidity.packageDefaultDependenciesContractsDirectory": "evm/src", - "solidity.packageDefaultDependenciesDirectory": "evm/lib", -} \ No newline at end of file From cf41c472c6ee146db2440b2a2a567aada40184b4 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Wed, 17 Jan 2024 15:24:18 +0100 Subject: [PATCH 38/86] fix: Initial code review fixes --- evm/src/integral/IntegralSwapAdapter.sol | 50 ++++++++++++++++-------- evm/test/IntegralSwapAdapter.t.sol | 19 --------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 85e9037..67ab0bb 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -8,6 +8,7 @@ import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/Safe /// @dev Integral submitted deadline of 3600 seconds (1 hour) to Paraswap, but it is not strictly necessary to be this long /// as the contract allows less durations, we use 1000 seconds (15 minutes) as a deadline uint256 constant SWAP_DEADLINE_SEC = 1000; +uint256 constant STANDARD_TOKEN_DECIMALS = 10**18; /// @title Integral Swap Adapter contract IntegralSwapAdapter is ISwapAdapter { @@ -33,12 +34,43 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory _specifiedAmounts ) external view override returns (Fraction[] memory _prices) { _prices = new Fraction[](_specifiedAmounts.length); + uint256 price = getPriceAt(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { - _prices[i] = getPriceAt(address(_sellToken), address(_buyToken)); + _prices[i] = price; } } + /// @notice Get swap price including fee + /// @param sellToken token to sell + /// @param buyToken token to buy + function getPriceAt(address sellToken, address buyToken) internal view returns(Fraction memory) { + uint256 priceWithoutFee = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)); + ITwapFactory factory = ITwapFactory(relayer.factory()); + address pairAddress = factory.getPair(address(sellToken), address(buyToken)); + + // get swapFee formatted; swapFee is a constant + uint256 swapFeeFormatted = (STANDARD_TOKEN_DECIMALS - relayer.swapFee(pairAddress)); + + // get token decimals + uint256 sellTokenDecimals = 10**ERC20(sellToken).decimals(); + uint256 buyTokenDecimals = 10**ERC20(buyToken).decimals(); + + /** + * @dev + * Denominator works as a "standardizer" for the price rather than a reserve value + * as Integral takes prices from oracles and do not operate with reserves; + * it is therefore used to maintain integrity for the Fraction division, + * as numerator and denominator could have different token decimals(es. ETH(18)-USDC(6)). + * Both numerator and denominator are also multiplied by STANDARD_TOKEN_DECIMALS + * to ensure that precision losses are minimized or null. + */ + return Fraction( + priceWithoutFee * STANDARD_TOKEN_DECIMALS, + STANDARD_TOKEN_DECIMALS * sellTokenDecimals * swapFeeFormatted / buyTokenDecimals + ); + } + /// @inheritdoc ISwapAdapter function swap( bytes32, @@ -154,7 +186,7 @@ contract IntegralSwapAdapter is ISwapAdapter { to: msg.sender, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountIn: amount, - amountOutMin: amountOut + amountOutMin: 0 })); return amountOut; @@ -190,20 +222,6 @@ contract IntegralSwapAdapter is ISwapAdapter { return amountIn; } - - /// @notice Get swap price including fee - /// @param sellToken token to sell - /// @param buyToken token to buy - function getPriceAt(address sellToken, address buyToken) internal view returns(Fraction memory) { - uint256 priceWithoutFee = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)); - ITwapFactory factory = ITwapFactory(relayer.factory()); - address pairAddress = factory.getPair(address(sellToken), address(buyToken)); - - return Fraction( - priceWithoutFee * 10**18, - 10**(ERC20(sellToken).decimals()) * 10**18 * (10**18 - relayer.swapFee(pairAddress)) / 10**(ERC20(buyToken).decimals()) - ); - } } interface ITwapRelayer { diff --git a/evm/test/IntegralSwapAdapter.t.sol b/evm/test/IntegralSwapAdapter.t.sol index 65b8fd5..3d41885 100644 --- a/evm/test/IntegralSwapAdapter.t.sol +++ b/evm/test/IntegralSwapAdapter.t.sol @@ -49,25 +49,6 @@ contract IntegralSwapAdapterTest is Test, ISwapAdapterTypes { assertGt(prices[i].denominator, 0); } } - - function testPriceKeepingIntegral() public { - bytes32 pair = bytes32(bytes20(USDC_WETH_PAIR)); - uint256[] memory amounts = new uint256[](TEST_ITERATIONS); - - for (uint256 i = 0; i < TEST_ITERATIONS; i++) { - amounts[i] = 1000 * i * 10 ** 15; - } - - Fraction[] memory prices = adapter.price(pair, WETH, USDC, amounts); - - for (uint256 i = 0; i < TEST_ITERATIONS - 1; i++) { - Fraction memory reducedPrice0 = Fraction(prices[i].numerator / 10**18, prices[i].denominator / 10**18); - Fraction memory reducedPrice1 = Fraction(prices[i + 1].numerator / 10**18, prices[i + 1].denominator / 10**18); - assertEq(reducedPrice0.compareFractions(reducedPrice1), 0); - assertGt(prices[i].denominator, 0); - assertGt(prices[i + 1].denominator, 0); - } - } /// @dev Since TwapRelayer's calculateAmountOut function is internal, and using quoteSell would /// revert the transaction if calculateAmountOut is not enough, From 1cffd007ad034c6cb9267ad0020df817438584c6 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 18 Jan 2024 11:06:13 +0100 Subject: [PATCH 39/86] fix: Moved getPriceAt() to bottom --- evm/lib/forge-std | 2 +- evm/src/integral/IntegralSwapAdapter.sol | 60 ++++++++++++------------ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/evm/lib/forge-std b/evm/lib/forge-std index 155d547..f73c73d 160000 --- a/evm/lib/forge-std +++ b/evm/lib/forge-std @@ -1 +1 @@ -Subproject commit 155d547c449afa8715f538d69454b83944117811 +Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421 diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 67ab0bb..ea14885 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -41,36 +41,6 @@ contract IntegralSwapAdapter is ISwapAdapter { } } - /// @notice Get swap price including fee - /// @param sellToken token to sell - /// @param buyToken token to buy - function getPriceAt(address sellToken, address buyToken) internal view returns(Fraction memory) { - uint256 priceWithoutFee = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)); - ITwapFactory factory = ITwapFactory(relayer.factory()); - address pairAddress = factory.getPair(address(sellToken), address(buyToken)); - - // get swapFee formatted; swapFee is a constant - uint256 swapFeeFormatted = (STANDARD_TOKEN_DECIMALS - relayer.swapFee(pairAddress)); - - // get token decimals - uint256 sellTokenDecimals = 10**ERC20(sellToken).decimals(); - uint256 buyTokenDecimals = 10**ERC20(buyToken).decimals(); - - /** - * @dev - * Denominator works as a "standardizer" for the price rather than a reserve value - * as Integral takes prices from oracles and do not operate with reserves; - * it is therefore used to maintain integrity for the Fraction division, - * as numerator and denominator could have different token decimals(es. ETH(18)-USDC(6)). - * Both numerator and denominator are also multiplied by STANDARD_TOKEN_DECIMALS - * to ensure that precision losses are minimized or null. - */ - return Fraction( - priceWithoutFee * STANDARD_TOKEN_DECIMALS, - STANDARD_TOKEN_DECIMALS * sellTokenDecimals * swapFeeFormatted / buyTokenDecimals - ); - } - /// @inheritdoc ISwapAdapter function swap( bytes32, @@ -222,6 +192,36 @@ contract IntegralSwapAdapter is ISwapAdapter { return amountIn; } + + /// @notice Get swap price including fee + /// @param sellToken token to sell + /// @param buyToken token to buy + function getPriceAt(address sellToken, address buyToken) internal view returns(Fraction memory) { + uint256 priceWithoutFee = relayer.getPriceByTokenAddresses(address(sellToken), address(buyToken)); + ITwapFactory factory = ITwapFactory(relayer.factory()); + address pairAddress = factory.getPair(address(sellToken), address(buyToken)); + + // get swapFee formatted; swapFee is a constant + uint256 swapFeeFormatted = (STANDARD_TOKEN_DECIMALS - relayer.swapFee(pairAddress)); + + // get token decimals + uint256 sellTokenDecimals = 10**ERC20(sellToken).decimals(); + uint256 buyTokenDecimals = 10**ERC20(buyToken).decimals(); + + /** + * @dev + * Denominator works as a "standardizer" for the price rather than a reserve value + * as Integral takes prices from oracles and do not operate with reserves; + * it is therefore used to maintain integrity for the Fraction division, + * as numerator and denominator could have different token decimals(es. ETH(18)-USDC(6)). + * Both numerator and denominator are also multiplied by STANDARD_TOKEN_DECIMALS + * to ensure that precision losses are minimized or null. + */ + return Fraction( + priceWithoutFee * STANDARD_TOKEN_DECIMALS, + STANDARD_TOKEN_DECIMALS * sellTokenDecimals * swapFeeFormatted / buyTokenDecimals + ); + } } interface ITwapRelayer { From 14ce015ac4726e006f2c07be9c8ae5c8ea731725 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Fri, 19 Jan 2024 11:54:11 +0100 Subject: [PATCH 40/86] feat: Added comment about minLimits as requested --- evm/src/integral/IntegralSwapAdapter.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index ea14885..840607d 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -84,6 +84,11 @@ contract IntegralSwapAdapter is ISwapAdapter { limits = new uint256[](2); limits[0] = limitMax0; limits[1] = limitMax1; + /** + * @dev minLimits in integral are the args: 2(for sellToken, the one before limitMax0) + * and 4(for buyToken, the one before limitMax1) of the function relayer.getPoolState(sellToken, buyToken); + * an implementation of them can be found in the test of this adapter + */ } /// @inheritdoc ISwapAdapter From d8ddc33f233dcff6936fb06406b45f2915938884 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Wed, 24 Jan 2024 16:28:50 -0500 Subject: [PATCH 41/86] feat: ethereum-balancer implementation --- substreams/ethereum-balancer/.DS_Store | Bin 0 -> 6148 bytes substreams/ethereum-balancer/Cargo.lock | 1269 ++++ substreams/ethereum-balancer/Cargo.toml | 29 + substreams/ethereum-balancer/abi/README.md | 9 + .../abi/composable_stable_pool_factory.json | 283 + .../abi/erc_linear_pool_factory.json | 325 + .../abi/euler_linear_pool_factory.json | 338 ++ .../abi/gearbox_linear_pool_factory.json | 325 + substreams/ethereum-balancer/abi/get_abis.py | 54 + .../abi/managed_pool_factory.json | 353 ++ .../abi/silo_linear_pool_factory.json | 325 + substreams/ethereum-balancer/abi/vault.json | 1179 ++++ .../abi/weighted_pool_factory.json | 273 + .../abi/weighted_pool_tokens_factory.json | 125 + .../abi/yearn_linear_pool_factory.json | 325 + substreams/ethereum-balancer/buf.gen.yaml | 12 + substreams/ethereum-balancer/build.rs | 43 + .../ethereum-balancer/proto/factory.proto | 19 + substreams/ethereum-balancer/proto/pool.proto | 15 + .../proto/tycho/evm/v1/common.proto | 108 + .../proto/tycho/evm/v1/entity.proto | 32 + .../proto/tycho/evm/v1/vm.proto | 50 + .../src/abi/composable_stable_pool_factory.rs | 1545 +++++ .../src/abi/erc_linear_pool_factory.rs | 1689 ++++++ .../src/abi/euler_linear_pool_factory.rs | 1765 ++++++ .../src/abi/gearbox_linear_pool_factory.rs | 1689 ++++++ .../src/abi/managed_pool_factory.rs | 1735 ++++++ substreams/ethereum-balancer/src/abi/mod.rs | 10 + .../src/abi/silo_linear_pool_factory.rs | 1689 ++++++ substreams/ethereum-balancer/src/abi/vault.rs | 5268 +++++++++++++++++ .../src/abi/weighted_pool_factory.rs | 1511 +++++ .../src/abi/weighted_pool_tokens_factory.rs | 641 ++ .../src/abi/yearn_linear_pool_factory.rs | 1689 ++++++ substreams/ethereum-balancer/src/lib.rs | 495 ++ .../src/pb/eth.balancer.v1.rs | 28 + .../src/pb/eth.factory.v1.rs | 28 + .../ethereum-balancer/src/pb/eth.pool.v1.rs | 22 + substreams/ethereum-balancer/src/pb/mod.rs | 9 + .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 235 + substreams/ethereum-balancer/substreams.yaml | 45 + 40 files changed, 25584 insertions(+) create mode 100644 substreams/ethereum-balancer/.DS_Store create mode 100644 substreams/ethereum-balancer/Cargo.lock create mode 100644 substreams/ethereum-balancer/Cargo.toml create mode 100644 substreams/ethereum-balancer/abi/README.md create mode 100644 substreams/ethereum-balancer/abi/composable_stable_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/erc_linear_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/euler_linear_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/gearbox_linear_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/get_abis.py create mode 100644 substreams/ethereum-balancer/abi/managed_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/silo_linear_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/vault.json create mode 100644 substreams/ethereum-balancer/abi/weighted_pool_factory.json create mode 100644 substreams/ethereum-balancer/abi/weighted_pool_tokens_factory.json create mode 100644 substreams/ethereum-balancer/abi/yearn_linear_pool_factory.json create mode 100644 substreams/ethereum-balancer/buf.gen.yaml create mode 100644 substreams/ethereum-balancer/build.rs create mode 100644 substreams/ethereum-balancer/proto/factory.proto create mode 100644 substreams/ethereum-balancer/proto/pool.proto create mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto create mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto create mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto create mode 100644 substreams/ethereum-balancer/src/abi/composable_stable_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/erc_linear_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/euler_linear_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/gearbox_linear_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/managed_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/mod.rs create mode 100644 substreams/ethereum-balancer/src/abi/silo_linear_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/vault.rs create mode 100644 substreams/ethereum-balancer/src/abi/weighted_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/weighted_pool_tokens_factory.rs create mode 100644 substreams/ethereum-balancer/src/abi/yearn_linear_pool_factory.rs create mode 100644 substreams/ethereum-balancer/src/lib.rs create mode 100644 substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs create mode 100644 substreams/ethereum-balancer/src/pb/eth.factory.v1.rs create mode 100644 substreams/ethereum-balancer/src/pb/eth.pool.v1.rs create mode 100644 substreams/ethereum-balancer/src/pb/mod.rs create mode 100644 substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs create mode 100644 substreams/ethereum-balancer/substreams.yaml diff --git a/substreams/ethereum-balancer/.DS_Store b/substreams/ethereum-balancer/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..269120cf9452a35d00e53e3bec5be96a2d24a57f GIT binary patch literal 6148 zcmeHK%}(Pm5FWRMwgRLcK;meLYb8oSLKT-#$_s1|99UGErh&#j@dRGC=Qc0b&?|f)w)a@4<`1AW0jICs8Pt78c7WOXV~7Qcc{nmyVNm zZ*)qdBc(#`rQh?8gTbU*TRl)w+6$t=NGAmT07HJB1d*>MZ8eVkMCZE3QAO$2)~C~E zvsIVdySuZxoVJ>cy4-0sXR~T$ZDVuqNB1fmM(VdAQs5V-WyRtP++ruUBR}bf9zG$t zbLMMz6oo3fKr2mDgaj$*hZkFJUkzglhUH&3ub!dmbnJ&+xeIU4@BcjR=e_=ayzymj z))k3qEX)8izzlpY1NH>1EPd`{@aoI}Gw=l&pz}eZ5;_($gZk*eMwbAHB{XZnKGhPG zBP}`>GlS?s5hfMUqzYSN2$PO>Y2zG=nL(2d!WJLGt}JYYBJ}DwztrI%9E0341I)l% z28w1_qx=8x-}V37BpxvX%)qx|K$JRer;S^(ckA5d=&qHh=cptUml^z!@1LE~$g)Sj-Hf1%-bEG!5J^10Tx3GbB!IQvd(} literal 0 HcmV?d00001 diff --git a/substreams/ethereum-balancer/Cargo.lock b/substreams/ethereum-balancer/Cargo.lock new file mode 100644 index 0000000..c96455e --- /dev/null +++ b/substreams/ethereum-balancer/Cargo.lock @@ -0,0 +1,1269 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ethabi" +version = "17.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" +dependencies = [ + "ethereum-types 0.13.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types 0.14.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde 0.3.2", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "impl-rlp", + "impl-serde 0.4.0", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom 0.12.1", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde 0.3.2", + "primitive-types 0.11.1", + "uint", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash 0.8.0", + "impl-rlp", + "impl-serde 0.4.0", + "primitive-types 0.12.2", + "uint", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash 0.7.0", + "impl-codec", + "impl-rlp", + "impl-serde 0.3.2", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive 0.12.3", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools 0.10.5", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost 0.11.9", + "prost-types 0.11.9", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 2.0.41", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost 0.12.3", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "substreams" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3524a4e2931ff6cd58783e62adbd7e44f461752eca0c423793cfb462351f24" +dependencies = [ + "anyhow", + "bigdecimal", + "hex", + "hex-literal 0.3.4", + "num-bigint", + "num-integer", + "num-traits", + "pad", + "prost 0.11.9", + "prost-build", + "prost-types 0.11.9", + "substreams-macro", + "thiserror", +] + +[[package]] +name = "substreams-balancer" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "ethabi 18.0.0", + "getrandom", + "hex", + "hex-literal 0.4.1", + "itertools 0.12.0", + "num-bigint", + "prost 0.11.9", + "prost-types 0.12.3", + "substreams", + "substreams-ethereum", +] + +[[package]] +name = "substreams-ethereum" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" +dependencies = [ + "getrandom", + "num-bigint", + "substreams", + "substreams-ethereum-abigen", + "substreams-ethereum-core", + "substreams-ethereum-derive", +] + +[[package]] +name = "substreams-ethereum-abigen" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" +dependencies = [ + "anyhow", + "ethabi 17.2.0", + "heck", + "hex", + "prettyplease", + "proc-macro2", + "quote", + "substreams-ethereum-core", + "syn 1.0.109", +] + +[[package]] +name = "substreams-ethereum-core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" +dependencies = [ + "bigdecimal", + "ethabi 17.2.0", + "getrandom", + "num-bigint", + "prost 0.11.9", + "prost-build", + "prost-types 0.11.9", + "substreams", +] + +[[package]] +name = "substreams-ethereum-derive" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" +dependencies = [ + "ethabi 17.2.0", + "heck", + "hex", + "num-bigint", + "proc-macro2", + "quote", + "substreams-ethereum-abigen", + "syn 1.0.109", +] + +[[package]] +name = "substreams-macro" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63c2b15adf5b4d7a6d1a73c73df951a6b2df6fbb4f0b41304dc28c5550ce0ed0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.41", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml new file mode 100644 index 0000000..795c565 --- /dev/null +++ b/substreams/ethereum-balancer/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "substreams-balancer" +version = "0.1.0" +edition = "2021" + +[lib] +name = "substreams_balancer" +crate-type = ["cdylib"] + +[dependencies] +substreams = "0.5" +substreams-ethereum = "0.9.9" +prost = "0.11" +hex-literal = "0.4.1" +ethabi = "18.0.0" +hex = "0.4.2" +bytes = "1.5.0" +anyhow = "1.0.75" +prost-types = "0.12.3" +num-bigint = "0.4.4" +itertools = "0.12.0" + +[build-dependencies] +anyhow = "1" +substreams-ethereum = "0.9" + +# Required so that ethabi > ethereum-types build correctly under wasm32-unknown-unknown +[target.wasm32-unknown-unknown.dependencies] +getrandom = { version = "0.2", features = ["custom"] } diff --git a/substreams/ethereum-balancer/abi/README.md b/substreams/ethereum-balancer/abi/README.md new file mode 100644 index 0000000..862e872 --- /dev/null +++ b/substreams/ethereum-balancer/abi/README.md @@ -0,0 +1,9 @@ +# ABIs + +`get_abis.py` is a simple python script using the etherscan API (free plan) to gather ABIs for all of the contracts we are tracking! + +We then can define all of the abis via `substreams_ethereum::Abigen::new` in our `build.rs`. + +## Recommendation + +It would be apt to convert (maybe through copilot) the python code into the `build.rs` file and then automate the `Abigen` functionality. diff --git a/substreams/ethereum-balancer/abi/composable_stable_pool_factory.json b/substreams/ethereum-balancer/abi/composable_stable_pool_factory.json new file mode 100644 index 0000000..a8eb0fd --- /dev/null +++ b/substreams/ethereum-balancer/abi/composable_stable_pool_factory.json @@ -0,0 +1,283 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "amplificationParameter", + "type": "uint256" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "tokenRateCacheDurations", + "type": "uint256[]" + }, + { + "internalType": "bool", + "name": "exemptFromYieldProtocolFeeFlag", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract ComposableStablePool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/erc_linear_pool_factory.json b/substreams/ethereum-balancer/abi/erc_linear_pool_factory.json new file mode 100644 index 0000000..caa4a33 --- /dev/null +++ b/substreams/ethereum-balancer/abi/erc_linear_pool_factory.json @@ -0,0 +1,325 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IBalancerQueries", + "name": "queries", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "Erc4626LinearPoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20", + "name": "mainToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "upperTarget", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract LinearPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastCreatedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/euler_linear_pool_factory.json b/substreams/ethereum-balancer/abi/euler_linear_pool_factory.json new file mode 100644 index 0000000..5c55933 --- /dev/null +++ b/substreams/ethereum-balancer/abi/euler_linear_pool_factory.json @@ -0,0 +1,338 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IBalancerQueries", + "name": "queries", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_eulerProtocol", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "EulerLinearPoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20", + "name": "mainToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "upperTarget", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract LinearPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "eulerProtocol", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastCreatedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/gearbox_linear_pool_factory.json b/substreams/ethereum-balancer/abi/gearbox_linear_pool_factory.json new file mode 100644 index 0000000..e314f94 --- /dev/null +++ b/substreams/ethereum-balancer/abi/gearbox_linear_pool_factory.json @@ -0,0 +1,325 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IBalancerQueries", + "name": "queries", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "GearboxLinearPoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20", + "name": "mainToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "upperTarget", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract GearboxLinearPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastCreatedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/get_abis.py b/substreams/ethereum-balancer/abi/get_abis.py new file mode 100644 index 0000000..6649c17 --- /dev/null +++ b/substreams/ethereum-balancer/abi/get_abis.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +import json +import os +import re +import time + +import requests + +# Exports contract ABI in JSON + +abis = { + "WeightedPoolFactory (v4)": "0x897888115Ada5773E02aA29F775430BFB5F34c51", + "WeightedPool2TokensFactory": "0xA5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0", # 80Bal-20WETH + "ComposableStablePoolFactory (v5)": "0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A", + "ERC4626LinearPoolFactory (v4)": "0x813EE7a840CE909E7Fea2117A44a90b8063bd4fd", + "EulerLinearPoolFactory": "0x5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347", + "GearboxLinearPoolFactory (v2)": "0x39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B", + "ManagedPoolFactory (v2)": "0xBF904F9F340745B4f0c4702c7B6Ab1e808eA6b93", + "SiloLinearPoolFactory (v2)": "0x4E11AEec21baF1660b1a46472963cB3DA7811C89", + "YearnLinearPoolFactory (v2)": "0x5F5222Ffa40F2AEd6380D022184D6ea67C776eE0", + # Vault + "Vault": "0xBA12222222228d8Ba445958a75a0704d566BF2C8", +} + +ABI_ENDPOINT = ( + "https://api.etherscan.io/api?module=contract&action=getabi&address={address}" +) + +if etherscan_key := os.environ.get("ETHERSCAN_API_TOKEN"): + print("API KEY Loaded!") + ABI_ENDPOINT += f"&apikey={etherscan_key}" + + +def __main__(): + for name, addr in abis.items(): + normalized_name = "_".join(re.findall(r"[A-Z]+[a-z]*", name)).lower() + print(f"Getting ABI for {name} at {addr} ({normalized_name})") + + try: + ... + response = requests.get(ABI_ENDPOINT.format(address=addr)) + response_json = response.json() + abi_json = json.loads(response_json["result"]) + result = json.dumps(abi_json, indent=4, sort_keys=True) + with open(f"{normalized_name}.json", "w") as f: + f.write(result) + except Exception as err: + print(response.content) + raise err + time.sleep(0.25) + + +if __name__ == "__main__": + __main__() diff --git a/substreams/ethereum-balancer/abi/managed_pool_factory.json b/substreams/ethereum-balancer/abi/managed_pool_factory.json new file mode 100644 index 0000000..76ae0ed --- /dev/null +++ b/substreams/ethereum-balancer/abi/managed_pool_factory.json @@ -0,0 +1,353 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IExternalWeightedMath", + "name": "externalWeightedMath", + "type": "address" + }, + { + "internalType": "contract IRecoveryModeHelper", + "name": "recoveryModeHelper", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "address[]", + "name": "assetManagers", + "type": "address[]" + } + ], + "internalType": "struct ManagedPool.ManagedPoolParams", + "name": "params", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "normalizedWeights", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "swapEnabledOnStart", + "type": "bool" + }, + { + "internalType": "bool", + "name": "mustAllowlistLPs", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "managementAumFeePercentage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "aumFeeId", + "type": "uint256" + } + ], + "internalType": "struct ManagedPoolSettings.ManagedPoolSettingsParams", + "name": "settingsParams", + "type": "tuple" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getRecoveryModeHelper", + "outputs": [ + { + "internalType": "contract IRecoveryModeHelper", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getWeightedMath", + "outputs": [ + { + "internalType": "contract IExternalWeightedMath", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/silo_linear_pool_factory.json b/substreams/ethereum-balancer/abi/silo_linear_pool_factory.json new file mode 100644 index 0000000..8df940f --- /dev/null +++ b/substreams/ethereum-balancer/abi/silo_linear_pool_factory.json @@ -0,0 +1,325 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IBalancerQueries", + "name": "queries", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "SiloLinearPoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20", + "name": "mainToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "upperTarget", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract SiloLinearPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastCreatedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/vault.json b/substreams/ethereum-balancer/abi/vault.json new file mode 100644 index 0000000..79d8dd8 --- /dev/null +++ b/substreams/ethereum-balancer/abi/vault.json @@ -0,0 +1,1179 @@ +[ + { + "inputs": [ + { + "internalType": "contract IAuthorizer", + "name": "authorizer", + "type": "address" + }, + { + "internalType": "contract IWETH", + "name": "weth", + "type": "address" + }, + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "AuthorizerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ExternalBalanceTransfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "contract IFlashLoanRecipient", + "name": "recipient", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + } + ], + "name": "FlashLoan", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "int256", + "name": "delta", + "type": "int256" + } + ], + "name": "InternalBalanceChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "PausedStateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "liquidityProvider", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "int256[]", + "name": "deltas", + "type": "int256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "protocolFeeAmounts", + "type": "uint256[]" + } + ], + "name": "PoolBalanceChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "assetManager", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "int256", + "name": "cashDelta", + "type": "int256" + }, + { + "indexed": false, + "internalType": "int256", + "name": "managedDelta", + "type": "int256" + } + ], + "name": "PoolBalanceManaged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "poolAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "enum IVault.PoolSpecialization", + "name": "specialization", + "type": "uint8" + } + ], + "name": "PoolRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "relayer", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "RelayerApprovalChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenIn", + "type": "address" + }, + { + "indexed": true, + "internalType": "contract IERC20", + "name": "tokenOut", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "Swap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "TokensDeregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "assetManagers", + "type": "address[]" + } + ], + "name": "TokensRegistered", + "type": "event" + }, + { + "inputs": [], + "name": "WETH", + "outputs": [ + { + "internalType": "contract IWETH", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "assetInIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "assetOutIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.BatchSwapStep[]", + "name": "swaps", + "type": "tuple[]" + }, + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + }, + { + "internalType": "int256[]", + "name": "limits", + "type": "int256[]" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "batchSwap", + "outputs": [ + { + "internalType": "int256[]", + "name": "assetDeltas", + "type": "int256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "deregisterTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "minAmountsOut", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.ExitPoolRequest", + "name": "request", + "type": "tuple" + } + ], + "name": "exitPool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IFlashLoanRecipient", + "name": "recipient", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "name": "flashLoan", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDomainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + } + ], + "name": "getInternalBalance", + "outputs": [ + { + "internalType": "uint256[]", + "name": "balances", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "getNextNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPausedState", + "outputs": [ + { + "internalType": "bool", + "name": "paused", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "pauseWindowEndTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodEndTime", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + } + ], + "name": "getPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "enum IVault.PoolSpecialization", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "getPoolTokenInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "cash", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "managed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastChangeBlock", + "type": "uint256" + }, + { + "internalType": "address", + "name": "assetManager", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + } + ], + "name": "getPoolTokens", + "outputs": [ + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "balances", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "lastChangeBlock", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeesCollector", + "outputs": [ + { + "internalType": "contract ProtocolFeesCollector", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "address", + "name": "relayer", + "type": "address" + } + ], + "name": "hasApprovedRelayer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "components": [ + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "maxAmountsIn", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.JoinPoolRequest", + "name": "request", + "type": "tuple" + } + ], + "name": "joinPool", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum IVault.PoolBalanceOpKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct IVault.PoolBalanceOp[]", + "name": "ops", + "type": "tuple[]" + } + ], + "name": "managePoolBalance", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "enum IVault.UserBalanceOpKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IAsset", + "name": "asset", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + } + ], + "internalType": "struct IVault.UserBalanceOp[]", + "name": "ops", + "type": "tuple[]" + } + ], + "name": "manageUserBalance", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "assetInIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "assetOutIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.BatchSwapStep[]", + "name": "swaps", + "type": "tuple[]" + }, + { + "internalType": "contract IAsset[]", + "name": "assets", + "type": "address[]" + }, + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + } + ], + "name": "queryBatchSwap", + "outputs": [ + { + "internalType": "int256[]", + "name": "", + "type": "int256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum IVault.PoolSpecialization", + "name": "specialization", + "type": "uint8" + } + ], + "name": "registerPool", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "address[]", + "name": "assetManagers", + "type": "address[]" + } + ], + "name": "registerTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IAuthorizer", + "name": "newAuthorizer", + "type": "address" + } + ], + "name": "setAuthorizer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "paused", + "type": "bool" + } + ], + "name": "setPaused", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "relayer", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setRelayerApproval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "poolId", + "type": "bytes32" + }, + { + "internalType": "enum IVault.SwapKind", + "name": "kind", + "type": "uint8" + }, + { + "internalType": "contract IAsset", + "name": "assetIn", + "type": "address" + }, + { + "internalType": "contract IAsset", + "name": "assetOut", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "userData", + "type": "bytes" + } + ], + "internalType": "struct IVault.SingleSwap", + "name": "singleSwap", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "bool", + "name": "fromInternalBalance", + "type": "bool" + }, + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "bool", + "name": "toInternalBalance", + "type": "bool" + } + ], + "internalType": "struct IVault.FundManagement", + "name": "funds", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "limit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swap", + "outputs": [ + { + "internalType": "uint256", + "name": "amountCalculated", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/weighted_pool_factory.json b/substreams/ethereum-balancer/abi/weighted_pool_factory.json new file mode 100644 index 0000000..eae16ae --- /dev/null +++ b/substreams/ethereum-balancer/abi/weighted_pool_factory.json @@ -0,0 +1,273 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "normalizedWeights", + "type": "uint256[]" + }, + { + "internalType": "contract IRateProvider[]", + "name": "rateProviders", + "type": "address[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/weighted_pool_tokens_factory.json b/substreams/ethereum-balancer/abi/weighted_pool_tokens_factory.json new file mode 100644 index 0000000..9fc8cf2 --- /dev/null +++ b/substreams/ethereum-balancer/abi/weighted_pool_tokens_factory.json @@ -0,0 +1,125 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20[]", + "name": "tokens", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "weights", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "oracleEnabled", + "type": "bool" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/abi/yearn_linear_pool_factory.json b/substreams/ethereum-balancer/abi/yearn_linear_pool_factory.json new file mode 100644 index 0000000..bd5465d --- /dev/null +++ b/substreams/ethereum-balancer/abi/yearn_linear_pool_factory.json @@ -0,0 +1,325 @@ +[ + { + "inputs": [ + { + "internalType": "contract IVault", + "name": "vault", + "type": "address" + }, + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "protocolFeeProvider", + "type": "address" + }, + { + "internalType": "contract IBalancerQueries", + "name": "queries", + "type": "address" + }, + { + "internalType": "string", + "name": "factoryVersion", + "type": "string" + }, + { + "internalType": "string", + "name": "poolVersion", + "type": "string" + }, + { + "internalType": "uint256", + "name": "initialPauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [], + "name": "FactoryDisabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + } + ], + "name": "YearnLinearPoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "contract IERC20", + "name": "mainToken", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "wrappedToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "upperTarget", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "swapFeePercentage", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "protocolId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + } + ], + "name": "create", + "outputs": [ + { + "internalType": "contract LinearPool", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "selector", + "type": "bytes4" + } + ], + "name": "getActionId", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getAuthorizer", + "outputs": [ + { + "internalType": "contract IAuthorizer", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCode", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreationCodeContracts", + "outputs": [ + { + "internalType": "address", + "name": "contractA", + "type": "address" + }, + { + "internalType": "address", + "name": "contractB", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLastCreatedPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPauseConfiguration", + "outputs": [ + { + "internalType": "uint256", + "name": "pauseWindowDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "bufferPeriodDuration", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getPoolVersion", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getProtocolFeePercentagesProvider", + "outputs": [ + { + "internalType": "contract IProtocolFeePercentagesProvider", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getVault", + "outputs": [ + { + "internalType": "contract IVault", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isDisabled", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "isPoolFromFactory", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/substreams/ethereum-balancer/buf.gen.yaml b/substreams/ethereum-balancer/buf.gen.yaml new file mode 100644 index 0000000..d2e6544 --- /dev/null +++ b/substreams/ethereum-balancer/buf.gen.yaml @@ -0,0 +1,12 @@ + +version: v1 +plugins: +- plugin: buf.build/community/neoeinstein-prost:v0.2.2 + out: src/pb + opt: + - file_descriptor_set=false + +- plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1 + out: src/pb + opt: + - no_features diff --git a/substreams/ethereum-balancer/build.rs b/substreams/ethereum-balancer/build.rs new file mode 100644 index 0000000..ceabf48 --- /dev/null +++ b/substreams/ethereum-balancer/build.rs @@ -0,0 +1,43 @@ +use anyhow::Result; +use std::{fs, io::Write}; +use substreams_ethereum::Abigen; + +fn main() -> Result<()> { + let abi_folder = "abi"; + let output_folder = "src/abi"; + + let files = fs::read_dir(abi_folder)?; + let mut mod_rs_content = String::new(); + + for file in files { + let file = file?; + let file_name = file.file_name(); + let file_name = file_name.to_string_lossy(); + + if !file_name.ends_with(".json") { + continue; + } + + let contract_name = file_name.split('.').next().unwrap(); + + let input_path = format!("{}/{}", abi_folder, file_name); + let output_path = format!("{}/{}.rs", output_folder, contract_name); + + mod_rs_content.push_str(&format!("pub mod {};\n", contract_name)); + + if std::path::Path::new(&output_path).exists() { + continue; + } + + Abigen::new(contract_name, &input_path)? + .generate()? + .write_to_file(&output_path)?; + } + + let mod_rs_path = format!("{}/mod.rs", output_folder); + let mut mod_rs_file = fs::File::create(mod_rs_path)?; + + mod_rs_file.write_all(mod_rs_content.as_bytes())?; + + Ok(()) +} diff --git a/substreams/ethereum-balancer/proto/factory.proto b/substreams/ethereum-balancer/proto/factory.proto new file mode 100644 index 0000000..f191ea8 --- /dev/null +++ b/substreams/ethereum-balancer/proto/factory.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package eth.factory.v1; + +message Pools { + repeated Pool pools = 1; +} + +message Pool { + bytes pool_id = 1; + fixed64 log_ordinal = 2; +} + +message Transfer { + bytes from = 1; + bytes to = 2; + string token = 3; + string amount = 4; +} diff --git a/substreams/ethereum-balancer/proto/pool.proto b/substreams/ethereum-balancer/proto/pool.proto new file mode 100644 index 0000000..c4dd94c --- /dev/null +++ b/substreams/ethereum-balancer/proto/pool.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package eth.pool.v1; + +message Transfers { + repeated Transfer transfers = 1; +} + +message Transfer { + string from = 1; + string to = 2; + uint64 token_id = 3; + string trx_hash = 4; + uint64 ordinal = 5; +} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto new file mode 100644 index 0000000..b88d0f6 --- /dev/null +++ b/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package tycho.evm.v1; + +// This file contains the proto definitions for Substreams common to all integrations. + +// A struct describing a block. +message Block { + // The blocks hash. + bytes hash = 1; + // The parent blocks hash. + bytes parent_hash = 2; + // The block number. + uint64 number = 3; + // The block timestamp. + uint64 ts = 4; +} + +// A struct describing a transaction. +message Transaction { + // The transaction hash. + bytes hash = 1; + // The sender of the transaction. + bytes from = 2; + // The receiver of the transaction. + bytes to = 3; + // The transactions index within the block. + // TODO: should this be uint32? to match the type from the native substream type? + uint64 index = 4; +} + +// Enum to specify the type of a change. +enum ChangeType { + CHANGE_TYPE_UNSPECIFIED = 0; + CHANGE_TYPE_UPDATE = 1; + CHANGE_TYPE_CREATION = 2; + CHANGE_TYPE_DELETION = 3; +} + +// A custom struct representing an arbitrary attribute of a protocol component. +// This is mainly used by the native integration to track the necessary information about the protocol. +message Attribute { + // The name of the attribute. + string name = 1; + // The value of the attribute. + bytes value = 2; + // The type of change the attribute underwent. + ChangeType change = 3; +} + +// A struct describing a part of the protocol. +// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, +// the component would represent a single contract. In case of VM integration, such component would +// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. +// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. +// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". +message ProtocolComponent { + // A unique identifier for the component within the protocol. + // Can be e.g. a stringified address or a string describing the trading pair. + string id = 1; + // Addresses of the ERC20 tokens used by the component. + repeated bytes tokens = 2; + // Addresses of the contracts used by the component. + // Usually it is a single contract, but some protocols use multiple contracts. + repeated bytes contracts = 3; + // Attributes of the component. Used mainly be the native integration. + // The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. + repeated Attribute static_att = 4; + // Type of change the component underwent. + ChangeType change = 5; +} + +message ProtocolComponents { + repeated ProtocolComponent components = 1; +} + +// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +message BalanceChange { + // The address of the ERC20 token whose balance changed. + bytes token = 1; + // The new balance of the token. + bytes balance = 2; + // The id of the component whose TVL is tracked. + // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + bytes component_id = 3; +} + +// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +message BalanceDelta { + uint64 ord = 1; + // The tx hash of the transaction that caused the balance change. + Transaction tx = 2; + // The address of the ERC20 token whose balance changed. + bytes token = 3; + // The delta balance of the token. + bytes delta = 4; + // The id of the component whose TVL is tracked. + // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + bytes component_id = 5; +} + +message BalanceDeltas { + repeated BalanceDelta balance_deltas = 1; +} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto new file mode 100644 index 0000000..14539e4 --- /dev/null +++ b/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package tycho.evm.v1; + +import "tycho/evm/v1/common.proto"; + +// This file contains the definition for the native integration of Substreams. + +// A component is a set of attributes that are associated with a custom entity. +message EntityChanges { + // A unique identifier of the entity within the protocol. + string component_id = 1; + // The set of attributes that are associated with the entity. + repeated Attribute attributes = 2; +} + +message TransactionEntityChanges { + Transaction tx = 1; + repeated EntityChanges entity_changes = 2; + // An array of newly added components. + repeated ProtocolComponent component_changes = 3; + // An array of balance changes to components. + repeated BalanceChange balance_changes = 4; +} + +// A set of transaction changes within a single block. +message BlockEntityChanges { + // The block for which these changes are collectively computed. + Block block = 1; + // The set of transaction changes observed in the specified block. + repeated TransactionEntityChanges changes = 2; +} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto new file mode 100644 index 0000000..a49dcf0 --- /dev/null +++ b/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; + +package tycho.evm.v1; + +import "tycho/evm/v1/common.proto"; + +// This file contains proto definitions specific to the VM integration. + +// A key value entry into contract storage. +message ContractSlot { + // A contract's storage slot. + bytes slot = 2; + // The new value for this storage slot. + bytes value = 3; +} + +// Changes made to a single contract's state. +message ContractChange { + // The contract's address + bytes address = 1; + // The new native balance of the contract, empty bytes indicates no change. + bytes balance = 2; + // The new code of the contract, empty bytes indicates no change. + bytes code = 3; + // The changes to this contract's slots, empty sequence indicates no change. + repeated ContractSlot slots = 4; + // Whether this is an update, a creation or a deletion. + ChangeType change = 5; +} + +// A set of changes aggregated by transaction. +message TransactionContractChanges { + // The transaction instance that results in the changes. + Transaction tx = 1; + // Contains the changes induced by the above transaction, aggregated on a per-contract basis. + // Must include changes to every contract that is tracked by all ProtocolComponents. + repeated ContractChange contract_changes = 2; + // An array of any component changes. + repeated ProtocolComponent component_changes = 3; + // An array of balance changes to components. + repeated BalanceChange balance_changes = 4; +} + +// A set of transaction changes within a single block. +message BlockContractChanges { + // The block for which these changes are collectively computed. + Block block = 1; + // The set of transaction changes observed in the specified block. + repeated TransactionContractChanges changes = 2; +} diff --git a/substreams/ethereum-balancer/src/abi/composable_stable_pool_factory.rs b/substreams/ethereum-balancer/src/abi/composable_stable_pool_factory.rs new file mode 100644 index 0000000..0d2a930 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/composable_stable_pool_factory.rs @@ -0,0 +1,1545 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub tokens: Vec>, + pub amplification_parameter: substreams::scalar::BigInt, + pub rate_providers: Vec>, + pub token_rate_cache_durations: Vec, + pub exempt_from_yield_protocol_fee_flag: bool, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [151u8, 30u8, 24u8, 51u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + amplification_parameter: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + rate_providers: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + token_rate_cache_durations: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + exempt_from_yield_protocol_fee_flag: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.amplification_parameter.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + { + let v = self + .rate_providers + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .token_rate_cache_durations + .iter() + .map(|inner| ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match inner.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Bool( + self.exempt_from_yield_protocol_fee_flag.clone(), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/erc_linear_pool_factory.rs b/substreams/ethereum-balancer/src/abi/erc_linear_pool_factory.rs new file mode 100644 index 0000000..5905670 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/erc_linear_pool_factory.rs @@ -0,0 +1,1689 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub main_token: Vec, + pub wrapped_token: Vec, + pub upper_target: substreams::scalar::BigInt, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub protocol_id: substreams::scalar::BigInt, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [118u8, 137u8, 91u8, 231u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + main_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + wrapped_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upper_target: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.main_token), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.wrapped_token), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.upper_target.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.protocol_id.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetLastCreatedPool {} + impl GetLastCreatedPool { + const METHOD_ID: [u8; 4] = [94u8, 211u8, 18u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetLastCreatedPool { + const NAME: &'static str = "getLastCreatedPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetLastCreatedPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Erc4626LinearPoolCreated { + pub pool: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl Erc4626LinearPoolCreated { + const TOPIC_ID: [u8; 32] = [ + 69u8, + 221u8, + 97u8, + 93u8, + 46u8, + 215u8, + 153u8, + 79u8, + 152u8, + 254u8, + 200u8, + 55u8, + 178u8, + 208u8, + 146u8, + 175u8, + 147u8, + 60u8, + 101u8, + 32u8, + 184u8, + 113u8, + 124u8, + 58u8, + 100u8, + 49u8, + 121u8, + 97u8, + 202u8, + 165u8, + 50u8, + 234u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'protocol_id' from topic of type 'uint256': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Erc4626LinearPoolCreated { + const NAME: &'static str = "Erc4626LinearPoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/euler_linear_pool_factory.rs b/substreams/ethereum-balancer/src/abi/euler_linear_pool_factory.rs new file mode 100644 index 0000000..afc20e3 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/euler_linear_pool_factory.rs @@ -0,0 +1,1765 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub main_token: Vec, + pub wrapped_token: Vec, + pub upper_target: substreams::scalar::BigInt, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl Create { + const METHOD_ID: [u8; 4] = [223u8, 138u8, 249u8, 137u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + main_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + wrapped_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upper_target: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.main_token), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.wrapped_token), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.upper_target.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.protocol_id.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct EulerProtocol {} + impl EulerProtocol { + const METHOD_ID: [u8; 4] = [82u8, 8u8, 252u8, 43u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for EulerProtocol { + const NAME: &'static str = "eulerProtocol"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for EulerProtocol { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetLastCreatedPool {} + impl GetLastCreatedPool { + const METHOD_ID: [u8; 4] = [94u8, 211u8, 18u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetLastCreatedPool { + const NAME: &'static str = "getLastCreatedPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetLastCreatedPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct EulerLinearPoolCreated { + pub pool: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl EulerLinearPoolCreated { + const TOPIC_ID: [u8; 32] = [ + 222u8, + 57u8, + 57u8, + 206u8, + 202u8, + 16u8, + 20u8, + 97u8, + 253u8, + 126u8, + 56u8, + 151u8, + 5u8, + 2u8, + 10u8, + 31u8, + 139u8, + 21u8, + 24u8, + 237u8, + 183u8, + 93u8, + 5u8, + 40u8, + 75u8, + 33u8, + 170u8, + 39u8, + 3u8, + 84u8, + 195u8, + 220u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'protocol_id' from topic of type 'uint256': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for EulerLinearPoolCreated { + const NAME: &'static str = "EulerLinearPoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/gearbox_linear_pool_factory.rs b/substreams/ethereum-balancer/src/abi/gearbox_linear_pool_factory.rs new file mode 100644 index 0000000..89a2b16 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/gearbox_linear_pool_factory.rs @@ -0,0 +1,1689 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub main_token: Vec, + pub wrapped_token: Vec, + pub upper_target: substreams::scalar::BigInt, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub protocol_id: substreams::scalar::BigInt, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [118u8, 137u8, 91u8, 231u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + main_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + wrapped_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upper_target: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.main_token), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.wrapped_token), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.upper_target.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.protocol_id.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetLastCreatedPool {} + impl GetLastCreatedPool { + const METHOD_ID: [u8; 4] = [94u8, 211u8, 18u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetLastCreatedPool { + const NAME: &'static str = "getLastCreatedPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetLastCreatedPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GearboxLinearPoolCreated { + pub pool: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl GearboxLinearPoolCreated { + const TOPIC_ID: [u8; 32] = [ + 247u8, + 233u8, + 204u8, + 1u8, + 56u8, + 242u8, + 70u8, + 13u8, + 229u8, + 105u8, + 50u8, + 195u8, + 236u8, + 237u8, + 29u8, + 78u8, + 21u8, + 121u8, + 168u8, + 54u8, + 100u8, + 80u8, + 108u8, + 25u8, + 212u8, + 48u8, + 74u8, + 242u8, + 106u8, + 164u8, + 139u8, + 212u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'protocol_id' from topic of type 'uint256': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for GearboxLinearPoolCreated { + const NAME: &'static str = "GearboxLinearPoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/managed_pool_factory.rs b/substreams/ethereum-balancer/src/abi/managed_pool_factory.rs new file mode 100644 index 0000000..afd6cab --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/managed_pool_factory.rs @@ -0,0 +1,1735 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub params: (String, String, Vec>), + pub settings_params: ( + Vec>, + Vec, + substreams::scalar::BigInt, + bool, + bool, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + ), + pub owner: Vec, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [115u8, 4u8, 184u8, 185u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::String, ethabi::ParamType::String, + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)) + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Uint(256usize))), + ethabi::ParamType::Uint(256usize), ethabi::ParamType::Bool, + ethabi::ParamType::Bool, ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize) + ], + ), + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_string() + .expect(INTERNAL_ERR), + tuple_elements[1usize] + .clone() + .into_string() + .expect(INTERNAL_ERR), + tuple_elements[2usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec() + }) + .collect(), + ) + }, + settings_params: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec() + }) + .collect(), + tuple_elements[1usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[4usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + tuple_elements[5usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[6usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + ) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Tuple( + vec![ + ethabi::Token::String(self.params.0.clone()), + ethabi::Token::String(self.params.1.clone()), { let v = self + .params.2.iter().map(| inner | + ethabi::Token::Address(ethabi::Address::from_slice(& + inner))).collect(); ethabi::Token::Array(v) } + ], + ), + ethabi::Token::Tuple( + vec![ + { let v = self.settings_params.0.iter().map(| inner | + ethabi::Token::Address(ethabi::Address::from_slice(& + inner))).collect(); ethabi::Token::Array(v) }, { let v = + self.settings_params.1.iter().map(| inner | + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),)).collect(); ethabi::Token::Array(v) }, + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .settings_params.2.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), ethabi::Token::Bool(self.settings_params.3 + .clone()), ethabi::Token::Bool(self.settings_params.4 + .clone()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .settings_params.5.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .settings_params.6.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),) + ], + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetRecoveryModeHelper {} + impl GetRecoveryModeHelper { + const METHOD_ID: [u8; 4] = [138u8, 71u8, 174u8, 59u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetRecoveryModeHelper { + const NAME: &'static str = "getRecoveryModeHelper"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetRecoveryModeHelper { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetWeightedMath {} + impl GetWeightedMath { + const METHOD_ID: [u8; 4] = [80u8, 143u8, 14u8, 174u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetWeightedMath { + const NAME: &'static str = "getWeightedMath"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetWeightedMath { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/mod.rs b/substreams/ethereum-balancer/src/abi/mod.rs new file mode 100644 index 0000000..ef6622d --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/mod.rs @@ -0,0 +1,10 @@ +pub mod yearn_linear_pool_factory; +pub mod composable_stable_pool_factory; +pub mod vault; +pub mod weighted_pool_tokens_factory; +pub mod silo_linear_pool_factory; +pub mod euler_linear_pool_factory; +pub mod weighted_pool_factory; +pub mod managed_pool_factory; +pub mod erc_linear_pool_factory; +pub mod gearbox_linear_pool_factory; diff --git a/substreams/ethereum-balancer/src/abi/silo_linear_pool_factory.rs b/substreams/ethereum-balancer/src/abi/silo_linear_pool_factory.rs new file mode 100644 index 0000000..aa0a62e --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/silo_linear_pool_factory.rs @@ -0,0 +1,1689 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub main_token: Vec, + pub wrapped_token: Vec, + pub upper_target: substreams::scalar::BigInt, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub protocol_id: substreams::scalar::BigInt, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [118u8, 137u8, 91u8, 231u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + main_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + wrapped_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upper_target: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.main_token), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.wrapped_token), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.upper_target.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.protocol_id.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetLastCreatedPool {} + impl GetLastCreatedPool { + const METHOD_ID: [u8; 4] = [94u8, 211u8, 18u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetLastCreatedPool { + const NAME: &'static str = "getLastCreatedPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetLastCreatedPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SiloLinearPoolCreated { + pub pool: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl SiloLinearPoolCreated { + const TOPIC_ID: [u8; 32] = [ + 51u8, + 255u8, + 20u8, + 158u8, + 158u8, + 34u8, + 79u8, + 133u8, + 82u8, + 43u8, + 217u8, + 79u8, + 245u8, + 135u8, + 189u8, + 84u8, + 170u8, + 248u8, + 170u8, + 90u8, + 22u8, + 253u8, + 146u8, + 79u8, + 240u8, + 1u8, + 55u8, + 93u8, + 114u8, + 156u8, + 173u8, + 41u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'protocol_id' from topic of type 'uint256': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for SiloLinearPoolCreated { + const NAME: &'static str = "SiloLinearPoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/vault.rs b/substreams/ethereum-balancer/src/abi/vault.rs new file mode 100644 index 0000000..ec00beb --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/vault.rs @@ -0,0 +1,5268 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Weth {} + impl Weth { + const METHOD_ID: [u8; 4] = [173u8, 92u8, 70u8, 72u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Weth { + const NAME: &'static str = "WETH"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Weth { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct BatchSwap { + pub kind: substreams::scalar::BigInt, + pub swaps: Vec< + ( + [u8; 32usize], + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + >, + pub assets: Vec>, + pub funds: (Vec, bool, Vec, bool), + pub limits: Vec, + pub deadline: substreams::scalar::BigInt, + } + impl BatchSwap { + const METHOD_ID: [u8; 4] = [148u8, 91u8, 206u8, 201u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Array( + Box::new( + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), ethabi::ParamType::Bytes + ], + ), + ), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Bool, + ethabi::ParamType::Address, ethabi::ParamType::Bool + ], + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Int(256usize)), + ), + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + kind: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swaps: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let tuple_elements = inner.into_tuple().expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[1usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_bytes() + .expect(INTERNAL_ERR), + ) + }) + .collect(), + assets: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + funds: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + limits: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + .collect(), + deadline: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.kind.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + { + let v = self + .swaps + .iter() + .map(|inner| ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(inner.0.as_ref().to_vec()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.1.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.2.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.3.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), ethabi::Token::Bytes(inner.4.clone()) + ], + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .assets + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.0)), ethabi::Token::Bool(self.funds.1.clone()), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.2)), ethabi::Token::Bool(self.funds.3.clone()) + ], + ), + { + let v = self + .limits + .iter() + .map(|inner| { + let non_full_signed_bytes = inner.to_signed_bytes_be(); + let full_signed_bytes_init = if non_full_signed_bytes[0] + & 0x80 == 0x80 + { + 0xff + } else { + 0x00 + }; + let mut full_signed_bytes = [full_signed_bytes_init + as u8; 32]; + non_full_signed_bytes + .into_iter() + .rev() + .enumerate() + .for_each(|(i, byte)| full_signed_bytes[31 - i] = byte); + ethabi::Token::Int( + ethabi::Int::from_big_endian(full_signed_bytes.as_ref()), + ) + }) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.deadline.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result, String> { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Int(256usize)), + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + .collect(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for BatchSwap { + const NAME: &'static str = "batchSwap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for BatchSwap { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct DeregisterTokens { + pub pool_id: [u8; 32usize], + pub tokens: Vec>, + } + impl DeregisterTokens { + const METHOD_ID: [u8; 4] = [125u8, 58u8, 235u8, 150u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for DeregisterTokens { + const NAME: &'static str = "deregisterTokens"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ExitPool { + pub pool_id: [u8; 32usize], + pub sender: Vec, + pub recipient: Vec, + pub request: (Vec>, Vec, Vec, bool), + } + impl ExitPool { + const METHOD_ID: [u8; 4] = [139u8, 219u8, 57u8, 19u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Uint(256usize))), + ethabi::ParamType::Bytes, ethabi::ParamType::Bool + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + sender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + request: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec() + }) + .collect(), + tuple_elements[1usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + tuple_elements[2usize] + .clone() + .into_bytes() + .expect(INTERNAL_ERR), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.sender), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Tuple( + vec![ + { let v = self.request.0.iter().map(| inner | + ethabi::Token::Address(ethabi::Address::from_slice(& + inner))).collect(); ethabi::Token::Array(v) }, { let v = + self.request.1.iter().map(| inner | + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),)).collect(); ethabi::Token::Array(v) }, + ethabi::Token::Bytes(self.request.2.clone()), + ethabi::Token::Bool(self.request.3.clone()) + ], + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for ExitPool { + const NAME: &'static str = "exitPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FlashLoan { + pub recipient: Vec, + pub tokens: Vec>, + pub amounts: Vec, + pub user_data: Vec, + } + impl FlashLoan { + const METHOD_ID: [u8; 4] = [92u8, 56u8, 68u8, 158u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ethabi::ParamType::Bytes, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + amounts: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + user_data: values + .pop() + .expect(INTERNAL_ERR) + .into_bytes() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .amounts + .iter() + .map(|inner| ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match inner.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Bytes(self.user_data.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for FlashLoan { + const NAME: &'static str = "flashLoan"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetDomainSeparator {} + impl GetDomainSeparator { + const METHOD_ID: [u8; 4] = [237u8, 36u8, 145u8, 29u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetDomainSeparator { + const NAME: &'static str = "getDomainSeparator"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> + for GetDomainSeparator { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetInternalBalance { + pub user: Vec, + pub tokens: Vec>, + } + impl GetInternalBalance { + const METHOD_ID: [u8; 4] = [15u8, 90u8, 110u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + user: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.user)), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result, String> { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetInternalBalance { + const NAME: &'static str = "getInternalBalance"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetInternalBalance { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetNextNonce { + pub user: Vec, + } + impl GetNextNonce { + const METHOD_ID: [u8; 4] = [144u8, 25u8, 59u8, 124u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + user: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.user))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetNextNonce { + const NAME: &'static str = "getNextNonce"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for GetNextNonce { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPausedState {} + impl GetPausedState { + const METHOD_ID: [u8; 4] = [28u8, 13u8, 224u8, 81u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (bool, substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (bool, substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Bool, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values.pop().expect(INTERNAL_ERR).into_bool().expect(INTERNAL_ERR), + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(bool, substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPausedState { + const NAME: &'static str = "getPausedState"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (bool, substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPausedState { + fn output( + data: &[u8], + ) -> Result< + (bool, substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPool { + pub pool_id: [u8; 32usize], + } + impl GetPool { + const METHOD_ID: [u8; 4] = [246u8, 192u8, 9u8, 39u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, substreams::scalar::BigInt), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result<(Vec, substreams::scalar::BigInt), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(8usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(Vec, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPool { + const NAME: &'static str = "getPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (Vec, substreams::scalar::BigInt), + > for GetPool { + fn output( + data: &[u8], + ) -> Result<(Vec, substreams::scalar::BigInt), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolTokenInfo { + pub pool_id: [u8; 32usize], + pub token: Vec, + } + impl GetPoolTokenInfo { + const METHOD_ID: [u8; 4] = [176u8, 95u8, 142u8, 72u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + ethabi::Token::Address(ethabi::Address::from_slice(&self.token)), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolTokenInfo { + const NAME: &'static str = "getPoolTokenInfo"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + > for GetPoolTokenInfo { + fn output( + data: &[u8], + ) -> Result< + ( + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolTokens { + pub pool_id: [u8; 32usize], + } + impl GetPoolTokens { + const METHOD_ID: [u8; 4] = [249u8, 77u8, 70u8, 104u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + ( + Vec>, + Vec, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + ( + Vec>, + Vec, + substreams::scalar::BigInt, + ), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option< + ( + Vec>, + Vec, + substreams::scalar::BigInt, + ), + > { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolTokens { + const NAME: &'static str = "getPoolTokens"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (Vec>, Vec, substreams::scalar::BigInt), + > for GetPoolTokens { + fn output( + data: &[u8], + ) -> Result< + ( + Vec>, + Vec, + substreams::scalar::BigInt, + ), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeesCollector {} + impl GetProtocolFeesCollector { + const METHOD_ID: [u8; 4] = [210u8, 148u8, 108u8, 43u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeesCollector { + const NAME: &'static str = "getProtocolFeesCollector"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeesCollector { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct HasApprovedRelayer { + pub user: Vec, + pub relayer: Vec, + } + impl HasApprovedRelayer { + const METHOD_ID: [u8; 4] = [254u8, 201u8, 13u8, 114u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + user: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + relayer: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address(ethabi::Address::from_slice(&self.user)), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.relayer), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for HasApprovedRelayer { + const NAME: &'static str = "hasApprovedRelayer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for HasApprovedRelayer { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct JoinPool { + pub pool_id: [u8; 32usize], + pub sender: Vec, + pub recipient: Vec, + pub request: (Vec>, Vec, Vec, bool), + } + impl JoinPool { + const METHOD_ID: [u8; 4] = [185u8, 92u8, 172u8, 40u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + ethabi::ParamType::Array(Box::new(ethabi::ParamType::Uint(256usize))), + ethabi::ParamType::Bytes, ethabi::ParamType::Bool + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + sender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + request: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec() + }) + .collect(), + tuple_elements[1usize] + .clone() + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + tuple_elements[2usize] + .clone() + .into_bytes() + .expect(INTERNAL_ERR), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.sender), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.recipient), + ), + ethabi::Token::Tuple( + vec![ + { let v = self.request.0.iter().map(| inner | + ethabi::Token::Address(ethabi::Address::from_slice(& + inner))).collect(); ethabi::Token::Array(v) }, { let v = + self.request.1.iter().map(| inner | + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),)).collect(); ethabi::Token::Array(v) }, + ethabi::Token::Bytes(self.request.2.clone()), + ethabi::Token::Bool(self.request.3.clone()) + ], + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for JoinPool { + const NAME: &'static str = "joinPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ManagePoolBalance { + pub ops: Vec< + ( + substreams::scalar::BigInt, + [u8; 32usize], + Vec, + substreams::scalar::BigInt, + ), + >, + } + impl ManagePoolBalance { + const METHOD_ID: [u8; 4] = [230u8, 196u8, 96u8, 146u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new( + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize) + ], + ), + ), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + ops: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let tuple_elements = inner.into_tuple().expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut result = [0u8; 32]; + let v = tuple_elements[1usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + ) + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let v = self + .ops + .iter() + .map(|inner| ethabi::Token::Tuple( + vec![ + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.0.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), ethabi::Token::FixedBytes(inner.1.as_ref() + .to_vec()), + ethabi::Token::Address(ethabi::Address::from_slice(& inner + .2)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.3.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),) + ], + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for ManagePoolBalance { + const NAME: &'static str = "managePoolBalance"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ManageUserBalance { + pub ops: Vec< + ( + substreams::scalar::BigInt, + Vec, + substreams::scalar::BigInt, + Vec, + Vec, + ), + >, + } + impl ManageUserBalance { + const METHOD_ID: [u8; 4] = [14u8, 142u8, 62u8, 132u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new( + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Uint(8usize), ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, ethabi::ParamType::Address + ], + ), + ), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + ops: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let tuple_elements = inner.into_tuple().expect(INTERNAL_ERR); + ( + { + let mut v = [0 as u8; 32]; + tuple_elements[0usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[1usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[3usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[4usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + { + let v = self + .ops + .iter() + .map(|inner| ethabi::Token::Tuple( + vec![ + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.0.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Address(ethabi::Address::from_slice(& inner + .1)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.2.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Address(ethabi::Address::from_slice(& inner + .3)), ethabi::Token::Address(ethabi::Address::from_slice(& + inner.4)) + ], + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for ManageUserBalance { + const NAME: &'static str = "manageUserBalance"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct QueryBatchSwap { + pub kind: substreams::scalar::BigInt, + pub swaps: Vec< + ( + [u8; 32usize], + substreams::scalar::BigInt, + substreams::scalar::BigInt, + substreams::scalar::BigInt, + Vec, + ), + >, + pub assets: Vec>, + pub funds: (Vec, bool, Vec, bool), + } + impl QueryBatchSwap { + const METHOD_ID: [u8; 4] = [248u8, 77u8, 6u8, 110u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(8usize), + ethabi::ParamType::Array( + Box::new( + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), ethabi::ParamType::Bytes + ], + ), + ), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Bool, + ethabi::ParamType::Address, ethabi::ParamType::Bool + ], + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + kind: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swaps: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let tuple_elements = inner.into_tuple().expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[1usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[2usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[3usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[4usize] + .clone() + .into_bytes() + .expect(INTERNAL_ERR), + ) + }) + .collect(), + assets: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + funds: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.kind.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + { + let v = self + .swaps + .iter() + .map(|inner| ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(inner.0.as_ref().to_vec()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.1.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.2.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match + inner.3.clone().to_bytes_be() { (num_bigint::Sign::Plus, + bytes) => bytes, (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), ethabi::Token::Bytes(inner.4.clone()) + ], + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .assets + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.0)), ethabi::Token::Bool(self.funds.1.clone()), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.2)), ethabi::Token::Bool(self.funds.3.clone()) + ], + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result, String> { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Int(256usize)), + ), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + .collect(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for QueryBatchSwap { + const NAME: &'static str = "queryBatchSwap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for QueryBatchSwap { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct RegisterPool { + pub specialization: substreams::scalar::BigInt, + } + impl RegisterPool { + const METHOD_ID: [u8; 4] = [9u8, 178u8, 118u8, 15u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(8usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + specialization: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.specialization.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for RegisterPool { + const NAME: &'static str = "registerPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for RegisterPool { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct RegisterTokens { + pub pool_id: [u8; 32usize], + pub tokens: Vec>, + pub asset_managers: Vec>, + } + impl RegisterTokens { + const METHOD_ID: [u8; 4] = [102u8, 169u8, 199u8, 210u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + asset_managers: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::FixedBytes(self.pool_id.as_ref().to_vec()), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .asset_managers + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for RegisterTokens { + const NAME: &'static str = "registerTokens"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetAuthorizer { + pub new_authorizer: Vec, + } + impl SetAuthorizer { + const METHOD_ID: [u8; 4] = [5u8, 138u8, 98u8, 143u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + new_authorizer: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.new_authorizer), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetAuthorizer { + const NAME: &'static str = "setAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetPaused { + pub paused: bool, + } + impl SetPaused { + const METHOD_ID: [u8; 4] = [22u8, 195u8, 139u8, 60u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + paused: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[ethabi::Token::Bool(self.paused.clone())]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetPaused { + const NAME: &'static str = "setPaused"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct SetRelayerApproval { + pub sender: Vec, + pub relayer: Vec, + pub approved: bool, + } + impl SetRelayerApproval { + const METHOD_ID: [u8; 4] = [250u8, 110u8, 103u8, 29u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Bool, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + sender: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + relayer: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + approved: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Address( + ethabi::Address::from_slice(&self.sender), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.relayer), + ), + ethabi::Token::Bool(self.approved.clone()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for SetRelayerApproval { + const NAME: &'static str = "setRelayerApproval"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub single_swap: ( + [u8; 32usize], + substreams::scalar::BigInt, + Vec, + Vec, + substreams::scalar::BigInt, + Vec, + ), + pub funds: (Vec, bool, Vec, bool), + pub limit: substreams::scalar::BigInt, + pub deadline: substreams::scalar::BigInt, + } + impl Swap { + const METHOD_ID: [u8; 4] = [82u8, 187u8, 190u8, 41u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::FixedBytes(32usize), + ethabi::ParamType::Uint(8usize), ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), ethabi::ParamType::Bytes + ], + ), + ethabi::ParamType::Tuple( + vec![ + ethabi::ParamType::Address, ethabi::ParamType::Bool, + ethabi::ParamType::Address, ethabi::ParamType::Bool + ], + ), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + single_swap: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + { + let mut result = [0u8; 32]; + let v = tuple_elements[0usize] + .clone() + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + { + let mut v = [0 as u8; 32]; + tuple_elements[1usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[3usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + { + let mut v = [0 as u8; 32]; + tuple_elements[4usize] + .clone() + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + tuple_elements[5usize] + .clone() + .into_bytes() + .expect(INTERNAL_ERR), + ) + }, + funds: { + let tuple_elements = values + .pop() + .expect(INTERNAL_ERR) + .into_tuple() + .expect(INTERNAL_ERR); + ( + tuple_elements[0usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[1usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + tuple_elements[2usize] + .clone() + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tuple_elements[3usize] + .clone() + .into_bool() + .expect(INTERNAL_ERR), + ) + }, + limit: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + deadline: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::Tuple( + vec![ + ethabi::Token::FixedBytes(self.single_swap.0.as_ref() + .to_vec()), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .single_swap.1.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .single_swap.2)), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .single_swap.3)), + ethabi::Token::Uint(ethabi::Uint::from_big_endian(match self + .single_swap.4.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") }, } + .as_slice(),),), ethabi::Token::Bytes(self.single_swap.5 + .clone()) + ], + ), + ethabi::Token::Tuple( + vec![ + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.0)), ethabi::Token::Bool(self.funds.1.clone()), + ethabi::Token::Address(ethabi::Address::from_slice(& self + .funds.2)), ethabi::Token::Bool(self.funds.3.clone()) + ], + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.limit.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.deadline.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut v = [0 as u8; 32]; + values + .pop() + .expect("one output data should have existed") + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Swap { + const NAME: &'static str = "swap"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable + for Swap { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct AuthorizerChanged { + pub new_authorizer: Vec, + } + impl AuthorizerChanged { + const TOPIC_ID: [u8; 32] = [ + 148u8, + 185u8, + 121u8, + 182u8, + 131u8, + 26u8, + 81u8, + 41u8, + 62u8, + 38u8, + 65u8, + 66u8, + 111u8, + 151u8, + 116u8, + 127u8, + 238u8, + 212u8, + 111u8, + 23u8, + 119u8, + 159u8, + 237u8, + 156u8, + 209u8, + 141u8, + 30u8, + 206u8, + 252u8, + 254u8, + 146u8, + 239u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + new_authorizer: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'new_authorizer' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for AuthorizerChanged { + const NAME: &'static str = "AuthorizerChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct ExternalBalanceTransfer { + pub token: Vec, + pub sender: Vec, + pub recipient: Vec, + pub amount: substreams::scalar::BigInt, + } + impl ExternalBalanceTransfer { + const TOPIC_ID: [u8; 32] = [ + 84u8, + 10u8, + 26u8, + 63u8, + 40u8, + 52u8, + 12u8, + 174u8, + 195u8, + 54u8, + 200u8, + 29u8, + 141u8, + 123u8, + 61u8, + 241u8, + 57u8, + 238u8, + 92u8, + 220u8, + 24u8, + 57u8, + 164u8, + 242u8, + 131u8, + 215u8, + 235u8, + 183u8, + 234u8, + 174u8, + 45u8, + 92u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Uint(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + token: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + recipient: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for ExternalBalanceTransfer { + const NAME: &'static str = "ExternalBalanceTransfer"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct FlashLoan { + pub recipient: Vec, + pub token: Vec, + pub amount: substreams::scalar::BigInt, + pub fee_amount: substreams::scalar::BigInt, + } + impl FlashLoan { + const TOPIC_ID: [u8; 32] = [ + 13u8, + 125u8, + 117u8, + 224u8, + 26u8, + 185u8, + 87u8, + 128u8, + 211u8, + 205u8, + 28u8, + 142u8, + 192u8, + 221u8, + 108u8, + 44u8, + 225u8, + 158u8, + 58u8, + 32u8, + 66u8, + 126u8, + 236u8, + 139u8, + 245u8, + 50u8, + 131u8, + 182u8, + 251u8, + 142u8, + 149u8, + 240u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + recipient: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'recipient' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + fee_amount: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for FlashLoan { + const NAME: &'static str = "FlashLoan"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct InternalBalanceChanged { + pub user: Vec, + pub token: Vec, + pub delta: substreams::scalar::BigInt, + } + impl InternalBalanceChanged { + const TOPIC_ID: [u8; 32] = [ + 24u8, + 225u8, + 234u8, + 65u8, + 57u8, + 230u8, + 132u8, + 19u8, + 215u8, + 208u8, + 138u8, + 167u8, + 82u8, + 231u8, + 21u8, + 104u8, + 227u8, + 107u8, + 44u8, + 91u8, + 249u8, + 64u8, + 137u8, + 51u8, + 20u8, + 194u8, + 197u8, + 176u8, + 30u8, + 170u8, + 12u8, + 66u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Int(256usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + user: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'user' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + delta: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for InternalBalanceChanged { + const NAME: &'static str = "InternalBalanceChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PausedStateChanged { + pub paused: bool, + } + impl PausedStateChanged { + const TOPIC_ID: [u8; 32] = [ + 158u8, + 58u8, + 94u8, + 55u8, + 34u8, + 69u8, + 50u8, + 222u8, + 166u8, + 123u8, + 137u8, + 250u8, + 206u8, + 24u8, + 87u8, + 3u8, + 115u8, + 138u8, + 34u8, + 138u8, + 110u8, + 138u8, + 35u8, + 222u8, + 229u8, + 70u8, + 150u8, + 1u8, + 128u8, + 211u8, + 190u8, + 100u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + paused: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + }) + } + } + impl substreams_ethereum::Event for PausedStateChanged { + const NAME: &'static str = "PausedStateChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolBalanceChanged { + pub pool_id: [u8; 32usize], + pub liquidity_provider: Vec, + pub tokens: Vec>, + pub deltas: Vec, + pub protocol_fee_amounts: Vec, + } + impl PoolBalanceChanged { + const TOPIC_ID: [u8; 32] = [ + 229u8, + 206u8, + 36u8, + 144u8, + 135u8, + 206u8, + 4u8, + 240u8, + 90u8, + 149u8, + 113u8, + 146u8, + 67u8, + 84u8, + 0u8, + 253u8, + 151u8, + 134u8, + 141u8, + 186u8, + 14u8, + 106u8, + 75u8, + 76u8, + 4u8, + 154u8, + 191u8, + 138u8, + 248u8, + 13u8, + 174u8, + 120u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() < 192usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Int(256usize)), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + liquidity_provider: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'liquidity_provider' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + deltas: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }) + .collect(), + protocol_fee_amounts: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + }) + } + } + impl substreams_ethereum::Event for PoolBalanceChanged { + const NAME: &'static str = "PoolBalanceChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolBalanceManaged { + pub pool_id: [u8; 32usize], + pub asset_manager: Vec, + pub token: Vec, + pub cash_delta: substreams::scalar::BigInt, + pub managed_delta: substreams::scalar::BigInt, + } + impl PoolBalanceManaged { + const TOPIC_ID: [u8; 32] = [ + 110u8, + 220u8, + 175u8, + 98u8, + 65u8, + 16u8, + 91u8, + 76u8, + 148u8, + 194u8, + 239u8, + 219u8, + 243u8, + 166u8, + 177u8, + 36u8, + 88u8, + 235u8, + 61u8, + 7u8, + 190u8, + 58u8, + 14u8, + 129u8, + 210u8, + 75u8, + 19u8, + 196u8, + 64u8, + 69u8, + 254u8, + 122u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Int(256usize), + ethabi::ParamType::Int(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + asset_manager: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'asset_manager' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[3usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + cash_delta: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + managed_delta: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_int() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_signed_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for PoolBalanceManaged { + const NAME: &'static str = "PoolBalanceManaged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolRegistered { + pub pool_id: [u8; 32usize], + pub pool_address: Vec, + pub specialization: substreams::scalar::BigInt, + } + impl PoolRegistered { + const TOPIC_ID: [u8; 32] = [ + 60u8, + 19u8, + 188u8, + 48u8, + 184u8, + 232u8, + 120u8, + 197u8, + 63u8, + 210u8, + 163u8, + 107u8, + 103u8, + 148u8, + 9u8, + 192u8, + 115u8, + 175u8, + 215u8, + 89u8, + 80u8, + 190u8, + 67u8, + 216u8, + 133u8, + 135u8, + 104u8, + 233u8, + 86u8, + 251u8, + 194u8, + 14u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Uint(8usize)], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + pool_address: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_address' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + specialization: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for PoolRegistered { + const NAME: &'static str = "PoolRegistered"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct RelayerApprovalChanged { + pub relayer: Vec, + pub sender: Vec, + pub approved: bool, + } + impl RelayerApprovalChanged { + const TOPIC_ID: [u8; 32] = [ + 70u8, + 150u8, + 31u8, + 219u8, + 69u8, + 2u8, + 182u8, + 70u8, + 213u8, + 9u8, + 95u8, + 186u8, + 118u8, + 0u8, + 72u8, + 106u8, + 138u8, + 192u8, + 80u8, + 65u8, + 213u8, + 92u8, + 223u8, + 15u8, + 22u8, + 237u8, + 103u8, + 113u8, + 128u8, + 181u8, + 202u8, + 216u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 32usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + relayer: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'relayer' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + sender: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'sender' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + approved: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + }) + } + } + impl substreams_ethereum::Event for RelayerApprovalChanged { + const NAME: &'static str = "RelayerApprovalChanged"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Swap { + pub pool_id: [u8; 32usize], + pub token_in: Vec, + pub token_out: Vec, + pub amount_in: substreams::scalar::BigInt, + pub amount_out: substreams::scalar::BigInt, + } + impl Swap { + const TOPIC_ID: [u8; 32] = [ + 33u8, + 112u8, + 199u8, + 65u8, + 196u8, + 21u8, + 49u8, + 174u8, + 194u8, + 14u8, + 124u8, + 16u8, + 124u8, + 36u8, + 238u8, + 207u8, + 221u8, + 21u8, + 230u8, + 156u8, + 155u8, + 176u8, + 168u8, + 221u8, + 55u8, + 177u8, + 132u8, + 11u8, + 158u8, + 11u8, + 32u8, + 123u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 4usize { + return false; + } + if log.data.len() != 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + token_in: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token_in' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + token_out: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[3usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'token_out' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + amount_in: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + amount_out: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for Swap { + const NAME: &'static str = "Swap"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TokensDeregistered { + pub pool_id: [u8; 32usize], + pub tokens: Vec>, + } + impl TokensDeregistered { + const TOPIC_ID: [u8; 32] = [ + 125u8, + 205u8, + 198u8, + 208u8, + 46u8, + 244u8, + 12u8, + 124u8, + 26u8, + 112u8, + 70u8, + 160u8, + 17u8, + 176u8, + 88u8, + 189u8, + 127u8, + 152u8, + 143u8, + 161u8, + 78u8, + 32u8, + 166u8, + 99u8, + 68u8, + 249u8, + 212u8, + 230u8, + 6u8, + 87u8, + 214u8, + 16u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() < 64usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + }) + } + } + impl substreams_ethereum::Event for TokensDeregistered { + const NAME: &'static str = "TokensDeregistered"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct TokensRegistered { + pub pool_id: [u8; 32usize], + pub tokens: Vec>, + pub asset_managers: Vec>, + } + impl TokensRegistered { + const TOPIC_ID: [u8; 32] = [ + 245u8, + 132u8, + 125u8, + 63u8, + 33u8, + 151u8, + 177u8, + 108u8, + 220u8, + 210u8, + 9u8, + 142u8, + 201u8, + 93u8, + 9u8, + 5u8, + 205u8, + 26u8, + 189u8, + 175u8, + 65u8, + 95u8, + 7u8, + 187u8, + 124u8, + 239u8, + 43u8, + 186u8, + 138u8, + 197u8, + 222u8, + 196u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() < 128usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ], + log.data.as_ref(), + ) + .map_err(|e| format!("unable to decode log.data: {:?}", e))?; + values.reverse(); + Ok(Self { + pool_id: { + let mut result = [0u8; 32]; + let v = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool_id' from topic of type 'bytes32': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + asset_managers: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + }) + } + } + impl substreams_ethereum::Event for TokensRegistered { + const NAME: &'static str = "TokensRegistered"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/weighted_pool_factory.rs b/substreams/ethereum-balancer/src/abi/weighted_pool_factory.rs new file mode 100644 index 0000000..db4e2bc --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/weighted_pool_factory.rs @@ -0,0 +1,1511 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub tokens: Vec>, + pub normalized_weights: Vec, + pub rate_providers: Vec>, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [33u8, 130u8, 200u8, 254u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + normalized_weights: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + rate_providers: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .normalized_weights + .iter() + .map(|inner| ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match inner.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .rate_providers + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/weighted_pool_tokens_factory.rs b/substreams/ethereum-balancer/src/abi/weighted_pool_tokens_factory.rs new file mode 100644 index 0000000..95f7262 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/weighted_pool_tokens_factory.rs @@ -0,0 +1,641 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub tokens: Vec>, + pub weights: Vec, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub oracle_enabled: bool, + pub owner: Vec, + } + impl Create { + const METHOD_ID: [u8; 4] = [21u8, 150u8, 1u8, 155u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Address), + ), + ethabi::ParamType::Array( + Box::new(ethabi::ParamType::Uint(256usize)), + ), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Bool, + ethabi::ParamType::Address, + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + tokens: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + inner.into_address().expect(INTERNAL_ERR).as_bytes().to_vec() + }) + .collect(), + weights: values + .pop() + .expect(INTERNAL_ERR) + .into_array() + .expect(INTERNAL_ERR) + .into_iter() + .map(|inner| { + let mut v = [0 as u8; 32]; + inner + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }) + .collect(), + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + oracle_enabled: values + .pop() + .expect(INTERNAL_ERR) + .into_bool() + .expect(INTERNAL_ERR), + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + { + let v = self + .tokens + .iter() + .map(|inner| ethabi::Token::Address( + ethabi::Address::from_slice(&inner), + )) + .collect(); + ethabi::Token::Array(v) + }, + { + let v = self + .weights + .iter() + .map(|inner| ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match inner.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + )) + .collect(); + ethabi::Token::Array(v) + }, + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Bool(self.oracle_enabled.clone()), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/abi/yearn_linear_pool_factory.rs b/substreams/ethereum-balancer/src/abi/yearn_linear_pool_factory.rs new file mode 100644 index 0000000..b5fbe27 --- /dev/null +++ b/substreams/ethereum-balancer/src/abi/yearn_linear_pool_factory.rs @@ -0,0 +1,1689 @@ + const INTERNAL_ERR: &'static str = "`ethabi_derive` internal error"; + /// Contract's functions. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod functions { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct Create { + pub name: String, + pub symbol: String, + pub main_token: Vec, + pub wrapped_token: Vec, + pub upper_target: substreams::scalar::BigInt, + pub swap_fee_percentage: substreams::scalar::BigInt, + pub owner: Vec, + pub protocol_id: substreams::scalar::BigInt, + pub salt: [u8; 32usize], + } + impl Create { + const METHOD_ID: [u8; 4] = [118u8, 137u8, 91u8, 231u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ + ethabi::ParamType::String, + ethabi::ParamType::String, + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Address, + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::FixedBytes(32usize), + ], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + name: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + symbol: values + .pop() + .expect(INTERNAL_ERR) + .into_string() + .expect(INTERNAL_ERR), + main_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + wrapped_token: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + upper_target: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + swap_fee_percentage: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + owner: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + salt: { + let mut result = [0u8; 32]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ + ethabi::Token::String(self.name.clone()), + ethabi::Token::String(self.symbol.clone()), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.main_token), + ), + ethabi::Token::Address( + ethabi::Address::from_slice(&self.wrapped_token), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.upper_target.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.swap_fee_percentage.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::Address(ethabi::Address::from_slice(&self.owner)), + ethabi::Token::Uint( + ethabi::Uint::from_big_endian( + match self.protocol_id.clone().to_bytes_be() { + (num_bigint::Sign::Plus, bytes) => bytes, + (num_bigint::Sign::NoSign, bytes) => bytes, + (num_bigint::Sign::Minus, _) => { + panic!("negative numbers are not supported") + } + } + .as_slice(), + ), + ), + ethabi::Token::FixedBytes(self.salt.as_ref().to_vec()), + ], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Create { + const NAME: &'static str = "create"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for Create { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Disable {} + impl Disable { + const METHOD_ID: [u8; 4] = [47u8, 39u8, 112u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + } + impl substreams_ethereum::Function for Disable { + const NAME: &'static str = "disable"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetActionId { + pub selector: [u8; 4usize], + } + impl GetActionId { + const METHOD_ID: [u8; 4] = [133u8, 28u8, 27u8, 179u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(4usize)], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + selector: { + let mut result = [0u8; 4]; + let v = values + .pop() + .expect(INTERNAL_ERR) + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }, + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::FixedBytes(self.selector.as_ref().to_vec())], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<[u8; 32usize], String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::FixedBytes(32usize)], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok({ + let mut result = [0u8; 32]; + let v = values + .pop() + .expect("one output data should have existed") + .into_fixed_bytes() + .expect(INTERNAL_ERR); + result.copy_from_slice(&v); + result + }) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<[u8; 32usize]> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetActionId { + const NAME: &'static str = "getActionId"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<[u8; 32usize]> for GetActionId { + fn output(data: &[u8]) -> Result<[u8; 32usize], String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetAuthorizer {} + impl GetAuthorizer { + const METHOD_ID: [u8; 4] = [170u8, 171u8, 173u8, 197u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetAuthorizer { + const NAME: &'static str = "getAuthorizer"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetAuthorizer { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCode {} + impl GetCreationCode { + const METHOD_ID: [u8; 4] = [0u8, 193u8, 148u8, 219u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bytes], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bytes() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCode { + const NAME: &'static str = "getCreationCode"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetCreationCode { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetCreationCodeContracts {} + impl GetCreationCodeContracts { + const METHOD_ID: [u8; 4] = [23u8, 68u8, 129u8, 250u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result<(Vec, Vec), String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address, ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option<(Vec, Vec)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetCreationCodeContracts { + const NAME: &'static str = "getCreationCodeContracts"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable<(Vec, Vec)> + for GetCreationCodeContracts { + fn output(data: &[u8]) -> Result<(Vec, Vec), String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetLastCreatedPool {} + impl GetLastCreatedPool { + const METHOD_ID: [u8; 4] = [94u8, 211u8, 18u8, 130u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetLastCreatedPool { + const NAME: &'static str = "getLastCreatedPool"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetLastCreatedPool { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPauseConfiguration {} + impl GetPauseConfiguration { + const METHOD_ID: [u8; 4] = [45u8, 164u8, 124u8, 64u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(call.return_data.as_ref()) + } + pub fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + let mut values = ethabi::decode( + &[ + ethabi::ParamType::Uint(256usize), + ethabi::ParamType::Uint(256usize), + ], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + values.reverse(); + Ok(( + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + { + let mut v = [0 as u8; 32]; + values + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + )) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call( + &self, + address: Vec, + ) -> Option<(substreams::scalar::BigInt, substreams::scalar::BigInt)> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPauseConfiguration { + const NAME: &'static str = "getPauseConfiguration"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + > for GetPauseConfiguration { + fn output( + data: &[u8], + ) -> Result< + (substreams::scalar::BigInt, substreams::scalar::BigInt), + String, + > { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetPoolVersion {} + impl GetPoolVersion { + const METHOD_ID: [u8; 4] = [63u8, 129u8, 155u8, 111u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetPoolVersion { + const NAME: &'static str = "getPoolVersion"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for GetPoolVersion { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetProtocolFeePercentagesProvider {} + impl GetProtocolFeePercentagesProvider { + const METHOD_ID: [u8; 4] = [115u8, 146u8, 56u8, 214u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetProtocolFeePercentagesProvider { + const NAME: &'static str = "getProtocolFeePercentagesProvider"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> + for GetProtocolFeePercentagesProvider { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct GetVault {} + impl GetVault { + const METHOD_ID: [u8; 4] = [141u8, 146u8, 138u8, 248u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result, String> { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result, String> { + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option> { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for GetVault { + const NAME: &'static str = "getVault"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable> for GetVault { + fn output(data: &[u8]) -> Result, String> { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsDisabled {} + impl IsDisabled { + const METHOD_ID: [u8; 4] = [108u8, 87u8, 245u8, 169u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsDisabled { + const NAME: &'static str = "isDisabled"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsDisabled { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct IsPoolFromFactory { + pub pool: Vec, + } + impl IsPoolFromFactory { + const METHOD_ID: [u8; 4] = [102u8, 52u8, 183u8, 83u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + let maybe_data = call.input.get(4..); + if maybe_data.is_none() { + return Err("no data to decode".to_string()); + } + let mut values = ethabi::decode( + &[ethabi::ParamType::Address], + maybe_data.unwrap(), + ) + .map_err(|e| format!("unable to decode call.input: {:?}", e))?; + values.reverse(); + Ok(Self { + pool: values + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode( + &[ethabi::Token::Address(ethabi::Address::from_slice(&self.pool))], + ); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::Bool], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_bool() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for IsPoolFromFactory { + const NAME: &'static str = "isPoolFromFactory"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for IsPoolFromFactory { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct Version {} + impl Version { + const METHOD_ID: [u8; 4] = [84u8, 253u8, 77u8, 80u8]; + pub fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Ok(Self {}) + } + pub fn encode(&self) -> Vec { + let data = ethabi::encode(&[]); + let mut encoded = Vec::with_capacity(4 + data.len()); + encoded.extend(Self::METHOD_ID); + encoded.extend(data); + encoded + } + pub fn output_call( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::output(call.return_data.as_ref()) + } + pub fn output(data: &[u8]) -> Result { + let mut values = ethabi::decode( + &[ethabi::ParamType::String], + data.as_ref(), + ) + .map_err(|e| format!("unable to decode output data: {:?}", e))?; + Ok( + values + .pop() + .expect("one output data should have existed") + .into_string() + .expect(INTERNAL_ERR), + ) + } + pub fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + match call.input.get(0..4) { + Some(signature) => Self::METHOD_ID == signature, + None => false, + } + } + pub fn call(&self, address: Vec) -> Option { + use substreams_ethereum::pb::eth::rpc; + let rpc_calls = rpc::RpcCalls { + calls: vec![ + rpc::RpcCall { to_addr : address, data : self.encode(), } + ], + }; + let responses = substreams_ethereum::rpc::eth_call(&rpc_calls).responses; + let response = responses + .get(0) + .expect("one response should have existed"); + if response.failed { + return None; + } + match Self::output(response.raw.as_ref()) { + Ok(data) => Some(data), + Err(err) => { + use substreams_ethereum::Function; + substreams::log::info!( + "Call output for function `{}` failed to decode with error: {}", + Self::NAME, err + ); + None + } + } + } + } + impl substreams_ethereum::Function for Version { + const NAME: &'static str = "version"; + fn match_call(call: &substreams_ethereum::pb::eth::v2::Call) -> bool { + Self::match_call(call) + } + fn decode( + call: &substreams_ethereum::pb::eth::v2::Call, + ) -> Result { + Self::decode(call) + } + fn encode(&self) -> Vec { + self.encode() + } + } + impl substreams_ethereum::rpc::RPCDecodable for Version { + fn output(data: &[u8]) -> Result { + Self::output(data) + } + } + } + /// Contract's events. + #[allow(dead_code, unused_imports, unused_variables)] + pub mod events { + use super::INTERNAL_ERR; + #[derive(Debug, Clone, PartialEq)] + pub struct FactoryDisabled {} + impl FactoryDisabled { + const TOPIC_ID: [u8; 32] = [ + 67u8, + 42u8, + 203u8, + 253u8, + 102u8, + 45u8, + 187u8, + 93u8, + 139u8, + 55u8, + 131u8, + 132u8, + 166u8, + 113u8, + 89u8, + 180u8, + 124u8, + 169u8, + 208u8, + 241u8, + 183u8, + 159u8, + 151u8, + 207u8, + 100u8, + 207u8, + 133u8, + 133u8, + 250u8, + 54u8, + 45u8, + 80u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 1usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self {}) + } + } + impl substreams_ethereum::Event for FactoryDisabled { + const NAME: &'static str = "FactoryDisabled"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct PoolCreated { + pub pool: Vec, + } + impl PoolCreated { + const TOPIC_ID: [u8; 32] = [ + 131u8, + 164u8, + 143u8, + 188u8, + 252u8, + 153u8, + 19u8, + 53u8, + 49u8, + 78u8, + 116u8, + 208u8, + 73u8, + 106u8, + 171u8, + 106u8, + 25u8, + 135u8, + 233u8, + 146u8, + 221u8, + 200u8, + 93u8, + 221u8, + 188u8, + 196u8, + 214u8, + 221u8, + 110u8, + 242u8, + 233u8, + 252u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 2usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + }) + } + } + impl substreams_ethereum::Event for PoolCreated { + const NAME: &'static str = "PoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + #[derive(Debug, Clone, PartialEq)] + pub struct YearnLinearPoolCreated { + pub pool: Vec, + pub protocol_id: substreams::scalar::BigInt, + } + impl YearnLinearPoolCreated { + const TOPIC_ID: [u8; 32] = [ + 218u8, + 47u8, + 85u8, + 125u8, + 110u8, + 128u8, + 210u8, + 220u8, + 243u8, + 137u8, + 79u8, + 43u8, + 183u8, + 79u8, + 233u8, + 132u8, + 14u8, + 77u8, + 85u8, + 142u8, + 53u8, + 15u8, + 106u8, + 173u8, + 99u8, + 175u8, + 14u8, + 11u8, + 18u8, + 241u8, + 165u8, + 134u8, + ]; + pub fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + if log.topics.len() != 3usize { + return false; + } + if log.data.len() != 0usize { + return false; + } + return log.topics.get(0).expect("bounds already checked").as_ref() + == Self::TOPIC_ID; + } + pub fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Ok(Self { + pool: ethabi::decode( + &[ethabi::ParamType::Address], + log.topics[1usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'pool' from topic of type 'address': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_address() + .expect(INTERNAL_ERR) + .as_bytes() + .to_vec(), + protocol_id: { + let mut v = [0 as u8; 32]; + ethabi::decode( + &[ethabi::ParamType::Uint(256usize)], + log.topics[2usize].as_ref(), + ) + .map_err(|e| { + format!( + "unable to decode param 'protocol_id' from topic of type 'uint256': {:?}", + e + ) + })? + .pop() + .expect(INTERNAL_ERR) + .into_uint() + .expect(INTERNAL_ERR) + .to_big_endian(v.as_mut_slice()); + substreams::scalar::BigInt::from_unsigned_bytes_be(&v) + }, + }) + } + } + impl substreams_ethereum::Event for YearnLinearPoolCreated { + const NAME: &'static str = "YearnLinearPoolCreated"; + fn match_log(log: &substreams_ethereum::pb::eth::v2::Log) -> bool { + Self::match_log(log) + } + fn decode( + log: &substreams_ethereum::pb::eth::v2::Log, + ) -> Result { + Self::decode(log) + } + } + } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/lib.rs b/substreams/ethereum-balancer/src/lib.rs new file mode 100644 index 0000000..25a4e4d --- /dev/null +++ b/substreams/ethereum-balancer/src/lib.rs @@ -0,0 +1,495 @@ +use std::collections::HashMap; + +use anyhow::Result; +use substreams::pb::substreams::StoreDeltas; +use substreams::store::{ + StoreAdd, StoreAddBigInt, StoreGet, StoreGetBigInt, StoreGetProto, StoreNew, + StoreSetIfNotExists, StoreSetIfNotExistsProto, +}; +use substreams::{hex, log}; + +use substreams::key; +use substreams::scalar::BigInt; +use substreams_ethereum::block_view::{CallView, LogView}; +use substreams_ethereum::pb::eth; +use substreams_ethereum::pb::eth::v2::{balance_change, Call, Log, TransactionTrace}; +use substreams_ethereum::{Event, Function}; + +use itertools::Itertools; +use pb::tycho::evm::v1::{self as tycho}; + +mod abi; +mod pb; + +const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); + +/// This trait defines some helpers for serializing and deserializing `Vec Vec; + fn deserialize_bytes(bytes: &[u8]) -> Vec; +} + +impl SerializableVecBigInt for Vec { + fn serialize_bytes(&self) -> Vec { + self.iter() + .flat_map(|big_int| big_int.to_signed_bytes_be()) + .collect() + } + fn deserialize_bytes(bytes: &[u8]) -> Vec { + bytes + .chunks_exact(32) + .map(|chunk| BigInt::from_signed_bytes_be(chunk)) + .collect::>() + } +} + +/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in +/// a later groupby operation. +struct TransactionWrapper(tycho::Transaction); + +impl PartialEq for TransactionWrapper { + fn eq(&self, other: &Self) -> bool { + self.0.hash == other.0.hash + } +} + +/// This is the main function that handles the creation of `ProtocolComponent`s with `Attribute`s +/// based on the specific factory address. There's 3 factory groups that are represented here: +/// - Weighted Pool Factories +/// - Linear Pool Factories +/// - Stable Pool Factories +/// (Balancer does have a bit more (esp. in the deprecated section) that could be implemented as +/// desired.) +/// We use the specific ABIs to decode both the log event and cooresponding call to gather +/// `PoolCreated` event information alongside the `Create` calldata that provide us details to +/// fufill both the required details + any extra `Attributes` +/// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html +fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + match pool_addr { + &hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { + let create_call = + abi::weighted_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::weighted_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "WeightedPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "normalized_weights".into(), + value: create_call.normalized_weights.serialize_bytes(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + &hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { + let create_call = + abi::composable_stable_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::composable_stable_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "ComposableStablePoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "amplification_parameter".into(), + value: create_call.amplification_parameter.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + &hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { + let create_call = + abi::erc_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::erc_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "ERC4626LinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + // Note, `lower_target` is generally hardcoded for all pools, not located in call data + // Note, rate provider might be provided as `create.protocol_id`, but as a BigInt. needs investigation + ], + change: tycho::ChangeType::Creation.into(), + }) + } + &hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { + let create_call = + abi::euler_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::euler_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "EulerLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + &hex!("39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B") => { + let create_call = + abi::gearbox_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::gearbox_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "GearboxLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + // The `ManagedPoolFactory` is a bit ✨ unique ✨, so we'll leave it commented out for now + // Take a look at it's `Create` call to see how the params are structured. + // &hex!("BF904F9F340745B4f0c4702c7B6Ab1e808eA6b93") => { + // let create_call = abi::managed_pool_factory::functions::Create::match_and_decode(call)?; + // let pool_created = + // abi::managed_pool_factory::events::PoolCreated::match_and_decode(log)?; + + // Some(tycho::ProtocolComponent { + // id: hex::encode(&pool_created.pool), + // tokens: create_call.tokens, + // contracts: vec![pool_addr.into(), pool_created.pool], + // static_att: vec![ + // tycho::Attribute { + // name: "pool_type".into(), + // value: "ManagedPoolFactory".into(), + // change: tycho::ChangeType::Creation.into(), + // }, + // tycho::Attribute { + // name: "swap_fee_percentage".into(), + // value: create_call.swap_fee_percentage.to_signed_bytes_be(), + // change: tycho::ChangeType::Creation.into(), + // }, + // ], + // change: tycho::ChangeType::Creation.into(), + // }) + // } + &hex!("4E11AEec21baF1660b1a46472963cB3DA7811C89") => { + let create_call = + abi::silo_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::silo_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "SiloLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + &hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { + let create_call = + abi::yearn_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::yearn_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "YearnLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + // The `WeightedPool2TokenFactory` is a deprecated contract but we've included it since one + // of the highest TVL pools, 80BAL-20WETH, is able to be tracked. + &hex!("A5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0") => { + let create_call = + abi::weighted_pool_tokens_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::weighted_pool_tokens_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "WeightedPool2TokensFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "swap_fee_percentage".into(), + value: create_call.swap_fee_percentage.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + // TODO + tycho::Attribute { + name: "weights".into(), + value: create_call.weights.serialize_bytes(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + _ => None, + } +} + +/// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a +/// store to be able to tally up final balances for tokens in a pool. +#[substreams::handlers::map] +pub fn map_balance_deltas(block: eth::v2::Block) -> Result { + Ok(tycho::BalanceDeltas { + balance_deltas: block + .events::(&[&VAULT_ADDRESS]) + .flat_map(|(event, log)| { + event + .tokens + .iter() + .zip(event.deltas.iter()) + .map(|(token, delta)| tycho::BalanceDelta { + ord: log.log.ordinal, + tx: Some(tycho::Transaction { + hash: log.receipt.transaction.hash.clone(), + from: log.receipt.transaction.from.clone(), + to: log.receipt.transaction.to.clone(), + index: Into::::into(log.receipt.transaction.index).clone(), + }), + token: token.clone(), + delta: delta.to_signed_bytes_be(), + component_id: event.pool_id.into(), + }) + .collect::>() + }) + .collect::>(), + }) +} + +/// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the +/// store key to ensure that there's a unique balance being tallied for each. +#[substreams::handlers::store] +pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt) { + deltas.balance_deltas.iter().for_each(|delta| { + store.add( + delta.ord, + format!( + "pool:{0}:token:{1}", + hex::encode(&delta.component_id), + hex::encode(&delta.token) + ), + BigInt::from_signed_bytes_be(&delta.delta), + ); + }); +} + +/// This is the main map that handles most of the indexing of this substream. +#[substreams::handlers::map] +pub fn map_changes( + block: eth::v2::Block, + deltas: tycho::BalanceDeltas, + store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. +) -> Result { + // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call + // We store these as a hashmap by tx hash since we need to agg by tx hash later + let mut transaction_contract_changes = block + .transactions() + .flat_map(|tx| { + tx.logs_with_calls() + .filter(|(_, call)| !call.call.state_reverted) + .filter_map(|(log, call)| { + let pool_factory_address = call.call.address.as_slice(); + + Some(( + tx.hash.clone(), + tycho::TransactionContractChanges { + tx: Some(tycho::Transaction { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: Into::::into(tx.index).clone(), + }), + contract_changes: vec![], + balance_changes: vec![], + component_changes: vec![pool_factory_map( + pool_factory_address, + &log, + &call.call, + )?], + }, + )) + }) + }) + .collect::>(); + + // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating `BalanceDeltas` + // We essentially just process the changes that occured to the `store` this block + // Then, these balance changes are merged onto the existing map of tx contract changes, + // inserting a new one if it doesn't exist. + store + .deltas + .into_iter() + .zip(deltas.balance_deltas) + .map(|(store_delta, balance_delta)| { + let pool_id = key::segment_at(&store_delta.key, 1); + let token_id = key::segment_at(&store_delta.key, 3); + ( + balance_delta.tx.unwrap(), + tycho::BalanceChange { + token: hex::decode(token_id).expect("Token ID not valid hex"), + balance: store_delta.new_value, + component_id: hex::decode(pool_id).expect("Token ID not valid hex"), + }, + ) + }) + // We need to group the balance changes by tx hash for the `TransactionContractChanges` agg + .group_by(|(tx, _)| TransactionWrapper(tx.clone())) + .into_iter() + .for_each(|(tx_wrapped, group)| { + let tx = tx_wrapped.0; + + if let Some(tx_change) = transaction_contract_changes.get_mut(&tx.hash) { + tx_change + .balance_changes + .extend(group.map(|(_, change)| change.clone())); + } else { + transaction_contract_changes.insert( + tx.hash.clone(), + tycho::TransactionContractChanges { + tx: Some(tx), + contract_changes: vec![], + component_changes: vec![], + balance_changes: group + .map(|(_, change)| change.clone()) + .collect::>(), + }, + ); + } + }); + + Ok(tycho::BlockContractChanges { + block: Some(tycho::Block { + number: block.number, + hash: block.hash.clone(), + parent_hash: block + .header + .as_ref() + .expect("Block header not present") + .parent_hash + .clone(), + ts: block.timestamp_seconds(), + }), + changes: transaction_contract_changes + .into_iter() + .map(|(_, v)| v) + .sorted_unstable_by_key(|tx_change| tx_change.tx.clone().unwrap().index) + .collect::>(), + }) +} diff --git a/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs b/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs new file mode 100644 index 0000000..47065d4 --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs @@ -0,0 +1,28 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pools { + #[prost(message, repeated, tag="1")] + pub pools: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pool { + #[prost(bytes="vec", tag="1")] + pub pool_id: ::prost::alloc::vec::Vec, + #[prost(fixed64, tag="2")] + pub log_ordinal: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfer { + #[prost(bytes="vec", tag="1")] + pub from: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub to: ::prost::alloc::vec::Vec, + #[prost(string, tag="3")] + pub token: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub amount: ::prost::alloc::string::String, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs b/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs new file mode 100644 index 0000000..47065d4 --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs @@ -0,0 +1,28 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pools { + #[prost(message, repeated, tag="1")] + pub pools: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Pool { + #[prost(bytes="vec", tag="1")] + pub pool_id: ::prost::alloc::vec::Vec, + #[prost(fixed64, tag="2")] + pub log_ordinal: u64, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfer { + #[prost(bytes="vec", tag="1")] + pub from: ::prost::alloc::vec::Vec, + #[prost(bytes="vec", tag="2")] + pub to: ::prost::alloc::vec::Vec, + #[prost(string, tag="3")] + pub token: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub amount: ::prost::alloc::string::String, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs b/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs new file mode 100644 index 0000000..16ad6e5 --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs @@ -0,0 +1,22 @@ +// @generated +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfers { + #[prost(message, repeated, tag="1")] + pub transfers: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transfer { + #[prost(string, tag="1")] + pub from: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub to: ::prost::alloc::string::String, + #[prost(uint64, tag="3")] + pub token_id: u64, + #[prost(string, tag="4")] + pub trx_hash: ::prost::alloc::string::String, + #[prost(uint64, tag="5")] + pub ordinal: u64, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/mod.rs b/substreams/ethereum-balancer/src/pb/mod.rs new file mode 100644 index 0000000..abb6b01 --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/mod.rs @@ -0,0 +1,9 @@ +pub mod tycho { + pub mod evm { + // @@protoc_insertion_point(attribute:tycho.evm.v1) + pub mod v1 { + include!("tycho.evm.v1.rs"); + // @@protoc_insertion_point(tycho.evm.v1) + } + } +} diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs new file mode 100644 index 0000000..a2c781a --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -0,0 +1,235 @@ +// @generated +// This file contains the proto definitions for Substreams common to all integrations. + +/// A struct describing a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + /// The blocks hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The parent blocks hash. + #[prost(bytes="vec", tag="2")] + pub parent_hash: ::prost::alloc::vec::Vec, + /// The block number. + #[prost(uint64, tag="3")] + pub number: u64, + /// The block timestamp. + #[prost(uint64, tag="4")] + pub ts: u64, +} +/// A struct describing a transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transaction { + /// The transaction hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The sender of the transaction. + #[prost(bytes="vec", tag="2")] + pub from: ::prost::alloc::vec::Vec, + /// The receiver of the transaction. + #[prost(bytes="vec", tag="3")] + pub to: ::prost::alloc::vec::Vec, + /// The transactions index within the block. + #[prost(uint64, tag="4")] + pub index: u64, +} +/// A custom struct representing an arbitrary attribute of a protocol component. +/// This is mainly used by the native integration to track the necessary information about the protocol. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Attribute { + /// The name of the attribute. + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + /// The value of the attribute. + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// The type of change the attribute underwent. + #[prost(enumeration="ChangeType", tag="3")] + pub change: i32, +} +/// A struct describing a part of the protocol. +/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, +/// the component would represent a single contract. In case of VM integration, such component would +/// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. +/// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. +/// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolComponent { + /// A unique identifier for the component within the protocol. + /// Can be e.g. a stringified address or a string describing the trading pair. + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + /// Addresses of the ERC20 tokens used by the component. + #[prost(bytes="vec", repeated, tag="2")] + pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Addresses of the contracts used by the component. + /// Usually it is a single contract, but some protocols use multiple contracts. + #[prost(bytes="vec", repeated, tag="3")] + pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Attributes of the component. Used mainly be the native integration. + /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. + #[prost(message, repeated, tag="4")] + pub static_att: ::prost::alloc::vec::Vec, + /// Type of change the component underwent. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolComponents { + #[prost(message, repeated, tag="1")] + pub components: ::prost::alloc::vec::Vec, +} +/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceChange { + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="1")] + pub token: ::prost::alloc::vec::Vec, + /// The new balance of the token. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="3")] + pub component_id: ::prost::alloc::vec::Vec, +} +/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockBalanceChanges { + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// Enum to specify the type of a change. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ChangeType { + Unspecified = 0, + Update = 1, + Creation = 2, + Deletion = 3, +} +impl ChangeType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED", + ChangeType::Update => "CHANGE_TYPE_UPDATE", + ChangeType::Creation => "CHANGE_TYPE_CREATION", + ChangeType::Deletion => "CHANGE_TYPE_DELETION", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "CHANGE_TYPE_UPDATE" => Some(Self::Update), + "CHANGE_TYPE_CREATION" => Some(Self::Creation), + "CHANGE_TYPE_DELETION" => Some(Self::Deletion), + _ => None, + } + } +} +// This file contains proto definitions specific to the VM integration. + +/// A key value entry into contract storage. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractSlot { + /// A contract's storage slot. + #[prost(bytes="vec", tag="2")] + pub slot: ::prost::alloc::vec::Vec, + /// The new value for this storage slot. + #[prost(bytes="vec", tag="3")] + pub value: ::prost::alloc::vec::Vec, +} +/// Changes made to a single contract's state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractChange { + /// The contract's address + #[prost(bytes="vec", tag="1")] + pub address: ::prost::alloc::vec::Vec, + /// The new native balance of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The new code of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="3")] + pub code: ::prost::alloc::vec::Vec, + /// The changes to this contract's slots, empty sequence indicates no change. + #[prost(message, repeated, tag="4")] + pub slots: ::prost::alloc::vec::Vec, + /// Whether this is an update, a creation or a deletion. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, +} +/// A set of changes aggregated by transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionContractChanges { + /// The transaction instance that results in the changes. + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. + /// Must include changes to every contract that is tracked by all ProtocolComponents. + #[prost(message, repeated, tag="2")] + pub contract_changes: ::prost::alloc::vec::Vec, + /// An array of any component changes. + #[prost(message, repeated, tag="3")] + pub component_changes: ::prost::alloc::vec::Vec, + /// An array of balance changes to components. + #[prost(message, repeated, tag="4")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// A set of transaction changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockContractChanges { + /// The block for which these changes are collectively computed. + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + /// The set of transaction changes observed in the specified block. + #[prost(message, repeated, tag="2")] + pub changes: ::prost::alloc::vec::Vec, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml new file mode 100644 index 0000000..99f90d0 --- /dev/null +++ b/substreams/ethereum-balancer/substreams.yaml @@ -0,0 +1,45 @@ +specVersion: v0.1.0 +package: + name: "substreams_balancer" + version: v0.1.0 + +protobuf: + files: + - tycho/evm/v1/vm.proto + - tycho/evm/v1/common.proto + importPaths: + - ../../proto/tycho/evm/v1/ + - ./proto + +binaries: + default: + type: wasm/rust-v1 + file: target/wasm32-unknown-unknown/release/substreams_balancer.wasm + +modules: + - name: map_balance_deltas + kind: map + initialBlock: 12369300 # An arbitrary block that should change based on your requirements + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.BalanceDeltas + + - name: store_balance_changes + kind: store + initialBlock: 12369300 + updatePolicy: add + valueType: bigint + inputs: + - map: map_balance_deltas + + - name: map_changes + kind: map + initialBlock: 12369300 + inputs: + - source: sf.ethereum.type.v2.Block + - map: map_transactions_created + - store: store_balance_changes + mode: deltas # This is the key property that simplifies `BalanceChange` handling + output: + type: proto:tycho.evm.v1.BlockContractChanges From c6c41e57736127c9360019c2be1c8c82d9f0952d Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Wed, 24 Jan 2024 16:24:41 -0500 Subject: [PATCH 42/86] fix: code clean w/ clippy --- substreams/ethereum-balancer/.DS_Store | Bin 6148 -> 0 bytes substreams/ethereum-balancer/src/lib.rs | 44 +++++++++++------------- 2 files changed, 20 insertions(+), 24 deletions(-) delete mode 100644 substreams/ethereum-balancer/.DS_Store diff --git a/substreams/ethereum-balancer/.DS_Store b/substreams/ethereum-balancer/.DS_Store deleted file mode 100644 index 269120cf9452a35d00e53e3bec5be96a2d24a57f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}(Pm5FWRMwgRLcK;meLYb8oSLKT-#$_s1|99UGErh&#j@dRGC=Qc0b&?|f)w)a@4<`1AW0jICs8Pt78c7WOXV~7Qcc{nmyVNm zZ*)qdBc(#`rQh?8gTbU*TRl)w+6$t=NGAmT07HJB1d*>MZ8eVkMCZE3QAO$2)~C~E zvsIVdySuZxoVJ>cy4-0sXR~T$ZDVuqNB1fmM(VdAQs5V-WyRtP++ruUBR}bf9zG$t zbLMMz6oo3fKr2mDgaj$*hZkFJUkzglhUH&3ub!dmbnJ&+xeIU4@BcjR=e_=ayzymj z))k3qEX)8izzlpY1NH>1EPd`{@aoI}Gw=l&pz}eZ5;_($gZk*eMwbAHB{XZnKGhPG zBP}`>GlS?s5hfMUqzYSN2$PO>Y2zG=nL(2d!WJLGt}JYYBJ}DwztrI%9E0341I)l% z28w1_qx=8x-}V37BpxvX%)qx|K$JRer;S^(ckA5d=&qHh=cptUml^z!@1LE~$g)Sj-Hf1%-bEG!5J^10Tx3GbB!IQvd(} diff --git a/substreams/ethereum-balancer/src/lib.rs b/substreams/ethereum-balancer/src/lib.rs index 25a4e4d..7a27d81 100644 --- a/substreams/ethereum-balancer/src/lib.rs +++ b/substreams/ethereum-balancer/src/lib.rs @@ -1,18 +1,15 @@ use std::collections::HashMap; use anyhow::Result; +use substreams::hex; use substreams::pb::substreams::StoreDeltas; -use substreams::store::{ - StoreAdd, StoreAddBigInt, StoreGet, StoreGetBigInt, StoreGetProto, StoreNew, - StoreSetIfNotExists, StoreSetIfNotExistsProto, -}; -use substreams::{hex, log}; +use substreams::store::{StoreAdd, StoreAddBigInt, StoreNew}; use substreams::key; use substreams::scalar::BigInt; -use substreams_ethereum::block_view::{CallView, LogView}; + use substreams_ethereum::pb::eth; -use substreams_ethereum::pb::eth::v2::{balance_change, Call, Log, TransactionTrace}; +use substreams_ethereum::pb::eth::v2::{Call, Log}; use substreams_ethereum::{Event, Function}; use itertools::Itertools; @@ -67,8 +64,8 @@ impl PartialEq for TransactionWrapper { /// fufill both the required details + any extra `Attributes` /// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { - match pool_addr { - &hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { + match *pool_addr { + hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { let create_call = abi::weighted_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -98,7 +95,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { let create_call = abi::composable_stable_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -128,7 +125,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { let create_call = abi::erc_linear_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -160,7 +157,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { let create_call = abi::euler_linear_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -190,7 +187,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B") => { let create_call = abi::gearbox_linear_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -222,7 +219,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + // hex!("BF904F9F340745B4f0c4702c7B6Ab1e808eA6b93") => { // let create_call = abi::managed_pool_factory::functions::Create::match_and_decode(call)?; // let pool_created = // abi::managed_pool_factory::events::PoolCreated::match_and_decode(log)?; @@ -246,7 +243,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("4E11AEec21baF1660b1a46472963cB3DA7811C89") => { let create_call = abi::silo_linear_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -276,7 +273,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { let create_call = abi::yearn_linear_pool_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -308,7 +305,7 @@ fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { + hex!("A5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0") => { let create_call = abi::weighted_pool_tokens_factory::functions::Create::match_and_decode(call)?; let pool_created = @@ -361,7 +358,7 @@ pub fn map_balance_deltas(block: eth::v2::Block) -> Result::into(log.receipt.transaction.index).clone(), + index: Into::::into(log.receipt.transaction.index), }), token: token.clone(), delta: delta.to_signed_bytes_be(), @@ -395,7 +392,7 @@ pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt pub fn map_changes( block: eth::v2::Block, deltas: tycho::BalanceDeltas, - store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. + store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. ) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call // We store these as a hashmap by tx hash since we need to agg by tx hash later @@ -414,14 +411,14 @@ pub fn map_changes( hash: tx.hash.clone(), from: tx.from.clone(), to: tx.to.clone(), - index: Into::::into(tx.index).clone(), + index: Into::::into(tx.index), }), contract_changes: vec![], balance_changes: vec![], component_changes: vec![pool_factory_map( pool_factory_address, - &log, - &call.call, + log, + call.call, )?], }, )) @@ -487,8 +484,7 @@ pub fn map_changes( ts: block.timestamp_seconds(), }), changes: transaction_contract_changes - .into_iter() - .map(|(_, v)| v) + .into_values() .sorted_unstable_by_key(|tx_change| tx_change.tx.clone().unwrap().index) .collect::>(), }) From 4d56335f2e6c6d907d5ee68669fea4d1fdf3c9be Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Wed, 24 Jan 2024 16:42:22 -0500 Subject: [PATCH 43/86] fix: naming errors in `substreams.yaml` --- substreams/ethereum-balancer/substreams.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 99f90d0..98ea7e0 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -38,7 +38,7 @@ modules: initialBlock: 12369300 inputs: - source: sf.ethereum.type.v2.Block - - map: map_transactions_created + - map: map_balance_deltas - store: store_balance_changes mode: deltas # This is the key property that simplifies `BalanceChange` handling output: From 8001e22674efc0084f653cc0a315c86a71235c52 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 25 Jan 2024 11:51:04 +0100 Subject: [PATCH 44/86] fix: Set amountOutMin --- evm/src/integral/IntegralSwapAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index 840607d..a394d26 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -161,7 +161,7 @@ contract IntegralSwapAdapter is ISwapAdapter { to: msg.sender, submitDeadline: uint32(block.timestamp + SWAP_DEADLINE_SEC), amountIn: amount, - amountOutMin: 0 + amountOutMin: amountOut })); return amountOut; From 7dca13f9e0dd7b1d1ee2b6b73b51aab50d5f9dca Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 25 Jan 2024 11:53:40 +0100 Subject: [PATCH 45/86] fix: fixed price type in price function --- evm/src/integral/IntegralSwapAdapter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/integral/IntegralSwapAdapter.sol b/evm/src/integral/IntegralSwapAdapter.sol index a394d26..4797132 100644 --- a/evm/src/integral/IntegralSwapAdapter.sol +++ b/evm/src/integral/IntegralSwapAdapter.sol @@ -34,7 +34,7 @@ contract IntegralSwapAdapter is ISwapAdapter { uint256[] memory _specifiedAmounts ) external view override returns (Fraction[] memory _prices) { _prices = new Fraction[](_specifiedAmounts.length); - uint256 price = getPriceAt(address(_sellToken), address(_buyToken)); + Fraction memory price = getPriceAt(address(_sellToken), address(_buyToken)); for (uint256 i = 0; i < _specifiedAmounts.length; i++) { _prices[i] = price; From f4f56ad42dbf5ab0a5eb6eb2e55eaf4c4794d269 Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 25 Jan 2024 12:39:52 +0100 Subject: [PATCH 46/86] fix: Solved merge conflicts --- .gitignore | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4045fd6..2c65d74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,13 @@ +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Substreams spkg files are build artifacts +*.spkg + +.env +.vscode .idea -.vscode/ +*.log From 9f82671082d635fc595324e448d41cb88a4a5632 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Mon, 29 Jan 2024 11:11:06 -0500 Subject: [PATCH 47/86] feat: lots of refactoring (file splitting - `lib.rs` split into multiple files with `modules.rs` being the main entrypoint for substreams - contract changes are tracked similiarly to ambient (generalized to use a store of tracked contracts) - static attributes were pruned of the dynamic ones --- substreams/ethereum-balancer/abi/get_abis.py | 3 +- .../proto/tycho/evm/v1/common.proto | 9 +- .../ethereum-balancer/src/contract_changes.rs | 190 +++++++ substreams/ethereum-balancer/src/lib.rs | 492 +----------------- substreams/ethereum-balancer/src/modules.rs | 239 +++++++++ substreams/ethereum-balancer/src/pb/mod.rs | 1 + .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 21 +- .../ethereum-balancer/src/pool_factories.rs | 273 ++++++++++ substreams/ethereum-balancer/substreams.yaml | 18 + 9 files changed, 744 insertions(+), 502 deletions(-) create mode 100644 substreams/ethereum-balancer/src/contract_changes.rs create mode 100644 substreams/ethereum-balancer/src/modules.rs create mode 100644 substreams/ethereum-balancer/src/pool_factories.rs diff --git a/substreams/ethereum-balancer/abi/get_abis.py b/substreams/ethereum-balancer/abi/get_abis.py index 6649c17..6b941e8 100644 --- a/substreams/ethereum-balancer/abi/get_abis.py +++ b/substreams/ethereum-balancer/abi/get_abis.py @@ -9,12 +9,13 @@ import requests # Exports contract ABI in JSON abis = { + # Factories "WeightedPoolFactory (v4)": "0x897888115Ada5773E02aA29F775430BFB5F34c51", "WeightedPool2TokensFactory": "0xA5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0", # 80Bal-20WETH "ComposableStablePoolFactory (v5)": "0xDB8d758BCb971e482B2C45f7F8a7740283A1bd3A", "ERC4626LinearPoolFactory (v4)": "0x813EE7a840CE909E7Fea2117A44a90b8063bd4fd", "EulerLinearPoolFactory": "0x5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347", - "GearboxLinearPoolFactory (v2)": "0x39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B", + # "GearboxLinearPoolFactory (v2)": "0x39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B", "ManagedPoolFactory (v2)": "0xBF904F9F340745B4f0c4702c7B6Ab1e808eA6b93", "SiloLinearPoolFactory (v2)": "0x4E11AEec21baF1660b1a46472963cB3DA7811C89", "YearnLinearPoolFactory (v2)": "0x5F5222Ffa40F2AEd6380D022184D6ea67C776eE0", diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto index b88d0f6..1a5caf4 100644 --- a/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto +++ b/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto @@ -70,8 +70,13 @@ message ProtocolComponent { ChangeType change = 5; } -message ProtocolComponents { - repeated ProtocolComponent components = 1; +message TransactionProtocolComponents { + Transaction tx = 1; + repeated ProtocolComponent components = 2; +} + +message GroupedTransactionProtocolComponents { + repeated TransactionProtocolComponents tx_components = 1; } // A struct for following the changes of Total Value Locked (TVL) of a protocol component. diff --git a/substreams/ethereum-balancer/src/contract_changes.rs b/substreams/ethereum-balancer/src/contract_changes.rs new file mode 100644 index 0000000..4ab49fe --- /dev/null +++ b/substreams/ethereum-balancer/src/contract_changes.rs @@ -0,0 +1,190 @@ +/// This file contains helpers to capture contract changes from the expanded block model. These +/// leverage the `code_changes`, `balance_changes`, and `storage_changes` fields available on the +/// `Call` type provided by block model in a substream (i.e. `logs_and_calls`, etc). +/// +/// ⚠️ These helpers *only* work if the **expanded block model** is available, more info blow. +/// https://streamingfastio.medium.com/new-block-model-to-accelerate-chain-integration-9f65126e5425 +use std::collections::HashMap; + +use substreams_ethereum::pb::eth; + +use pb::tycho::evm::v1::{self as tycho}; + +use substreams::store::{StoreGet, StoreGetInt64}; + +use crate::pb; + +struct SlotValue { + new_value: Vec, + start_value: Vec, +} + +impl SlotValue { + fn has_changed(&self) -> bool { + self.start_value != self.new_value + } +} + +// Uses a map for slots, protobuf does not allow bytes in hashmap keys +pub struct InterimContractChange { + address: Vec, + balance: Vec, + code: Vec, + slots: HashMap, SlotValue>, + change: tycho::ChangeType, +} + +impl From for tycho::ContractChange { + fn from(value: InterimContractChange) -> Self { + tycho::ContractChange { + address: value.address, + balance: value.balance, + code: value.code, + slots: value + .slots + .into_iter() + .filter(|(_, value)| value.has_changed()) + .map(|(slot, value)| tycho::ContractSlot { + slot, + value: value.new_value, + }) + .collect(), + change: value.change.into(), + } + } +} + +pub fn extract_contract_changes( + block: ð::v2::Block, + contracts: StoreGetInt64, + transaction_contract_changes: &mut HashMap, +) { + let mut changed_contracts: HashMap, InterimContractChange> = HashMap::new(); + + // Collect all accounts created in this block + let created_accounts: HashMap<_, _> = block + .transactions() + .flat_map(|tx| { + tx.calls.iter().flat_map(|call| { + call.account_creations + .iter() + .map(|ac| (&ac.account, ac.ordinal)) + }) + }) + .collect(); + + block.transactions().for_each(|block_tx| { + let mut storage_changes = Vec::new(); + let mut balance_changes = Vec::new(); + let mut code_changes = Vec::new(); + + block_tx + .calls + .iter() + .filter(|call| { + !call.state_reverted + && contracts + .get_last(format!("pool:{0}", hex::encode(&call.address))) + .is_some() + }) + .for_each(|call| { + storage_changes.extend(call.storage_changes.iter()); + balance_changes.extend(call.balance_changes.iter()); + code_changes.extend(call.code_changes.iter()); + }); + + storage_changes.sort_unstable_by_key(|change| change.ordinal); + balance_changes.sort_unstable_by_key(|change| change.ordinal); + code_changes.sort_unstable_by_key(|change| change.ordinal); + + storage_changes.iter().for_each(|storage_change| { + let contract_change = changed_contracts + .entry(storage_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: storage_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&storage_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + let slot_value = contract_change + .slots + .entry(storage_change.key.clone()) + .or_insert_with(|| SlotValue { + new_value: storage_change.new_value.clone(), + start_value: storage_change.old_value.clone(), + }); + + slot_value + .new_value + .copy_from_slice(&storage_change.new_value); + }); + + balance_changes.iter().for_each(|balance_change| { + let contract_change = changed_contracts + .entry(balance_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: balance_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&balance_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + if let Some(new_balance) = &balance_change.new_value { + contract_change.balance.clear(); + contract_change + .balance + .extend_from_slice(&new_balance.bytes); + } + }); + + code_changes.iter().for_each(|code_change| { + let contract_change = changed_contracts + .entry(code_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: code_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&code_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + contract_change.code.clear(); + contract_change + .code + .extend_from_slice(&code_change.new_code); + }); + + if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { + transaction_contract_changes + .entry(block_tx.index.into()) + .or_insert_with(|| tycho::TransactionContractChanges { + tx: Some(tycho::Transaction { + hash: block_tx.hash.clone(), + from: block_tx.from.clone(), + to: block_tx.to.clone(), + index: block_tx.index as u64, + }), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + }) + .contract_changes + .extend(changed_contracts.drain().map(|(_, change)| change.into())); + } + }); +} diff --git a/substreams/ethereum-balancer/src/lib.rs b/substreams/ethereum-balancer/src/lib.rs index 7a27d81..88ecc50 100644 --- a/substreams/ethereum-balancer/src/lib.rs +++ b/substreams/ethereum-balancer/src/lib.rs @@ -1,491 +1,5 @@ -use std::collections::HashMap; - -use anyhow::Result; -use substreams::hex; -use substreams::pb::substreams::StoreDeltas; -use substreams::store::{StoreAdd, StoreAddBigInt, StoreNew}; - -use substreams::key; -use substreams::scalar::BigInt; - -use substreams_ethereum::pb::eth; -use substreams_ethereum::pb::eth::v2::{Call, Log}; -use substreams_ethereum::{Event, Function}; - -use itertools::Itertools; -use pb::tycho::evm::v1::{self as tycho}; - mod abi; +mod contract_changes; +mod modules; mod pb; - -const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); - -/// This trait defines some helpers for serializing and deserializing `Vec Vec; - fn deserialize_bytes(bytes: &[u8]) -> Vec; -} - -impl SerializableVecBigInt for Vec { - fn serialize_bytes(&self) -> Vec { - self.iter() - .flat_map(|big_int| big_int.to_signed_bytes_be()) - .collect() - } - fn deserialize_bytes(bytes: &[u8]) -> Vec { - bytes - .chunks_exact(32) - .map(|chunk| BigInt::from_signed_bytes_be(chunk)) - .collect::>() - } -} - -/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in -/// a later groupby operation. -struct TransactionWrapper(tycho::Transaction); - -impl PartialEq for TransactionWrapper { - fn eq(&self, other: &Self) -> bool { - self.0.hash == other.0.hash - } -} - -/// This is the main function that handles the creation of `ProtocolComponent`s with `Attribute`s -/// based on the specific factory address. There's 3 factory groups that are represented here: -/// - Weighted Pool Factories -/// - Linear Pool Factories -/// - Stable Pool Factories -/// (Balancer does have a bit more (esp. in the deprecated section) that could be implemented as -/// desired.) -/// We use the specific ABIs to decode both the log event and cooresponding call to gather -/// `PoolCreated` event information alongside the `Create` calldata that provide us details to -/// fufill both the required details + any extra `Attributes` -/// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html -fn pool_factory_map(pool_addr: &[u8], log: &Log, call: &Call) -> Option { - match *pool_addr { - hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { - let create_call = - abi::weighted_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::weighted_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "WeightedPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "normalized_weights".into(), - value: create_call.normalized_weights.serialize_bytes(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { - let create_call = - abi::composable_stable_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::composable_stable_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "ComposableStablePoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "amplification_parameter".into(), - value: create_call.amplification_parameter.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { - let create_call = - abi::erc_linear_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::erc_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "ERC4626LinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - // Note, `lower_target` is generally hardcoded for all pools, not located in call data - // Note, rate provider might be provided as `create.protocol_id`, but as a BigInt. needs investigation - ], - change: tycho::ChangeType::Creation.into(), - }) - } - hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { - let create_call = - abi::euler_linear_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::euler_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "EulerLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - hex!("39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B") => { - let create_call = - abi::gearbox_linear_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::gearbox_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "GearboxLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - // The `ManagedPoolFactory` is a bit ✨ unique ✨, so we'll leave it commented out for now - // Take a look at it's `Create` call to see how the params are structured. - // hex!("BF904F9F340745B4f0c4702c7B6Ab1e808eA6b93") => { - // let create_call = abi::managed_pool_factory::functions::Create::match_and_decode(call)?; - // let pool_created = - // abi::managed_pool_factory::events::PoolCreated::match_and_decode(log)?; - - // Some(tycho::ProtocolComponent { - // id: hex::encode(&pool_created.pool), - // tokens: create_call.tokens, - // contracts: vec![pool_addr.into(), pool_created.pool], - // static_att: vec![ - // tycho::Attribute { - // name: "pool_type".into(), - // value: "ManagedPoolFactory".into(), - // change: tycho::ChangeType::Creation.into(), - // }, - // tycho::Attribute { - // name: "swap_fee_percentage".into(), - // value: create_call.swap_fee_percentage.to_signed_bytes_be(), - // change: tycho::ChangeType::Creation.into(), - // }, - // ], - // change: tycho::ChangeType::Creation.into(), - // }) - // } - hex!("4E11AEec21baF1660b1a46472963cB3DA7811C89") => { - let create_call = - abi::silo_linear_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::silo_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "SiloLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { - let create_call = - abi::yearn_linear_pool_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::yearn_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "YearnLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - // The `WeightedPool2TokenFactory` is a deprecated contract but we've included it since one - // of the highest TVL pools, 80BAL-20WETH, is able to be tracked. - hex!("A5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0") => { - let create_call = - abi::weighted_pool_tokens_factory::functions::Create::match_and_decode(call)?; - let pool_created = - abi::weighted_pool_tokens_factory::events::PoolCreated::match_and_decode(log)?; - - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "WeightedPool2TokensFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "swap_fee_percentage".into(), - value: create_call.swap_fee_percentage.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - // TODO - tycho::Attribute { - name: "weights".into(), - value: create_call.weights.serialize_bytes(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - }) - } - _ => None, - } -} - -/// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a -/// store to be able to tally up final balances for tokens in a pool. -#[substreams::handlers::map] -pub fn map_balance_deltas(block: eth::v2::Block) -> Result { - Ok(tycho::BalanceDeltas { - balance_deltas: block - .events::(&[&VAULT_ADDRESS]) - .flat_map(|(event, log)| { - event - .tokens - .iter() - .zip(event.deltas.iter()) - .map(|(token, delta)| tycho::BalanceDelta { - ord: log.log.ordinal, - tx: Some(tycho::Transaction { - hash: log.receipt.transaction.hash.clone(), - from: log.receipt.transaction.from.clone(), - to: log.receipt.transaction.to.clone(), - index: Into::::into(log.receipt.transaction.index), - }), - token: token.clone(), - delta: delta.to_signed_bytes_be(), - component_id: event.pool_id.into(), - }) - .collect::>() - }) - .collect::>(), - }) -} - -/// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the -/// store key to ensure that there's a unique balance being tallied for each. -#[substreams::handlers::store] -pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt) { - deltas.balance_deltas.iter().for_each(|delta| { - store.add( - delta.ord, - format!( - "pool:{0}:token:{1}", - hex::encode(&delta.component_id), - hex::encode(&delta.token) - ), - BigInt::from_signed_bytes_be(&delta.delta), - ); - }); -} - -/// This is the main map that handles most of the indexing of this substream. -#[substreams::handlers::map] -pub fn map_changes( - block: eth::v2::Block, - deltas: tycho::BalanceDeltas, - store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. -) -> Result { - // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call - // We store these as a hashmap by tx hash since we need to agg by tx hash later - let mut transaction_contract_changes = block - .transactions() - .flat_map(|tx| { - tx.logs_with_calls() - .filter(|(_, call)| !call.call.state_reverted) - .filter_map(|(log, call)| { - let pool_factory_address = call.call.address.as_slice(); - - Some(( - tx.hash.clone(), - tycho::TransactionContractChanges { - tx: Some(tycho::Transaction { - hash: tx.hash.clone(), - from: tx.from.clone(), - to: tx.to.clone(), - index: Into::::into(tx.index), - }), - contract_changes: vec![], - balance_changes: vec![], - component_changes: vec![pool_factory_map( - pool_factory_address, - log, - call.call, - )?], - }, - )) - }) - }) - .collect::>(); - - // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating `BalanceDeltas` - // We essentially just process the changes that occured to the `store` this block - // Then, these balance changes are merged onto the existing map of tx contract changes, - // inserting a new one if it doesn't exist. - store - .deltas - .into_iter() - .zip(deltas.balance_deltas) - .map(|(store_delta, balance_delta)| { - let pool_id = key::segment_at(&store_delta.key, 1); - let token_id = key::segment_at(&store_delta.key, 3); - ( - balance_delta.tx.unwrap(), - tycho::BalanceChange { - token: hex::decode(token_id).expect("Token ID not valid hex"), - balance: store_delta.new_value, - component_id: hex::decode(pool_id).expect("Token ID not valid hex"), - }, - ) - }) - // We need to group the balance changes by tx hash for the `TransactionContractChanges` agg - .group_by(|(tx, _)| TransactionWrapper(tx.clone())) - .into_iter() - .for_each(|(tx_wrapped, group)| { - let tx = tx_wrapped.0; - - if let Some(tx_change) = transaction_contract_changes.get_mut(&tx.hash) { - tx_change - .balance_changes - .extend(group.map(|(_, change)| change.clone())); - } else { - transaction_contract_changes.insert( - tx.hash.clone(), - tycho::TransactionContractChanges { - tx: Some(tx), - contract_changes: vec![], - component_changes: vec![], - balance_changes: group - .map(|(_, change)| change.clone()) - .collect::>(), - }, - ); - } - }); - - Ok(tycho::BlockContractChanges { - block: Some(tycho::Block { - number: block.number, - hash: block.hash.clone(), - parent_hash: block - .header - .as_ref() - .expect("Block header not present") - .parent_hash - .clone(), - ts: block.timestamp_seconds(), - }), - changes: transaction_contract_changes - .into_values() - .sorted_unstable_by_key(|tx_change| tx_change.tx.clone().unwrap().index) - .collect::>(), - }) -} +mod pool_factories; diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs new file mode 100644 index 0000000..7471c36 --- /dev/null +++ b/substreams/ethereum-balancer/src/modules.rs @@ -0,0 +1,239 @@ +use std::collections::HashMap; + +use anyhow::Result; +use substreams::hex; +use substreams::pb::substreams::StoreDeltas; +use substreams::store::{ + StoreAdd, StoreAddBigInt, StoreAddInt64, StoreGet, StoreGetInt64, StoreNew, +}; + +use substreams::key; +use substreams::scalar::BigInt; + +use substreams_ethereum::pb::eth; + +use itertools::Itertools; +use pb::tycho::evm::v1::{self as tycho}; + +use contract_changes::extract_contract_changes; + +use crate::{abi, contract_changes, pb, pool_factories}; + +const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); + +/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in +/// a later groupby operation. +#[derive(Debug)] +struct TransactionWrapper(tycho::Transaction); + +impl PartialEq for TransactionWrapper { + fn eq(&self, other: &Self) -> bool { + self.0.hash == other.0.hash + } +} + +#[substreams::handlers::map] +pub fn map_pools_created( + block: eth::v2::Block, +) -> Result { + // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call + // We store these as a hashmap by tx hash since we need to agg by tx hash later + Ok(tycho::GroupedTransactionProtocolComponents { + tx_components: block + .transactions() + .map(|tx| tycho::TransactionProtocolComponents { + tx: Some(tycho::Transaction { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: Into::::into(tx.index), + }), + components: tx + .logs_with_calls() + .filter(|(_, call)| !call.call.state_reverted) + .filter_map(|(log, call)| { + Some(pool_factories::address_map( + call.call.address.as_slice(), + log, + call.call, + )?) + }) + .collect::>(), + }) + .collect::>(), + }) +} + +/// Simply stores the `ProtocolComponent`s with the pool id as the key +#[substreams::handlers::store] +pub fn store_pools_created(map: tycho::GroupedTransactionProtocolComponents, store: StoreAddInt64) { + store.add_many( + 0, + &map.tx_components + .iter() + .flat_map(|tx_components| &tx_components.components) + .map(|component| format!("pool:{0}", component.id)) + .collect::>(), + 1, + ); +} + +/// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a +/// store to be able to tally up final balances for tokens in a pool. +#[substreams::handlers::map] +pub fn map_balance_deltas(block: eth::v2::Block) -> Result { + Ok(tycho::BalanceDeltas { + balance_deltas: block + .events::(&[&VAULT_ADDRESS]) + .flat_map(|(event, log)| { + event + .tokens + .iter() + .zip(event.deltas.iter()) + .map(|(token, delta)| tycho::BalanceDelta { + ord: log.log.ordinal, + tx: Some(tycho::Transaction { + hash: log.receipt.transaction.hash.clone(), + from: log.receipt.transaction.from.clone(), + to: log.receipt.transaction.to.clone(), + index: Into::::into(log.receipt.transaction.index), + }), + token: token.clone(), + delta: delta.to_signed_bytes_be(), + component_id: event.pool_id.into(), + }) + .collect::>() + }) + .collect::>(), + }) +} + +/// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the +/// store key to ensure that there's a unique balance being tallied for each. +#[substreams::handlers::store] +pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt) { + deltas.balance_deltas.iter().for_each(|delta| { + store.add( + delta.ord, + format!( + "pool:{0}:token:{1}", + hex::encode(&delta.component_id), + hex::encode(&delta.token) + ), + BigInt::from_signed_bytes_be(&delta.delta), + ); + }); +} + +/// This is the main map that handles most of the indexing of this substream. +/// Every contract change is grouped by transaction index via the `transaction_contract_changes` +/// map. Each block of code will extend the `TransactionContractChanges` struct with the +/// cooresponding changes (balance, component, contract), inserting a new one if it doesn't exist. +/// At the very end, the map can easily be sorted by index to ensure the final `BlockContractChanges` +/// is ordered by transactions properly. +#[substreams::handlers::map] +pub fn map_changes( + block: eth::v2::Block, + grouped_components: tycho::GroupedTransactionProtocolComponents, + deltas: tycho::BalanceDeltas, + components_store: StoreGetInt64, + balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. +) -> Result { + // We merge contract changes by transaction (identified by transaction index) making it easy to + // sort them at the very end. + let mut transaction_contract_changes: HashMap<_, tycho::TransactionContractChanges> = + HashMap::new(); + + // `ProtocolComponents` are gathered from `map_pools_created` which just need a bit of work to + // convert into `TransactionContractChanges` + grouped_components + .tx_components + .iter() + .for_each(|tx_component| { + let tx = tx_component.tx.as_ref().unwrap(); + + transaction_contract_changes + .entry(tx.index) + .or_insert_with(|| tycho::TransactionContractChanges { + tx: Some(tx.clone()), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + }) + .component_changes + .extend_from_slice(&tx_component.components); + }); + + // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating + // `BalanceDeltas`. We essentially just process the changes that occured to the `store` this + // block. Then, these balance changes are merged onto the existing map of tx contract changes, + // inserting a new one if it doesn't exist. + balance_store + .deltas + .into_iter() + .zip(deltas.balance_deltas) + .map(|(store_delta, balance_delta)| { + let pool_id = key::segment_at(&store_delta.key, 1); + let token_id = key::segment_at(&store_delta.key, 3); + ( + balance_delta.tx.unwrap(), + tycho::BalanceChange { + token: hex::decode(token_id).expect("Token ID not valid hex"), + balance: store_delta.new_value, + component_id: hex::decode(pool_id).expect("Token ID not valid hex"), + }, + ) + }) + // We need to group the balance changes by tx hash for the `TransactionContractChanges` agg + .group_by(|(tx, _)| TransactionWrapper(tx.clone())) + .into_iter() + .for_each(|(tx_wrapped, group)| { + let tx = tx_wrapped.0; + + transaction_contract_changes + .entry(tx.index) + .or_insert_with(|| tycho::TransactionContractChanges { + tx: Some(tx.clone()), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + }) + .balance_changes + .extend(group.map(|(_, change)| change)); + }); + + // General helper for extracting contract changes. Uses block, our component store which holds + // all of our tracked deployed pool addresses, and the map of tx contract changes which we + // output into for final processing later. + extract_contract_changes(&block, components_store, &mut transaction_contract_changes); + + // Process all `transaction_contract_changes` for final output in the `BlockContractChanges`, + // sorted by transaction index (the key). + Ok(tycho::BlockContractChanges { + block: Some(tycho::Block { + number: block.number, + hash: block.hash.clone(), + parent_hash: block + .header + .as_ref() + .expect("Block header not present") + .parent_hash + .clone(), + ts: block.timestamp_seconds(), + }), + changes: transaction_contract_changes + .drain() + .sorted_unstable_by_key(|(index, _)| index.clone()) + .filter_map(|(_, change)| { + if change.contract_changes.is_empty() + && change.component_changes.is_empty() + && change.balance_changes.is_empty() + { + None + } else { + Some(change) + } + }) + .collect::>(), + }) +} diff --git a/substreams/ethereum-balancer/src/pb/mod.rs b/substreams/ethereum-balancer/src/pb/mod.rs index abb6b01..43d8838 100644 --- a/substreams/ethereum-balancer/src/pb/mod.rs +++ b/substreams/ethereum-balancer/src/pb/mod.rs @@ -1,3 +1,4 @@ +// @generated pub mod tycho { pub mod evm { // @@protoc_insertion_point(attribute:tycho.evm.v1) diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs index a2c781a..affc411 100644 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -32,6 +32,7 @@ pub struct Transaction { #[prost(bytes="vec", tag="3")] pub to: ::prost::alloc::vec::Vec, /// The transactions index within the block. + /// TODO: should this be uint32? to match the type from the native substream type? #[prost(uint64, tag="4")] pub index: u64, } @@ -80,10 +81,18 @@ pub struct ProtocolComponent { } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProtocolComponents { - #[prost(message, repeated, tag="1")] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] pub components: ::prost::alloc::vec::Vec, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GroupedTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} /// A struct for following the changes of Total Value Locked (TVL) of a protocol component. /// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. /// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. @@ -129,14 +138,6 @@ pub struct BalanceDeltas { #[prost(message, repeated, tag="1")] pub balance_deltas: ::prost::alloc::vec::Vec, } -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockBalanceChanges { - #[prost(message, optional, tag="1")] - pub block: ::core::option::Option, - #[prost(message, repeated, tag="2")] - pub balance_changes: ::prost::alloc::vec::Vec, -} /// Enum to specify the type of a change. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs new file mode 100644 index 0000000..0956103 --- /dev/null +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -0,0 +1,273 @@ +use substreams_ethereum::pb::eth::v2::{Call, Log}; +use substreams_ethereum::{Event, Function}; + +use crate::abi; +use crate::pb; +use pb::tycho::evm::v1::{self as tycho}; +use substreams::hex; + +use substreams::scalar::BigInt; + +/// This trait defines some helpers for serializing and deserializing `Vec Vec; + fn deserialize_bytes(bytes: &[u8]) -> Vec; +} + +impl SerializableVecBigInt for Vec { + fn serialize_bytes(&self) -> Vec { + self.iter() + .flat_map(|big_int| big_int.to_signed_bytes_be()) + .collect() + } + fn deserialize_bytes(bytes: &[u8]) -> Vec { + bytes + .chunks_exact(32) + .map(|chunk| BigInt::from_signed_bytes_be(chunk)) + .collect::>() + } +} + +/// This is the main function that handles the creation of `ProtocolComponent`s with `Attribute`s +/// based on the specific factory address. There's 3 factory groups that are represented here: +/// - Weighted Pool Factories +/// - Linear Pool Factories +/// - Stable Pool Factories +/// (Balancer does have a bit more (esp. in the deprecated section) that could be implemented as +/// desired.) +/// We use the specific ABIs to decode both the log event and cooresponding call to gather +/// `PoolCreated` event information alongside the `Create` calldata that provide us details to +/// fufill both the required details + any extra `Attributes` +/// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html +pub fn address_map( + pool_addr: &[u8], + log: &Log, + call: &Call, +) -> Option { + match *pool_addr { + hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { + let create_call = + abi::weighted_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::weighted_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "WeightedPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "normalized_weights".into(), + value: create_call.normalized_weights.serialize_bytes(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { + let create_call = + abi::composable_stable_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::composable_stable_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "ComposableStablePoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { + let create_call = + abi::erc_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::erc_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "ERC4626LinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + // Note, `lower_target` is generally hardcoded for all pools, not located in call data + // Note, rate provider might be provided as `create.protocol_id`, but as a BigInt. needs investigation + ], + change: tycho::ChangeType::Creation.into(), + }) + } + hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { + let create_call = + abi::euler_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::euler_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "EulerLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + // ❌ Reading the deployed factory for Gearbox showcases that it's currently disabled + // hex!("39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B") => { + // let create_call = + // abi::gearbox_linear_pool_factory::functions::Create::match_and_decode(call)?; + // let pool_created = + // abi::gearbox_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + // Some(tycho::ProtocolComponent { + // id: hex::encode(&pool_created.pool), + // tokens: vec![create_call.main_token, create_call.wrapped_token], + // contracts: vec![pool_addr.into(), pool_created.pool], + // static_att: vec![ + // tycho::Attribute { + // name: "pool_type".into(), + // value: "GearboxLinearPoolFactory".into(), + // change: tycho::ChangeType::Creation.into(), + // }, + // tycho::Attribute { + // name: "upper_target".into(), + // value: create_call.upper_target.to_signed_bytes_be(), + // change: tycho::ChangeType::Creation.into(), + // }, + // ], + // change: tycho::ChangeType::Creation.into(), + // }) + // } + // ❌ The `ManagedPoolFactory` is a bit ✨ unique ✨, so we'll leave it commented out for now + // Take a look at it's `Create` call to see how the params are structured. + // hex!("BF904F9F340745B4f0c4702c7B6Ab1e808eA6b93") => { + // let create_call = abi::managed_pool_factory::functions::Create::match_and_decode(call)?; + // let pool_created = + // abi::managed_pool_factory::events::PoolCreated::match_and_decode(log)?; + + // Some(tycho::ProtocolComponent { + // id: hex::encode(&pool_created.pool), + // tokens: create_call.tokens, + // contracts: vec![pool_addr.into(), pool_created.pool], + // static_att: vec![ + // tycho::Attribute { + // name: "pool_type".into(), + // value: "ManagedPoolFactory".into(), + // change: tycho::ChangeType::Creation.into(), + // }, + // ], + // change: tycho::ChangeType::Creation.into(), + // }) + // } + hex!("4E11AEec21baF1660b1a46472963cB3DA7811C89") => { + let create_call = + abi::silo_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::silo_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "SiloLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { + let create_call = + abi::yearn_linear_pool_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::yearn_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: vec![create_call.main_token, create_call.wrapped_token], + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "YearnLinearPoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "upper_target".into(), + value: create_call.upper_target.to_signed_bytes_be(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + // The `WeightedPool2TokenFactory` is a deprecated contract but we've included it since one + // of the highest TVL pools, 80BAL-20WETH, is able to be tracked. + hex!("A5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0") => { + let create_call = + abi::weighted_pool_tokens_factory::functions::Create::match_and_decode(call)?; + let pool_created = + abi::weighted_pool_tokens_factory::events::PoolCreated::match_and_decode(log)?; + + Some(tycho::ProtocolComponent { + id: hex::encode(&pool_created.pool), + tokens: create_call.tokens, + contracts: vec![pool_addr.into(), pool_created.pool], + static_att: vec![ + tycho::Attribute { + name: "pool_type".into(), + value: "WeightedPool2TokensFactory".into(), + change: tycho::ChangeType::Creation.into(), + }, + tycho::Attribute { + name: "weights".into(), + value: create_call.weights.serialize_bytes(), + change: tycho::ChangeType::Creation.into(), + }, + ], + change: tycho::ChangeType::Creation.into(), + }) + } + _ => None, + } +} diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 98ea7e0..7006218 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -17,6 +17,22 @@ binaries: file: target/wasm32-unknown-unknown/release/substreams_balancer.wasm modules: + - name: map_pools_created + kind: map + initialBlock: 12369300 + inputs: + - source: sf.ethereum.type.v2.Block + output: + type: proto:tycho.evm.v1.GroupedTransactionProtocolComponents + + - name: store_pools_created + kind: store + initialBlock: 12369300 + updatePolicy: add + valueType: int64 + inputs: + - map: map_pools_created + - name: map_balance_deltas kind: map initialBlock: 12369300 # An arbitrary block that should change based on your requirements @@ -38,7 +54,9 @@ modules: initialBlock: 12369300 inputs: - source: sf.ethereum.type.v2.Block + - map: map_pools_created - map: map_balance_deltas + - store: store_pools_created - store: store_balance_changes mode: deltas # This is the key property that simplifies `BalanceChange` handling output: From c96eb068d7f15a245a2920598e37193261e0eb75 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Wed, 31 Jan 2024 10:28:41 -0500 Subject: [PATCH 48/86] refactor: adjust naming --- .../ethereum-balancer/src/pool_factories.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index 0956103..62f1601 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -42,11 +42,11 @@ impl SerializableVecBigInt for Vec { /// fufill both the required details + any extra `Attributes` /// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html pub fn address_map( - pool_addr: &[u8], + pool_factory_address: &[u8], log: &Log, call: &Call, ) -> Option { - match *pool_addr { + match *pool_factory_address { hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { let create_call = abi::weighted_pool_factory::functions::Create::match_and_decode(call)?; @@ -56,7 +56,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -81,7 +81,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -101,7 +101,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -128,7 +128,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -200,7 +200,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -225,7 +225,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -252,7 +252,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_addr.into(), pool_created.pool], + contracts: vec![pool_factory_address.into(), pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), From e7b458cc01659ff1014abca618e8debee22f0076 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Thu, 1 Feb 2024 09:36:26 -0500 Subject: [PATCH 49/86] feat: remove `requests` as a dep for `get_abis.py` script and add docs --- substreams/ethereum-balancer/abi/README.md | 13 +++++++++++++ substreams/ethereum-balancer/abi/get_abis.py | 16 +++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/substreams/ethereum-balancer/abi/README.md b/substreams/ethereum-balancer/abi/README.md index 862e872..bcb5ddc 100644 --- a/substreams/ethereum-balancer/abi/README.md +++ b/substreams/ethereum-balancer/abi/README.md @@ -7,3 +7,16 @@ We then can define all of the abis via `substreams_ethereum::Abigen::new` in our ## Recommendation It would be apt to convert (maybe through copilot) the python code into the `build.rs` file and then automate the `Abigen` functionality. + +## Usage + +Requires `python 3.8+`, + +```bash +cd abi +python get_abis.py +``` + +This will populate the files in the `abi` folder. + +When the `build.rs` file runs (when `rust-analyzer` activates or `cargo build` is manually ran), Abigen will generate new rust src files from the abis in the `src/abi` folder. diff --git a/substreams/ethereum-balancer/abi/get_abis.py b/substreams/ethereum-balancer/abi/get_abis.py index 6b941e8..6935391 100644 --- a/substreams/ethereum-balancer/abi/get_abis.py +++ b/substreams/ethereum-balancer/abi/get_abis.py @@ -3,8 +3,7 @@ import json import os import re import time - -import requests +import urllib.request # Exports contract ABI in JSON @@ -38,13 +37,12 @@ def __main__(): print(f"Getting ABI for {name} at {addr} ({normalized_name})") try: - ... - response = requests.get(ABI_ENDPOINT.format(address=addr)) - response_json = response.json() - abi_json = json.loads(response_json["result"]) - result = json.dumps(abi_json, indent=4, sort_keys=True) - with open(f"{normalized_name}.json", "w") as f: - f.write(result) + with urllib.request.urlopen(ABI_ENDPOINT.format(address=addr)) as response: + response_json = json.loads(response.read().decode()) + abi_json = json.loads(response_json["result"]) + result = json.dumps(abi_json, indent=4, sort_keys=True) + with open(f"{normalized_name}.json", "w") as f: + f.write(result) except Exception as err: print(response.content) raise err From 0a031d8bf5dec8001eb9b6a4f44f1bed315bd873 Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Thu, 1 Feb 2024 13:52:02 -0500 Subject: [PATCH 50/86] fix: prune empty transaction protocol component groups from `map_pools_created` --- substreams/ethereum-balancer/src/modules.rs | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 7471c36..0bc9aed 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -41,14 +41,8 @@ pub fn map_pools_created( Ok(tycho::GroupedTransactionProtocolComponents { tx_components: block .transactions() - .map(|tx| tycho::TransactionProtocolComponents { - tx: Some(tycho::Transaction { - hash: tx.hash.clone(), - from: tx.from.clone(), - to: tx.to.clone(), - index: Into::::into(tx.index), - }), - components: tx + .filter_map(|tx| { + let components = tx .logs_with_calls() .filter(|(_, call)| !call.call.state_reverted) .filter_map(|(log, call)| { @@ -58,7 +52,21 @@ pub fn map_pools_created( call.call, )?) }) - .collect::>(), + .collect::>(); + + if !components.is_empty() { + Some(tycho::TransactionProtocolComponents { + tx: Some(tycho::Transaction { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: Into::::into(tx.index), + }), + components, + }) + } else { + None + } }) .collect::>(), }) From 10f2e04c02d1acf202b3ead9c2be09989fc5cc4b Mon Sep 17 00:00:00 2001 From: 0xMochan Date: Mon, 5 Feb 2024 13:58:25 -0500 Subject: [PATCH 51/86] fix: only emit balance changes if the component is tracked --- substreams/ethereum-balancer/src/modules.rs | 38 +++++++++++++------- substreams/ethereum-balancer/substreams.yaml | 1 + 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 0bc9aed..2ac0f0e 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -89,7 +89,10 @@ pub fn store_pools_created(map: tycho::GroupedTransactionProtocolComponents, sto /// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a /// store to be able to tally up final balances for tokens in a pool. #[substreams::handlers::map] -pub fn map_balance_deltas(block: eth::v2::Block) -> Result { +pub fn map_balance_deltas( + block: eth::v2::Block, + store: StoreGetInt64, +) -> Result { Ok(tycho::BalanceDeltas { balance_deltas: block .events::(&[&VAULT_ADDRESS]) @@ -98,17 +101,28 @@ pub fn map_balance_deltas(block: eth::v2::Block) -> Result::into(log.receipt.transaction.index), - }), - token: token.clone(), - delta: delta.to_signed_bytes_be(), - component_id: event.pool_id.into(), + .filter_map(|(token, delta)| { + let component_id: Vec<_> = event.pool_id.into(); + + if store + .get_last(format!("pool:{0}", hex::encode(&component_id))) + .is_none() + { + return None; + } + + Some(tycho::BalanceDelta { + ord: log.log.ordinal, + tx: Some(tycho::Transaction { + hash: log.receipt.transaction.hash.clone(), + from: log.receipt.transaction.from.clone(), + to: log.receipt.transaction.to.clone(), + index: Into::::into(log.receipt.transaction.index), + }), + token: token.clone(), + delta: delta.to_signed_bytes_be(), + component_id: component_id.clone(), + }) }) .collect::>() }) diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 7006218..6324d2b 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -38,6 +38,7 @@ modules: initialBlock: 12369300 # An arbitrary block that should change based on your requirements inputs: - source: sf.ethereum.type.v2.Block + - store: store_pools_created output: type: proto:tycho.evm.v1.BalanceDeltas From 58c56e2287003f1a834dc4f1fc78ce73dc83bdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20H=C3=B6ng?= Date: Wed, 21 Feb 2024 15:48:49 +0000 Subject: [PATCH 52/86] GITBOOK-6: Start documenting substreams integrations --- docs/SUMMARY.md | 3 +- docs/indexing/substreams-integration.md | 141 ++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 docs/indexing/substreams-integration.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 1e70a1c..64e1431 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -10,5 +10,4 @@ ## Indexing -* [Substreams Integration](indexing/substreams-integration/README.md) - * [Tutorial: Ambient](indexing/substreams-integration/tutorial-ambient.md) +* [Substreams Integration](indexing/substreams-integration.md) diff --git a/docs/indexing/substreams-integration.md b/docs/indexing/substreams-integration.md new file mode 100644 index 0000000..0bbb12e --- /dev/null +++ b/docs/indexing/substreams-integration.md @@ -0,0 +1,141 @@ +# Substreams Integration + +This page describes the data model required to ingest protocol state into the PropellerHeads solver. + +To integrate a protocol PropellerHeads rely on either native or vm logic. Most integration will likely choose to use the VM, as this is usually less effort, the guide will focus mostly on providing state for vm integrations. + +Native integration should operate following exactly the same pattern, just that they should emit changed attributes instead of changes contract storage slots. + +### Understanding the Data Model + +PropellerHeads ingest all data versioned by block and transaction. This helps maintain a low latency feed and deal correctly with chains that can experience reverts. + +This means each state change that is communicated must be communicated with its respective transaction that caused the change. + +Next, for each emitted transactions that carries state changes, the corresponding block must be provided as well. + +So basically when processing a block we need to emit the block itself, all transactions that introduced protocol state changes and last but not least the state changes themselves, associated to their corresponding transaction. + +**The data model that encodes changes, transaction and blocks in messages, can be found** [**here**](https://github.com/propeller-heads/propeller-protocol-lib/tree/main/proto/tycho/evm/v1)**.** + +#### Common Models + +The following models are shared for both vm and native integrations. + +{% @github-files/github-code-block url="https://github.com/propeller-heads/propeller-protocol-lib/blob/main/proto/tycho/evm/v1/common.proto" %} + +#### VM Specific Models + +The models shown below are specific to vm integrations: + +{% @github-files/github-code-block url="https://github.com/propeller-heads/propeller-protocol-lib/blob/main/proto/tycho/evm/v1/vm.proto" %} + +Please be aware that changes need to be aggregated on the transaction level, it is considered an error to emit `BlockContractChanges` with duplicated transactions present in the `changes` attributes. + +All attributes are expected to be set in the final message unless the docs (in the comments) indicate otherwise. + +#### Native Integration Models + +The models below are very similar to the vm integration models but have a few modifications necessary to support native integrations. + +{% @github-files/github-code-block url="https://github.com/propeller-heads/propeller-protocol-lib/blob/main/proto/tycho/evm/v1/entity.proto" %} + +Once again changes must be aggregated on a transaction level, emitting these models with duplicated transaction as the final output would be considered an error. + +### Changes of interest + +PropellerHeads integration should at least communicate the following changes: + +* Any changes to the protocol state, for VM integrations that usually means contract storage changes of all contracts whose state may be accessed during a swap operation. +* Any newly added protocol component such as a pool, pair, market, etc. Basically anything that signifies that a new operation can be executed now using the protocol. +* ERC20 Balances, whenever the balances of one contracts involved with the protocol change, this change should be communicated in terms of absolute balances. + +In the next section we will show a few common techniques that can be leveraged to quickly implement an integration. + +### How to Integrate + +Before starting, it is important to be aware of the protocol we are aiming to integrate functions. + +It is especially important to know: + +* Which contracts are involved in the protocol and what functions do they serve. How do they affect the behaviour of the component being integrated? +* What conditions (e.g. oracle update) or what kind of method calls can lead to a relevant state change on the protocol, which ultimately changes the protocols behaviour if observed externally. +* Are there components added or removed, and how are they added. Most protocols use either a factory contract, which can be used to deploy new components, or they use a method call that provisiona a new component within the overall system. + +Once the workings of the protocol are clear the implementation can start. + +#### Setup + +PropellerHeads indexing integrations are provided as [substreams](https://substreams.streamingfast.io/) skpg files. If you do not know substreams yet, make sure to go check them out and set up their [cli](https://substreams.streamingfast.io/documentation/consume/installing-the-cli) before continuing. + +Please start a new package for your integration, by copying the `ethereum-template` to a new name. The convention is: `[CHAIN]-[PROTOCOL_SYSTEM]` please make sure to also adjust: `cargo.toml` as well as `substreams.yaml` accordingly. + +It should be possible now to generate the necessary protobuf code: + +``` +substreams protogen substreams.yaml --exclude-paths="sf/substreams,google" +``` + +You are ready to start coding. Please refer to the substreams documentation for more information on the available tools such as handlers and stores. + +#### Tracking Components + +Usually the first step consists in detecting the creation of new components and store their contract addresses in a store, so they can be properly tracked further downstream. + +Later we'll have to emit balance and state changes based on the set of currently tracked components. + +{% hint style="info" %} +Note that emitting state changes of components that have not been previously announced is considered an error. +{% endhint %} + +Newly created components are detected by mapping over the `sf.ethereum.type.v2.Block model`. + +The output message should usually contain as much information about the component available at that time as well as the transaction that created the protocol component. + +We have found that using the final model prefilled with only component changes is usually good enough since it holds all the information that will be necessary at the end. + +For VM Integrations the final model is `BlockContractChanges`: + +```protobuf +// A set of changes aggregated by transaction. +message TransactionContractChanges { + // The transaction instance that results in the changes. + Transaction tx = 1; + // Contains the changes induced by the above transaction, aggregated on a per-contract basis. + // Must include changes to every contract that is tracked by all ProtocolComponents. + repeated ContractChange contract_changes = 2; + // An array of any component changes. + repeated ProtocolComponent component_changes = 3; + // An array of balance changes to components. + repeated BalanceChange balance_changes = 4; +} + +// A set of transaction changes within a single block. +message BlockContractChanges { + // The block for which these changes are collectively computed. + Block block = 1; + // The set of transaction changes observed in the specified block. + repeated TransactionContractChanges changes = 2; +} +``` + +Note that a single transaction may emit multiple newly created components. In this case it is expected that the `TransactionContractChanges.component_changes`, contains multiple `ProtocolComponents`. + +Once emitted, the protocol components should be stored in a Store, since we will later have to use this store to decide whether a contract is interesting to us or not. + +#### Tracking Absolute Balances + +Tracking balances can be tricky since often balance information is only available in relative values. + +This means the relative values have to be aggregated by component, to arrive at an absolute value. Additionally throughout this aggregation we need to track the balance change inducing transaction. + +Since this is challenging the following approach is recommended: + +* Use a handler to process a block and emit the `BalanceDeltas` struct. Make sure to sort the balance deltas by `component_id, token_address` +* Aggregate the BalanceDelta messages using a `BigIntAddStore`. +* In a final handler, use as inputs: A `DeltaStore` input from step 2 and the `BalanceDeltas` from step 1. You can now zip the deltas from the store with the balance deltas from step 1. The store deltas contains the aggregated (absolute) balance at each version and the balance deltas contain the corresponding transaction. + +#### Tracking State Changes + +To track contract changes, you can simply use the `extract_contract_changes` function (see balancer implementation). This function will extract all relevant contract storage changes given the full block model and a store that flags contract addresses as relevant. + From be9ce6ffc1cca6a5d1acdc52bc5b6b5c0f200a1f Mon Sep 17 00:00:00 2001 From: domenicodev Date: Thu, 22 Feb 2024 18:38:12 +0100 Subject: [PATCH 53/86] fix: Fixed trade price in swap function for UniswapV2Adapter --- evm/src/uniswap-v2/UniswapV2SwapAdapter.sol | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/evm/src/uniswap-v2/UniswapV2SwapAdapter.sol b/evm/src/uniswap-v2/UniswapV2SwapAdapter.sol index cd07683..16a1673 100644 --- a/evm/src/uniswap-v2/UniswapV2SwapAdapter.sol +++ b/evm/src/uniswap-v2/UniswapV2SwapAdapter.sol @@ -87,7 +87,12 @@ contract UniswapV2SwapAdapter is ISwapAdapter { buy(pair, sellToken, zero2one, r0, r1, specifiedAmount); } trade.gasUsed = gasBefore - gasleft(); - trade.price = getPriceAt(specifiedAmount, r0, r1); + if(side == OrderSide.Sell) { + trade.price = getPriceAt(specifiedAmount, r0, r1); + } + else { + trade.price = getPriceAt(trade.calculatedAmount, r0, r1); + } } /// @notice Executes a sell order on a given pool. From b3909a414040a102a8307bc25f977c3086c91e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alan=20H=C3=B6ng?= Date: Thu, 7 Mar 2024 10:08:36 +0000 Subject: [PATCH 54/86] GITBOOK-7: Specify byte encoding rules --- docs/indexing/substreams-integration.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/indexing/substreams-integration.md b/docs/indexing/substreams-integration.md index 0bbb12e..5572939 100644 --- a/docs/indexing/substreams-integration.md +++ b/docs/indexing/substreams-integration.md @@ -42,6 +42,18 @@ The models below are very similar to the vm integration models but have a few mo Once again changes must be aggregated on a transaction level, emitting these models with duplicated transaction as the final output would be considered an error. +#### Integer Byte encoding + +Many of the types above are variable length bytes. This allows for flexibility across blockchains but require agreeing on an informal interface, so later applications know how to interpret these bytes. + +**Integers:** especially integers used to communicate balances, should always be encoded as unsigned big-endian integer. This is simply because balances serve multiple purposes within the system and need to be decoded in multiple location of the messages journey. + +**Strings**: If you need to store strings, please use utf-8 encoding to store them as bytes. + +**Attributes:** the value encoding for attributes in the native implementation messages is variable. It depends on the use case. Since the attributes are highly dynamic they are only used by the corresponding logic components, so the encoding can be tailored to the logic implementation: E.g. since Rust uses little endian one may choose to use little endian encoding for integers if the native logic module is written in Rust. + + + ### Changes of interest PropellerHeads integration should at least communicate the following changes: From b8d7f6686c7e63d85378bbdec3abdde53f39311d Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:39:07 +0100 Subject: [PATCH 55/86] Fix balancer substream naming --- substreams/Readme.md | 2 +- substreams/ethereum-balancer/Cargo.toml | 4 ++-- substreams/ethereum-balancer/substreams.yaml | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/substreams/Readme.md b/substreams/Readme.md index f4f9aa3..530d858 100644 --- a/substreams/Readme.md +++ b/substreams/Readme.md @@ -47,7 +47,7 @@ The example from the official docs will serve us just well: ```toml [package] -name = "substreams_[CHAIN]_[PROTOCOL_SYSTEM]" +name = "substreams-[CHAIN]-[PROTOCOL_SYSTEM]" version = "0.1.0" edition = "2021" diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml index 795c565..ace53d3 100644 --- a/substreams/ethereum-balancer/Cargo.toml +++ b/substreams/ethereum-balancer/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "substreams-balancer" +name = "substreams-ethereum-balancer" version = "0.1.0" edition = "2021" [lib] -name = "substreams_balancer" +name = "substreams_ethereum_balancer" crate-type = ["cdylib"] [dependencies] diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 6324d2b..f1bc3af 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -1,6 +1,6 @@ specVersion: v0.1.0 package: - name: "substreams_balancer" + name: "substreams_ethereum_balancer" version: v0.1.0 protobuf: @@ -14,7 +14,7 @@ protobuf: binaries: default: type: wasm/rust-v1 - file: target/wasm32-unknown-unknown/release/substreams_balancer.wasm + file: target/wasm32-unknown-unknown/release/substreams_ethereum_balancer.wasm modules: - name: map_pools_created @@ -35,7 +35,7 @@ modules: - name: map_balance_deltas kind: map - initialBlock: 12369300 # An arbitrary block that should change based on your requirements + initialBlock: 12369300 # An arbitrary block that should change based on your requirements inputs: - source: sf.ethereum.type.v2.Block - store: store_pools_created @@ -59,6 +59,6 @@ modules: - map: map_balance_deltas - store: store_pools_created - store: store_balance_changes - mode: deltas # This is the key property that simplifies `BalanceChange` handling + mode: deltas # This is the key property that simplifies `BalanceChange` handling output: type: proto:tycho.evm.v1.BlockContractChanges From 66a048fbe2333c3cdcf17ae4c07914bc565fa07b Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:45:58 +0100 Subject: [PATCH 56/86] refactor: update protobuf messages --- proto/tycho/evm/v1/balancer.proto | 32 ++++ proto/tycho/evm/v1/common.proto | 27 ++- substreams/ethereum-balancer/Cargo.lock | 36 ++-- .../ethereum-balancer/proto/factory.proto | 19 --- substreams/ethereum-balancer/proto/pool.proto | 15 -- .../proto/tycho/evm/v1/common.proto | 113 ------------- .../proto/tycho/evm/v1/entity.proto | 32 ---- .../proto/tycho/evm/v1/vm.proto | 50 ------ substreams/ethereum-balancer/src/modules.rs | 11 +- .../src/pb/eth.balancer.v1.rs | 28 ---- .../src/pb/eth.factory.v1.rs | 28 ---- .../ethereum-balancer/src/pb/eth.pool.v1.rs | 22 --- .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 158 +++++++++++++----- .../ethereum-balancer/src/pool_factories.rs | 66 +++++++- substreams/ethereum-balancer/substreams.yaml | 4 +- 15 files changed, 261 insertions(+), 380 deletions(-) create mode 100644 proto/tycho/evm/v1/balancer.proto delete mode 100644 substreams/ethereum-balancer/proto/factory.proto delete mode 100644 substreams/ethereum-balancer/proto/pool.proto delete mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto delete mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto delete mode 100644 substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto delete mode 100644 substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs delete mode 100644 substreams/ethereum-balancer/src/pb/eth.factory.v1.rs delete mode 100644 substreams/ethereum-balancer/src/pb/eth.pool.v1.rs diff --git a/proto/tycho/evm/v1/balancer.proto b/proto/tycho/evm/v1/balancer.proto new file mode 100644 index 0000000..f5a4c63 --- /dev/null +++ b/proto/tycho/evm/v1/balancer.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +package tycho.evm.v1; + +import "tycho/evm/v1/common.proto"; + +// A struct for following the changes of Total Value Locked (TVL). +message BalanceDelta { + uint64 ord = 1; + // The tx hash of the transaction that caused the balance change. + Transaction tx = 2; + // The address of the ERC20 token whose balance changed. + bytes token = 3; + // The delta balance of the token. + bytes delta = 4; + // The id of the component whose TVL is tracked. + // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + bytes component_id = 5; +} + +message BalanceDeltas { + repeated BalanceDelta balance_deltas = 1; +} + +message TransactionProtocolComponents { + Transaction tx = 1; + repeated ProtocolComponent components = 2; +} + +message GroupedTransactionProtocolComponents { + repeated TransactionProtocolComponents tx_components = 1; +} \ No newline at end of file diff --git a/proto/tycho/evm/v1/common.proto b/proto/tycho/evm/v1/common.proto index d52dbed..545cad0 100644 --- a/proto/tycho/evm/v1/common.proto +++ b/proto/tycho/evm/v1/common.proto @@ -25,6 +25,7 @@ message Transaction { // The receiver of the transaction. bytes to = 3; // The transactions index within the block. + // TODO: should this be uint32? to match the type from the native substream type? uint64 index = 4; } @@ -47,6 +48,26 @@ message Attribute { ChangeType change = 3; } +enum FinancialType{ + SWAP = 0; + LEND = 1; + LEVERAGE = 2; + PSM = 3; +} + + +enum ImplementationType { + VM = 0; + CUSTOM = 1; +} + +message ProtocolType{ + string name = 1; + FinancialType financial_type = 2; + repeated Attribute attribute_schema = 3; + ImplementationType implementation_type = 4; +} + // A struct describing a part of the protocol. // Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, // the component would represent a single contract. In case of VM integration, such component would @@ -67,6 +88,10 @@ message ProtocolComponent { repeated Attribute static_att = 4; // Type of change the component underwent. ChangeType change = 5; + /// Represents the functionality of the component. + ProtocolType protocol_type = 6; + // Transaction where this component was created + Transaction tx = 7; } // A struct for following the changes of Total Value Locked (TVL) of a protocol component. @@ -77,7 +102,7 @@ message BalanceChange { bytes token = 1; // The new balance of the token. bytes balance = 2; - // The id of the component whose TVL is tracked. + // The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. bytes component_id = 3; } diff --git a/substreams/ethereum-balancer/Cargo.lock b/substreams/ethereum-balancer/Cargo.lock index c96455e..b05dce5 100644 --- a/substreams/ethereum-balancer/Cargo.lock +++ b/substreams/ethereum-balancer/Cargo.lock @@ -884,24 +884,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "substreams-balancer" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "ethabi 18.0.0", - "getrandom", - "hex", - "hex-literal 0.4.1", - "itertools 0.12.0", - "num-bigint", - "prost 0.11.9", - "prost-types 0.12.3", - "substreams", - "substreams-ethereum", -] - [[package]] name = "substreams-ethereum" version = "0.9.9" @@ -933,6 +915,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "substreams-ethereum-balancer" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "ethabi 18.0.0", + "getrandom", + "hex", + "hex-literal 0.4.1", + "itertools 0.12.0", + "num-bigint", + "prost 0.11.9", + "prost-types 0.12.3", + "substreams", + "substreams-ethereum", +] + [[package]] name = "substreams-ethereum-core" version = "0.9.9" diff --git a/substreams/ethereum-balancer/proto/factory.proto b/substreams/ethereum-balancer/proto/factory.proto deleted file mode 100644 index f191ea8..0000000 --- a/substreams/ethereum-balancer/proto/factory.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package eth.factory.v1; - -message Pools { - repeated Pool pools = 1; -} - -message Pool { - bytes pool_id = 1; - fixed64 log_ordinal = 2; -} - -message Transfer { - bytes from = 1; - bytes to = 2; - string token = 3; - string amount = 4; -} diff --git a/substreams/ethereum-balancer/proto/pool.proto b/substreams/ethereum-balancer/proto/pool.proto deleted file mode 100644 index c4dd94c..0000000 --- a/substreams/ethereum-balancer/proto/pool.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -package eth.pool.v1; - -message Transfers { - repeated Transfer transfers = 1; -} - -message Transfer { - string from = 1; - string to = 2; - uint64 token_id = 3; - string trx_hash = 4; - uint64 ordinal = 5; -} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto deleted file mode 100644 index 1a5caf4..0000000 --- a/substreams/ethereum-balancer/proto/tycho/evm/v1/common.proto +++ /dev/null @@ -1,113 +0,0 @@ -syntax = "proto3"; - -package tycho.evm.v1; - -// This file contains the proto definitions for Substreams common to all integrations. - -// A struct describing a block. -message Block { - // The blocks hash. - bytes hash = 1; - // The parent blocks hash. - bytes parent_hash = 2; - // The block number. - uint64 number = 3; - // The block timestamp. - uint64 ts = 4; -} - -// A struct describing a transaction. -message Transaction { - // The transaction hash. - bytes hash = 1; - // The sender of the transaction. - bytes from = 2; - // The receiver of the transaction. - bytes to = 3; - // The transactions index within the block. - // TODO: should this be uint32? to match the type from the native substream type? - uint64 index = 4; -} - -// Enum to specify the type of a change. -enum ChangeType { - CHANGE_TYPE_UNSPECIFIED = 0; - CHANGE_TYPE_UPDATE = 1; - CHANGE_TYPE_CREATION = 2; - CHANGE_TYPE_DELETION = 3; -} - -// A custom struct representing an arbitrary attribute of a protocol component. -// This is mainly used by the native integration to track the necessary information about the protocol. -message Attribute { - // The name of the attribute. - string name = 1; - // The value of the attribute. - bytes value = 2; - // The type of change the attribute underwent. - ChangeType change = 3; -} - -// A struct describing a part of the protocol. -// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, -// the component would represent a single contract. In case of VM integration, such component would -// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. -// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. -// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". -message ProtocolComponent { - // A unique identifier for the component within the protocol. - // Can be e.g. a stringified address or a string describing the trading pair. - string id = 1; - // Addresses of the ERC20 tokens used by the component. - repeated bytes tokens = 2; - // Addresses of the contracts used by the component. - // Usually it is a single contract, but some protocols use multiple contracts. - repeated bytes contracts = 3; - // Attributes of the component. Used mainly be the native integration. - // The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. - repeated Attribute static_att = 4; - // Type of change the component underwent. - ChangeType change = 5; -} - -message TransactionProtocolComponents { - Transaction tx = 1; - repeated ProtocolComponent components = 2; -} - -message GroupedTransactionProtocolComponents { - repeated TransactionProtocolComponents tx_components = 1; -} - -// A struct for following the changes of Total Value Locked (TVL) of a protocol component. -// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. -// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. -message BalanceChange { - // The address of the ERC20 token whose balance changed. - bytes token = 1; - // The new balance of the token. - bytes balance = 2; - // The id of the component whose TVL is tracked. - // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - bytes component_id = 3; -} - -// A struct for following the changes of Total Value Locked (TVL) of a protocol component. -// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. -// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. -message BalanceDelta { - uint64 ord = 1; - // The tx hash of the transaction that caused the balance change. - Transaction tx = 2; - // The address of the ERC20 token whose balance changed. - bytes token = 3; - // The delta balance of the token. - bytes delta = 4; - // The id of the component whose TVL is tracked. - // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - bytes component_id = 5; -} - -message BalanceDeltas { - repeated BalanceDelta balance_deltas = 1; -} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto deleted file mode 100644 index 14539e4..0000000 --- a/substreams/ethereum-balancer/proto/tycho/evm/v1/entity.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; - -package tycho.evm.v1; - -import "tycho/evm/v1/common.proto"; - -// This file contains the definition for the native integration of Substreams. - -// A component is a set of attributes that are associated with a custom entity. -message EntityChanges { - // A unique identifier of the entity within the protocol. - string component_id = 1; - // The set of attributes that are associated with the entity. - repeated Attribute attributes = 2; -} - -message TransactionEntityChanges { - Transaction tx = 1; - repeated EntityChanges entity_changes = 2; - // An array of newly added components. - repeated ProtocolComponent component_changes = 3; - // An array of balance changes to components. - repeated BalanceChange balance_changes = 4; -} - -// A set of transaction changes within a single block. -message BlockEntityChanges { - // The block for which these changes are collectively computed. - Block block = 1; - // The set of transaction changes observed in the specified block. - repeated TransactionEntityChanges changes = 2; -} diff --git a/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto b/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto deleted file mode 100644 index a49dcf0..0000000 --- a/substreams/ethereum-balancer/proto/tycho/evm/v1/vm.proto +++ /dev/null @@ -1,50 +0,0 @@ -syntax = "proto3"; - -package tycho.evm.v1; - -import "tycho/evm/v1/common.proto"; - -// This file contains proto definitions specific to the VM integration. - -// A key value entry into contract storage. -message ContractSlot { - // A contract's storage slot. - bytes slot = 2; - // The new value for this storage slot. - bytes value = 3; -} - -// Changes made to a single contract's state. -message ContractChange { - // The contract's address - bytes address = 1; - // The new native balance of the contract, empty bytes indicates no change. - bytes balance = 2; - // The new code of the contract, empty bytes indicates no change. - bytes code = 3; - // The changes to this contract's slots, empty sequence indicates no change. - repeated ContractSlot slots = 4; - // Whether this is an update, a creation or a deletion. - ChangeType change = 5; -} - -// A set of changes aggregated by transaction. -message TransactionContractChanges { - // The transaction instance that results in the changes. - Transaction tx = 1; - // Contains the changes induced by the above transaction, aggregated on a per-contract basis. - // Must include changes to every contract that is tracked by all ProtocolComponents. - repeated ContractChange contract_changes = 2; - // An array of any component changes. - repeated ProtocolComponent component_changes = 3; - // An array of balance changes to components. - repeated BalanceChange balance_changes = 4; -} - -// A set of transaction changes within a single block. -message BlockContractChanges { - // The block for which these changes are collectively computed. - Block block = 1; - // The set of transaction changes observed in the specified block. - repeated TransactionContractChanges changes = 2; -} diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 2ac0f0e..d121c2d 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -17,6 +17,7 @@ use pb::tycho::evm::v1::{self as tycho}; use contract_changes::extract_contract_changes; +use crate::pb::tycho::evm::v1::{BalanceDeltas, GroupedTransactionProtocolComponents}; use crate::{abi, contract_changes, pb, pool_factories}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -50,6 +51,12 @@ pub fn map_pools_created( call.call.address.as_slice(), log, call.call, + &tycho::Transaction { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: tx.index.into(), + }, )?) }) .collect::>(); @@ -156,8 +163,8 @@ pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt #[substreams::handlers::map] pub fn map_changes( block: eth::v2::Block, - grouped_components: tycho::GroupedTransactionProtocolComponents, - deltas: tycho::BalanceDeltas, + grouped_components: GroupedTransactionProtocolComponents, + deltas: BalanceDeltas, components_store: StoreGetInt64, balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. ) -> Result { diff --git a/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs b/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs deleted file mode 100644 index 47065d4..0000000 --- a/substreams/ethereum-balancer/src/pb/eth.balancer.v1.rs +++ /dev/null @@ -1,28 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Pools { - #[prost(message, repeated, tag="1")] - pub pools: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Pool { - #[prost(bytes="vec", tag="1")] - pub pool_id: ::prost::alloc::vec::Vec, - #[prost(fixed64, tag="2")] - pub log_ordinal: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transfer { - #[prost(bytes="vec", tag="1")] - pub from: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] - pub to: ::prost::alloc::vec::Vec, - #[prost(string, tag="3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub amount: ::prost::alloc::string::String, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs b/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs deleted file mode 100644 index 47065d4..0000000 --- a/substreams/ethereum-balancer/src/pb/eth.factory.v1.rs +++ /dev/null @@ -1,28 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Pools { - #[prost(message, repeated, tag="1")] - pub pools: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Pool { - #[prost(bytes="vec", tag="1")] - pub pool_id: ::prost::alloc::vec::Vec, - #[prost(fixed64, tag="2")] - pub log_ordinal: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transfer { - #[prost(bytes="vec", tag="1")] - pub from: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] - pub to: ::prost::alloc::vec::Vec, - #[prost(string, tag="3")] - pub token: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub amount: ::prost::alloc::string::String, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs b/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs deleted file mode 100644 index 16ad6e5..0000000 --- a/substreams/ethereum-balancer/src/pb/eth.pool.v1.rs +++ /dev/null @@ -1,22 +0,0 @@ -// @generated -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transfers { - #[prost(message, repeated, tag="1")] - pub transfers: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transfer { - #[prost(string, tag="1")] - pub from: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub to: ::prost::alloc::string::String, - #[prost(uint64, tag="3")] - pub token_id: u64, - #[prost(string, tag="4")] - pub trx_hash: ::prost::alloc::string::String, - #[prost(uint64, tag="5")] - pub ordinal: u64, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs index affc411..21d371d 100644 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -51,6 +51,18 @@ pub struct Attribute { #[prost(enumeration="ChangeType", tag="3")] pub change: i32, } +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolType { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(enumeration="FinancialType", tag="2")] + pub financial_type: i32, + #[prost(message, repeated, tag="3")] + pub attribute_schema: ::prost::alloc::vec::Vec, + #[prost(enumeration="ImplementationType", tag="4")] + pub implementation_type: i32, +} /// A struct describing a part of the protocol. /// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, /// the component would represent a single contract. In case of VM integration, such component would @@ -78,20 +90,12 @@ pub struct ProtocolComponent { /// Type of change the component underwent. #[prost(enumeration="ChangeType", tag="5")] pub change: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionProtocolComponents { - #[prost(message, optional, tag="1")] + /// / Represents the functionality of the component. + #[prost(message, optional, tag="6")] + pub protocol_type: ::core::option::Option, + /// Transaction where this component was created + #[prost(message, optional, tag="7")] pub tx: ::core::option::Option, - #[prost(message, repeated, tag="2")] - pub components: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GroupedTransactionProtocolComponents { - #[prost(message, repeated, tag="1")] - pub tx_components: ::prost::alloc::vec::Vec, } /// A struct for following the changes of Total Value Locked (TVL) of a protocol component. /// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. @@ -105,39 +109,11 @@ pub struct BalanceChange { /// The new balance of the token. #[prost(bytes="vec", tag="2")] pub balance: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. + /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. #[prost(bytes="vec", tag="3")] pub component_id: ::prost::alloc::vec::Vec, } -/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. -/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. -/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDelta { - #[prost(uint64, tag="1")] - pub ord: u64, - /// The tx hash of the transaction that caused the balance change. - #[prost(message, optional, tag="2")] - pub tx: ::core::option::Option, - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="3")] - pub token: ::prost::alloc::vec::Vec, - /// The delta balance of the token. - #[prost(bytes="vec", tag="4")] - pub delta: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. - /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - #[prost(bytes="vec", tag="5")] - pub component_id: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDeltas { - #[prost(message, repeated, tag="1")] - pub balance_deltas: ::prost::alloc::vec::Vec, -} /// Enum to specify the type of a change. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -171,6 +147,64 @@ impl ChangeType { } } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum FinancialType { + Swap = 0, + Lend = 1, + Leverage = 2, + Psm = 3, +} +impl FinancialType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + FinancialType::Swap => "SWAP", + FinancialType::Lend => "LEND", + FinancialType::Leverage => "LEVERAGE", + FinancialType::Psm => "PSM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SWAP" => Some(Self::Swap), + "LEND" => Some(Self::Lend), + "LEVERAGE" => Some(Self::Leverage), + "PSM" => Some(Self::Psm), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ImplementationType { + Vm = 0, + Custom = 1, +} +impl ImplementationType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ImplementationType::Vm => "VM", + ImplementationType::Custom => "CUSTOM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VM" => Some(Self::Vm), + "CUSTOM" => Some(Self::Custom), + _ => None, + } + } +} // This file contains proto definitions specific to the VM integration. /// A key value entry into contract storage. @@ -233,4 +267,44 @@ pub struct BlockContractChanges { #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } +/// A struct for following the changes of Total Value Locked (TVL). +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub components: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GroupedTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} // @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index 62f1601..fb99696 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -3,6 +3,7 @@ use substreams_ethereum::{Event, Function}; use crate::abi; use crate::pb; +use crate::pb::tycho::evm::v1::{FinancialType, ImplementationType, ProtocolType, Transaction}; use pb::tycho::evm::v1::{self as tycho}; use substreams::hex; @@ -13,6 +14,7 @@ use substreams::scalar::BigInt; /// handled by any downstream application. trait SerializableVecBigInt { fn serialize_bytes(&self) -> Vec; + #[allow(dead_code)] fn deserialize_bytes(bytes: &[u8]) -> Vec; } @@ -25,7 +27,7 @@ impl SerializableVecBigInt for Vec { fn deserialize_bytes(bytes: &[u8]) -> Vec { bytes .chunks_exact(32) - .map(|chunk| BigInt::from_signed_bytes_be(chunk)) + .map(BigInt::from_signed_bytes_be) .collect::>() } } @@ -45,6 +47,7 @@ pub fn address_map( pool_factory_address: &[u8], log: &Log, call: &Call, + tx: &Transaction, ) -> Option { match *pool_factory_address { hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { @@ -70,6 +73,13 @@ pub fn address_map( }, ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { @@ -82,14 +92,19 @@ pub fn address_map( id: hex::encode(&pool_created.pool), tokens: create_call.tokens, contracts: vec![pool_factory_address.into(), pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "ComposableStablePoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - ], + static_att: vec![tycho::Attribute { + name: "pool_type".into(), + value: "ComposableStablePoolFactory".into(), + change: tycho::ChangeType::Creation.into(), + }], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { @@ -117,6 +132,13 @@ pub fn address_map( // Note, rate provider might be provided as `create.protocol_id`, but as a BigInt. needs investigation ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { @@ -142,6 +164,13 @@ pub fn address_map( }, ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } // ❌ Reading the deployed factory for Gearbox showcases that it's currently disabled @@ -214,6 +243,13 @@ pub fn address_map( }, ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { @@ -239,6 +275,13 @@ pub fn address_map( }, ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } // The `WeightedPool2TokenFactory` is a deprecated contract but we've included it since one @@ -266,6 +309,13 @@ pub fn address_map( }, ], change: tycho::ChangeType::Creation.into(), + protocol_type: Some(ProtocolType { + name: "balancer".to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: ImplementationType::Vm.into(), + }), + tx: Some(tx.clone()), }) } _ => None, diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index f1bc3af..9919f23 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -7,9 +7,9 @@ protobuf: files: - tycho/evm/v1/vm.proto - tycho/evm/v1/common.proto + - tycho/evm/v1/balancer.proto importPaths: - - ../../proto/tycho/evm/v1/ - - ./proto + - ../../proto binaries: default: From 51275f0ccfba5caa43ca72c7d90ad4a193e1edc5 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:46:52 +0100 Subject: [PATCH 57/86] fix: remove balancer factory from components' contracts --- substreams/ethereum-balancer/src/modules.rs | 5 ++-- .../ethereum-balancer/src/pool_factories.rs | 28 +++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index d121c2d..e741fb3 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -47,7 +47,7 @@ pub fn map_pools_created( .logs_with_calls() .filter(|(_, call)| !call.call.state_reverted) .filter_map(|(log, call)| { - Some(pool_factories::address_map( + pool_factories::address_map( call.call.address.as_slice(), log, call.call, @@ -57,7 +57,7 @@ pub fn map_pools_created( to: tx.to.clone(), index: tx.index.into(), }, - )?) + ) }) .collect::>(); @@ -204,6 +204,7 @@ pub fn map_changes( .map(|(store_delta, balance_delta)| { let pool_id = key::segment_at(&store_delta.key, 1); let token_id = key::segment_at(&store_delta.key, 3); + ( balance_delta.tx.unwrap(), tycho::BalanceChange { diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index fb99696..e19933c 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -59,7 +59,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -74,7 +74,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -91,7 +91,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![tycho::Attribute { name: "pool_type".into(), value: "ComposableStablePoolFactory".into(), @@ -99,7 +99,7 @@ pub fn address_map( }], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -116,7 +116,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -133,7 +133,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -150,7 +150,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -165,7 +165,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -229,7 +229,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -244,7 +244,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -261,7 +261,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -276,7 +276,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), @@ -295,7 +295,7 @@ pub fn address_map( Some(tycho::ProtocolComponent { id: hex::encode(&pool_created.pool), tokens: create_call.tokens, - contracts: vec![pool_factory_address.into(), pool_created.pool], + contracts: vec![pool_created.pool], static_att: vec![ tycho::Attribute { name: "pool_type".into(), @@ -310,7 +310,7 @@ pub fn address_map( ], change: tycho::ChangeType::Creation.into(), protocol_type: Some(ProtocolType { - name: "balancer".to_string(), + name: "balancer_pool".to_string(), financial_type: FinancialType::Swap.into(), attribute_schema: vec![], implementation_type: ImplementationType::Vm.into(), From accfa074fd9ccfaedf387891eb16c38b400889a9 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:50:12 +0100 Subject: [PATCH 58/86] fix: filter out changes that aren't balancer related --- .../ethereum-balancer/src/contract_changes.rs | 153 ++++++++++-------- 1 file changed, 87 insertions(+), 66 deletions(-) diff --git a/substreams/ethereum-balancer/src/contract_changes.rs b/substreams/ethereum-balancer/src/contract_changes.rs index 4ab49fe..664b0e7 100644 --- a/substreams/ethereum-balancer/src/contract_changes.rs +++ b/substreams/ethereum-balancer/src/contract_changes.rs @@ -97,77 +97,98 @@ pub fn extract_contract_changes( balance_changes.sort_unstable_by_key(|change| change.ordinal); code_changes.sort_unstable_by_key(|change| change.ordinal); - storage_changes.iter().for_each(|storage_change| { - let contract_change = changed_contracts - .entry(storage_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: storage_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&storage_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); + storage_changes + .iter() + .filter(|changes| { + contracts + .get_last(format!("pool:{0}", hex::encode(&changes.address))) + .is_some() + }) + .for_each(|storage_change| { + let contract_change = changed_contracts + .entry(storage_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: storage_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&storage_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); - let slot_value = contract_change - .slots - .entry(storage_change.key.clone()) - .or_insert_with(|| SlotValue { - new_value: storage_change.new_value.clone(), - start_value: storage_change.old_value.clone(), - }); + let slot_value = contract_change + .slots + .entry(storage_change.key.clone()) + .or_insert_with(|| SlotValue { + new_value: storage_change.new_value.clone(), + start_value: storage_change.old_value.clone(), + }); - slot_value - .new_value - .copy_from_slice(&storage_change.new_value); - }); + slot_value + .new_value + .copy_from_slice(&storage_change.new_value); + }); - balance_changes.iter().for_each(|balance_change| { - let contract_change = changed_contracts - .entry(balance_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: balance_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&balance_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); + balance_changes + .iter() + .filter(|changes| { + contracts + .get_last(format!("pool:{0}", hex::encode(&changes.address))) + .is_some() + }) + .for_each(|balance_change| { + let contract_change = changed_contracts + .entry(balance_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: balance_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&balance_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); - if let Some(new_balance) = &balance_change.new_value { - contract_change.balance.clear(); + if let Some(new_balance) = &balance_change.new_value { + contract_change.balance.clear(); + contract_change + .balance + .extend_from_slice(&new_balance.bytes); + } + }); + + code_changes + .iter() + .filter(|changes| { + contracts + .get_last(format!("pool:{0}", hex::encode(&changes.address))) + .is_some() + }) + .for_each(|code_change| { + let contract_change = changed_contracts + .entry(code_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: code_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&code_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + contract_change.code.clear(); contract_change - .balance - .extend_from_slice(&new_balance.bytes); - } - }); - - code_changes.iter().for_each(|code_change| { - let contract_change = changed_contracts - .entry(code_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: code_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&code_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); - - contract_change.code.clear(); - contract_change - .code - .extend_from_slice(&code_change.new_code); - }); + .code + .extend_from_slice(&code_change.new_code); + }); if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { transaction_contract_changes From c283a8134112b502a874e8c76bf63999bdc1e7ce Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:32:42 +0100 Subject: [PATCH 59/86] Make clippy happy --- substreams/ethereum-balancer/build.rs | 1 + substreams/ethereum-balancer/src/abi/mod.rs | 1 + substreams/ethereum-balancer/src/modules.rs | 11 +++-------- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/substreams/ethereum-balancer/build.rs b/substreams/ethereum-balancer/build.rs index ceabf48..90e1f1e 100644 --- a/substreams/ethereum-balancer/build.rs +++ b/substreams/ethereum-balancer/build.rs @@ -8,6 +8,7 @@ fn main() -> Result<()> { let files = fs::read_dir(abi_folder)?; let mut mod_rs_content = String::new(); + mod_rs_content.push_str("#![allow(clippy::all)]\n"); for file in files { let file = file?; diff --git a/substreams/ethereum-balancer/src/abi/mod.rs b/substreams/ethereum-balancer/src/abi/mod.rs index ef6622d..0f60dc0 100644 --- a/substreams/ethereum-balancer/src/abi/mod.rs +++ b/substreams/ethereum-balancer/src/abi/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::all)] pub mod yearn_linear_pool_factory; pub mod composable_stable_pool_factory; pub mod vault; diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index e741fb3..7d666cc 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -102,7 +102,7 @@ pub fn map_balance_deltas( ) -> Result { Ok(tycho::BalanceDeltas { balance_deltas: block - .events::(&[&VAULT_ADDRESS]) + .events::(&[VAULT_ADDRESS]) .flat_map(|(event, log)| { event .tokens @@ -111,12 +111,7 @@ pub fn map_balance_deltas( .filter_map(|(token, delta)| { let component_id: Vec<_> = event.pool_id.into(); - if store - .get_last(format!("pool:{0}", hex::encode(&component_id))) - .is_none() - { - return None; - } + store.get_last(format!("pool:{0}", hex::encode(&component_id)))?; Some(tycho::BalanceDelta { ord: log.log.ordinal, @@ -253,7 +248,7 @@ pub fn map_changes( }), changes: transaction_contract_changes .drain() - .sorted_unstable_by_key(|(index, _)| index.clone()) + .sorted_unstable_by_key(|(index, _)| *index) .filter_map(|(_, change)| { if change.contract_changes.is_empty() && change.component_changes.is_empty() From a1864e3cd4bb09dfda2f25d4ce2887e9646e8cb5 Mon Sep 17 00:00:00 2001 From: kayibal Date: Mon, 11 Mar 2024 19:10:28 +0000 Subject: [PATCH 60/86] Don't include balancer specific pb in tycho pbs. --- .../ethereum-balancer/proto}/balancer.proto | 8 ++-- substreams/ethereum-balancer/src/modules.rs | 18 ++++---- .../ethereum-balancer/src/pb/balancer.rs | 42 +++++++++++++++++++ substreams/ethereum-balancer/src/pb/mod.rs | 5 +++ .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 40 ------------------ substreams/ethereum-balancer/substreams.yaml | 3 +- 6 files changed, 62 insertions(+), 54 deletions(-) rename {proto/tycho/evm/v1 => substreams/ethereum-balancer/proto}/balancer.proto (84%) create mode 100644 substreams/ethereum-balancer/src/pb/balancer.rs diff --git a/proto/tycho/evm/v1/balancer.proto b/substreams/ethereum-balancer/proto/balancer.proto similarity index 84% rename from proto/tycho/evm/v1/balancer.proto rename to substreams/ethereum-balancer/proto/balancer.proto index f5a4c63..6efe1c9 100644 --- a/proto/tycho/evm/v1/balancer.proto +++ b/substreams/ethereum-balancer/proto/balancer.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package tycho.evm.v1; +package balancer; import "tycho/evm/v1/common.proto"; @@ -8,7 +8,7 @@ import "tycho/evm/v1/common.proto"; message BalanceDelta { uint64 ord = 1; // The tx hash of the transaction that caused the balance change. - Transaction tx = 2; + tycho.evm.v1.Transaction tx = 2; // The address of the ERC20 token whose balance changed. bytes token = 3; // The delta balance of the token. @@ -23,8 +23,8 @@ message BalanceDeltas { } message TransactionProtocolComponents { - Transaction tx = 1; - repeated ProtocolComponent components = 2; + tycho.evm.v1.Transaction tx = 1; + repeated tycho.evm.v1.ProtocolComponent components = 2; } message GroupedTransactionProtocolComponents { diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 7d666cc..96554ca 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -17,7 +17,7 @@ use pb::tycho::evm::v1::{self as tycho}; use contract_changes::extract_contract_changes; -use crate::pb::tycho::evm::v1::{BalanceDeltas, GroupedTransactionProtocolComponents}; +use crate::pb::balancer::{BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, TransactionProtocolComponents}; use crate::{abi, contract_changes, pb, pool_factories}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -36,10 +36,10 @@ impl PartialEq for TransactionWrapper { #[substreams::handlers::map] pub fn map_pools_created( block: eth::v2::Block, -) -> Result { +) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call // We store these as a hashmap by tx hash since we need to agg by tx hash later - Ok(tycho::GroupedTransactionProtocolComponents { + Ok(GroupedTransactionProtocolComponents { tx_components: block .transactions() .filter_map(|tx| { @@ -62,7 +62,7 @@ pub fn map_pools_created( .collect::>(); if !components.is_empty() { - Some(tycho::TransactionProtocolComponents { + Some(TransactionProtocolComponents { tx: Some(tycho::Transaction { hash: tx.hash.clone(), from: tx.from.clone(), @@ -81,7 +81,7 @@ pub fn map_pools_created( /// Simply stores the `ProtocolComponent`s with the pool id as the key #[substreams::handlers::store] -pub fn store_pools_created(map: tycho::GroupedTransactionProtocolComponents, store: StoreAddInt64) { +pub fn store_pools_created(map: GroupedTransactionProtocolComponents, store: StoreAddInt64) { store.add_many( 0, &map.tx_components @@ -99,8 +99,8 @@ pub fn store_pools_created(map: tycho::GroupedTransactionProtocolComponents, sto pub fn map_balance_deltas( block: eth::v2::Block, store: StoreGetInt64, -) -> Result { - Ok(tycho::BalanceDeltas { +) -> Result { + Ok(BalanceDeltas { balance_deltas: block .events::(&[VAULT_ADDRESS]) .flat_map(|(event, log)| { @@ -113,7 +113,7 @@ pub fn map_balance_deltas( store.get_last(format!("pool:{0}", hex::encode(&component_id)))?; - Some(tycho::BalanceDelta { + Some(BalanceDelta { ord: log.log.ordinal, tx: Some(tycho::Transaction { hash: log.receipt.transaction.hash.clone(), @@ -135,7 +135,7 @@ pub fn map_balance_deltas( /// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the /// store key to ensure that there's a unique balance being tallied for each. #[substreams::handlers::store] -pub fn store_balance_changes(deltas: tycho::BalanceDeltas, store: StoreAddBigInt) { +pub fn store_balance_changes(deltas: BalanceDeltas, store: StoreAddBigInt) { deltas.balance_deltas.iter().for_each(|delta| { store.add( delta.ord, diff --git a/substreams/ethereum-balancer/src/pb/balancer.rs b/substreams/ethereum-balancer/src/pb/balancer.rs new file mode 100644 index 0000000..b2f52d2 --- /dev/null +++ b/substreams/ethereum-balancer/src/pb/balancer.rs @@ -0,0 +1,42 @@ +// @generated +/// A struct for following the changes of Total Value Locked (TVL). +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub components: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GroupedTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} +// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/mod.rs b/substreams/ethereum-balancer/src/pb/mod.rs index 43d8838..1d5f1e8 100644 --- a/substreams/ethereum-balancer/src/pb/mod.rs +++ b/substreams/ethereum-balancer/src/pb/mod.rs @@ -1,4 +1,9 @@ // @generated +// @@protoc_insertion_point(attribute:balancer) +pub mod balancer { + include!("balancer.rs"); + // @@protoc_insertion_point(balancer) +} pub mod tycho { pub mod evm { // @@protoc_insertion_point(attribute:tycho.evm.v1) diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs index 21d371d..cf81ed2 100644 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -267,44 +267,4 @@ pub struct BlockContractChanges { #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } -/// A struct for following the changes of Total Value Locked (TVL). -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDelta { - #[prost(uint64, tag="1")] - pub ord: u64, - /// The tx hash of the transaction that caused the balance change. - #[prost(message, optional, tag="2")] - pub tx: ::core::option::Option, - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="3")] - pub token: ::prost::alloc::vec::Vec, - /// The delta balance of the token. - #[prost(bytes="vec", tag="4")] - pub delta: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. - /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - #[prost(bytes="vec", tag="5")] - pub component_id: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDeltas { - #[prost(message, repeated, tag="1")] - pub balance_deltas: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionProtocolComponents { - #[prost(message, optional, tag="1")] - pub tx: ::core::option::Option, - #[prost(message, repeated, tag="2")] - pub components: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GroupedTransactionProtocolComponents { - #[prost(message, repeated, tag="1")] - pub tx_components: ::prost::alloc::vec::Vec, -} // @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 9919f23..c5b56d0 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -7,9 +7,10 @@ protobuf: files: - tycho/evm/v1/vm.proto - tycho/evm/v1/common.proto - - tycho/evm/v1/balancer.proto + - balancer.proto importPaths: - ../../proto + - ./proto binaries: default: From 1e546230ded47e52096b6a7ec84fa1f175c7a9b9 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:49:09 +0100 Subject: [PATCH 61/86] fix: map_balance_deltas pool_id check --- substreams/ethereum-balancer/src/modules.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 96554ca..8448772 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -17,7 +17,10 @@ use pb::tycho::evm::v1::{self as tycho}; use contract_changes::extract_contract_changes; -use crate::pb::balancer::{BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, TransactionProtocolComponents}; +use crate::pb::balancer::{ + BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, + TransactionProtocolComponents, +}; use crate::{abi, contract_changes, pb, pool_factories}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -34,9 +37,7 @@ impl PartialEq for TransactionWrapper { } #[substreams::handlers::map] -pub fn map_pools_created( - block: eth::v2::Block, -) -> Result { +pub fn map_pools_created(block: eth::v2::Block) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call // We store these as a hashmap by tx hash since we need to agg by tx hash later Ok(GroupedTransactionProtocolComponents { @@ -109,7 +110,7 @@ pub fn map_balance_deltas( .iter() .zip(event.deltas.iter()) .filter_map(|(token, delta)| { - let component_id: Vec<_> = event.pool_id.into(); + let component_id = event.pool_id[..20].to_vec(); store.get_last(format!("pool:{0}", hex::encode(&component_id)))?; @@ -119,11 +120,11 @@ pub fn map_balance_deltas( hash: log.receipt.transaction.hash.clone(), from: log.receipt.transaction.from.clone(), to: log.receipt.transaction.to.clone(), - index: Into::::into(log.receipt.transaction.index), + index: log.receipt.transaction.index.into(), }), - token: token.clone(), + token: token.to_vec(), delta: delta.to_signed_bytes_be(), - component_id: component_id.clone(), + component_id, }) }) .collect::>() From 38dcd9d843354bfc8fdb9e461da4594d102837e1 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Tue, 12 Mar 2024 12:51:26 +0100 Subject: [PATCH 62/86] fix: BalanceChange encoding --- proto/tycho/evm/v1/common.proto | 2 +- substreams/ethereum-balancer/src/modules.rs | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/proto/tycho/evm/v1/common.proto b/proto/tycho/evm/v1/common.proto index 545cad0..7f6d369 100644 --- a/proto/tycho/evm/v1/common.proto +++ b/proto/tycho/evm/v1/common.proto @@ -100,7 +100,7 @@ message ProtocolComponent { message BalanceChange { // The address of the ERC20 token whose balance changed. bytes token = 1; - // The new balance of the token. + // The new balance of the token. Note: it must be a big endian encoded int. bytes balance = 2; // The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 8448772..f84a496 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::str::FromStr; use anyhow::Result; use substreams::hex; @@ -200,12 +201,17 @@ pub fn map_changes( .map(|(store_delta, balance_delta)| { let pool_id = key::segment_at(&store_delta.key, 1); let token_id = key::segment_at(&store_delta.key, 3); + // store_delta.new_value is an ASCII string representing an integer + let ascii_string = + String::from_utf8(store_delta.new_value.clone()).expect("Invalid UTF-8 sequence"); + let balance = BigInt::from_str(&ascii_string).expect("Failed to parse integer"); + let big_endian_bytes_balance = balance.to_bytes_be().1; ( balance_delta.tx.unwrap(), tycho::BalanceChange { token: hex::decode(token_id).expect("Token ID not valid hex"), - balance: store_delta.new_value, + balance: big_endian_bytes_balance, component_id: hex::decode(pool_id).expect("Token ID not valid hex"), }, ) From 2a1b83f6c5c317ac5e2f270904e9f944c9668f09 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Tue, 12 Mar 2024 22:53:30 +0100 Subject: [PATCH 63/86] fix: index balance changes from `Swap` events --- substreams/ethereum-balancer/src/modules.rs | 90 +++++++++++++++------ 1 file changed, 65 insertions(+), 25 deletions(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index f84a496..71f0e83 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -17,6 +17,7 @@ use itertools::Itertools; use pb::tycho::evm::v1::{self as tycho}; use contract_changes::extract_contract_changes; +use substreams_ethereum::Event; use crate::pb::balancer::{ BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, @@ -95,43 +96,82 @@ pub fn store_pools_created(map: GroupedTransactionProtocolComponents, store: Sto ); } -/// Since the `PoolBalanceChanged` events administer only deltas, we need to leverage a map and a +/// Since the `PoolBalanceChanged` and `Swap` events administer only deltas, we need to leverage a map and a /// store to be able to tally up final balances for tokens in a pool. #[substreams::handlers::map] pub fn map_balance_deltas( block: eth::v2::Block, store: StoreGetInt64, ) -> Result { - Ok(BalanceDeltas { - balance_deltas: block - .events::(&[VAULT_ADDRESS]) - .flat_map(|(event, log)| { - event - .tokens - .iter() - .zip(event.deltas.iter()) - .filter_map(|(token, delta)| { - let component_id = event.pool_id[..20].to_vec(); + let balance_deltas = block + .logs() + .filter(|log| log.address() == VAULT_ADDRESS) + .flat_map(|vault_log| { + let mut deltas = Vec::new(); - store.get_last(format!("pool:{0}", hex::encode(&component_id)))?; - - Some(BalanceDelta { - ord: log.log.ordinal, + if let Some(ev) = + abi::vault::events::PoolBalanceChanged::match_and_decode(vault_log.log) + { + let component_id = ev.pool_id[..20].to_vec(); + if store + .get_last(format!("pool:{}", hex::encode(&component_id))) + .is_some() + { + for (token, delta) in ev.tokens.iter().zip(ev.deltas.iter()) { + deltas.push(BalanceDelta { + ord: vault_log.ordinal(), tx: Some(tycho::Transaction { - hash: log.receipt.transaction.hash.clone(), - from: log.receipt.transaction.from.clone(), - to: log.receipt.transaction.to.clone(), - index: log.receipt.transaction.index.into(), + hash: vault_log.receipt.transaction.hash.clone(), + from: vault_log.receipt.transaction.from.clone(), + to: vault_log.receipt.transaction.to.clone(), + index: vault_log.receipt.transaction.index.into(), }), token: token.to_vec(), delta: delta.to_signed_bytes_be(), + component_id: component_id.clone(), + }); + } + } + } else if let Some(ev) = abi::vault::events::Swap::match_and_decode(vault_log.log) { + let component_id = ev.pool_id[..20].to_vec(); + if store + .get_last(format!("pool:{}", hex::encode(&component_id))) + .is_some() + { + deltas.extend_from_slice(&[ + BalanceDelta { + ord: vault_log.ordinal(), + tx: Some(tycho::Transaction { + hash: vault_log.receipt.transaction.hash.clone(), + from: vault_log.receipt.transaction.from.clone(), + to: vault_log.receipt.transaction.to.clone(), + index: vault_log.receipt.transaction.index.into(), + }), + token: ev.token_in.to_vec(), + delta: ev.amount_in.to_signed_bytes_be(), + component_id: component_id.clone(), + }, + BalanceDelta { + ord: vault_log.ordinal(), + tx: Some(tycho::Transaction { + hash: vault_log.receipt.transaction.hash.clone(), + from: vault_log.receipt.transaction.from.clone(), + to: vault_log.receipt.transaction.to.clone(), + index: vault_log.receipt.transaction.index.into(), + }), + token: ev.token_out.to_vec(), + delta: ev.amount_out.neg().to_signed_bytes_be(), component_id, - }) - }) - .collect::>() - }) - .collect::>(), - }) + }, + ]); + } + } + + deltas + }) + .collect::>(); + + Ok(BalanceDeltas { balance_deltas }) } /// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the From 7601072e873b21738c8238bb23016365ca4fc882 Mon Sep 17 00:00:00 2001 From: Florian Pellissier <111426680+flopell@users.noreply.github.com> Date: Wed, 13 Mar 2024 10:19:59 +0100 Subject: [PATCH 64/86] fix: encode component_id as UTF8 --- substreams/ethereum-balancer/src/modules.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 71f0e83..2b47bd1 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -252,7 +252,7 @@ pub fn map_changes( tycho::BalanceChange { token: hex::decode(token_id).expect("Token ID not valid hex"), balance: big_endian_bytes_balance, - component_id: hex::decode(pool_id).expect("Token ID not valid hex"), + component_id: pool_id.as_bytes().to_vec(), }, ) }) From 4b2437dab63d320daa09711375d0cc879f0b3fad Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 12:11:38 +0000 Subject: [PATCH 65/86] Revert "Don't include balancer specific pb in tycho pbs." This reverts commit a1864e3c. We will actually make the balance delta messages part of the tycho packages since this makes a few things simpler when trying to factor out an sdk. --- .../tycho/evm/v1}/balancer.proto | 8 ++-- substreams/ethereum-balancer/src/modules.rs | 10 ++--- .../ethereum-balancer/src/pb/balancer.rs | 42 ------------------- substreams/ethereum-balancer/src/pb/mod.rs | 5 --- .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 40 ++++++++++++++++++ substreams/ethereum-balancer/substreams.yaml | 3 +- 6 files changed, 49 insertions(+), 59 deletions(-) rename {substreams/ethereum-balancer/proto => proto/tycho/evm/v1}/balancer.proto (84%) delete mode 100644 substreams/ethereum-balancer/src/pb/balancer.rs diff --git a/substreams/ethereum-balancer/proto/balancer.proto b/proto/tycho/evm/v1/balancer.proto similarity index 84% rename from substreams/ethereum-balancer/proto/balancer.proto rename to proto/tycho/evm/v1/balancer.proto index 6efe1c9..f5a4c63 100644 --- a/substreams/ethereum-balancer/proto/balancer.proto +++ b/proto/tycho/evm/v1/balancer.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package balancer; +package tycho.evm.v1; import "tycho/evm/v1/common.proto"; @@ -8,7 +8,7 @@ import "tycho/evm/v1/common.proto"; message BalanceDelta { uint64 ord = 1; // The tx hash of the transaction that caused the balance change. - tycho.evm.v1.Transaction tx = 2; + Transaction tx = 2; // The address of the ERC20 token whose balance changed. bytes token = 3; // The delta balance of the token. @@ -23,8 +23,8 @@ message BalanceDeltas { } message TransactionProtocolComponents { - tycho.evm.v1.Transaction tx = 1; - repeated tycho.evm.v1.ProtocolComponent components = 2; + Transaction tx = 1; + repeated ProtocolComponent components = 2; } message GroupedTransactionProtocolComponents { diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 2b47bd1..75f61a3 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -14,16 +14,14 @@ use substreams::scalar::BigInt; use substreams_ethereum::pb::eth; use itertools::Itertools; -use pb::tycho::evm::v1::{self as tycho}; + use contract_changes::extract_contract_changes; use substreams_ethereum::Event; -use crate::pb::balancer::{ - BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, - TransactionProtocolComponents, -}; -use crate::{abi, contract_changes, pb, pool_factories}; +use crate::pb::tycho::evm::v1::{self as tycho}; +use crate::pb::tycho::evm::v1::{BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, TransactionProtocolComponents}; +use crate::{abi, contract_changes, pool_factories}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); diff --git a/substreams/ethereum-balancer/src/pb/balancer.rs b/substreams/ethereum-balancer/src/pb/balancer.rs deleted file mode 100644 index b2f52d2..0000000 --- a/substreams/ethereum-balancer/src/pb/balancer.rs +++ /dev/null @@ -1,42 +0,0 @@ -// @generated -/// A struct for following the changes of Total Value Locked (TVL). -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDelta { - #[prost(uint64, tag="1")] - pub ord: u64, - /// The tx hash of the transaction that caused the balance change. - #[prost(message, optional, tag="2")] - pub tx: ::core::option::Option, - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="3")] - pub token: ::prost::alloc::vec::Vec, - /// The delta balance of the token. - #[prost(bytes="vec", tag="4")] - pub delta: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. - /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - #[prost(bytes="vec", tag="5")] - pub component_id: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDeltas { - #[prost(message, repeated, tag="1")] - pub balance_deltas: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionProtocolComponents { - #[prost(message, optional, tag="1")] - pub tx: ::core::option::Option, - #[prost(message, repeated, tag="2")] - pub components: ::prost::alloc::vec::Vec, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GroupedTransactionProtocolComponents { - #[prost(message, repeated, tag="1")] - pub tx_components: ::prost::alloc::vec::Vec, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pb/mod.rs b/substreams/ethereum-balancer/src/pb/mod.rs index 1d5f1e8..43d8838 100644 --- a/substreams/ethereum-balancer/src/pb/mod.rs +++ b/substreams/ethereum-balancer/src/pb/mod.rs @@ -1,9 +1,4 @@ // @generated -// @@protoc_insertion_point(attribute:balancer) -pub mod balancer { - include!("balancer.rs"); - // @@protoc_insertion_point(balancer) -} pub mod tycho { pub mod evm { // @@protoc_insertion_point(attribute:tycho.evm.v1) diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs index cf81ed2..21d371d 100644 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -267,4 +267,44 @@ pub struct BlockContractChanges { #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } +/// A struct for following the changes of Total Value Locked (TVL). +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub components: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GroupedTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} // @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index c5b56d0..9919f23 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -7,10 +7,9 @@ protobuf: files: - tycho/evm/v1/vm.proto - tycho/evm/v1/common.proto - - balancer.proto + - tycho/evm/v1/balancer.proto importPaths: - ../../proto - - ./proto binaries: default: From 0d621a4545c9a00f6ce6942d127b4af259b33dec Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 12:28:10 +0000 Subject: [PATCH 66/86] Improve the naming of utils. --- .../evm/v1/{balancer.proto => utils.proto} | 17 ++++++++++++---- substreams/ethereum-balancer/src/modules.rs | 20 +++++++++---------- .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 19 +++++++++++++----- substreams/ethereum-balancer/substreams.yaml | 2 +- 4 files changed, 38 insertions(+), 20 deletions(-) rename proto/tycho/evm/v1/{balancer.proto => utils.proto} (50%) diff --git a/proto/tycho/evm/v1/balancer.proto b/proto/tycho/evm/v1/utils.proto similarity index 50% rename from proto/tycho/evm/v1/balancer.proto rename to proto/tycho/evm/v1/utils.proto index f5a4c63..ea3f5d5 100644 --- a/proto/tycho/evm/v1/balancer.proto +++ b/proto/tycho/evm/v1/utils.proto @@ -4,8 +4,13 @@ package tycho.evm.v1; import "tycho/evm/v1/common.proto"; -// A struct for following the changes of Total Value Locked (TVL). +// A message containing relative balance changes. +// +// Used to track token balances of protocol components in case they are only +// available as relative values within a block. message BalanceDelta { + // The ordinal of the balance change. Must be unique & deterministic over all balances + // changes within a block. uint64 ord = 1; // The tx hash of the transaction that caused the balance change. Transaction tx = 2; @@ -14,19 +19,23 @@ message BalanceDelta { // The delta balance of the token. bytes delta = 4; // The id of the component whose TVL is tracked. - // If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + // If the protocol component includes multiple contracts, the balance change must be + // aggregated to reflect how much tokens can be traded. bytes component_id = 5; } -message BalanceDeltas { +// A set of balances deltas, usually a group of changes within a single block. +message BlockBalanceDeltas { repeated BalanceDelta balance_deltas = 1; } +// A message containing protocol components that were created by a single tx. message TransactionProtocolComponents { Transaction tx = 1; repeated ProtocolComponent components = 2; } -message GroupedTransactionProtocolComponents { +// All protocol components that were created within a block with their corresponding tx. +message BlockTransactionProtocolComponents { repeated TransactionProtocolComponents tx_components = 1; } \ No newline at end of file diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 75f61a3..c4fcb4a 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -20,7 +20,7 @@ use contract_changes::extract_contract_changes; use substreams_ethereum::Event; use crate::pb::tycho::evm::v1::{self as tycho}; -use crate::pb::tycho::evm::v1::{BalanceDelta, BalanceDeltas, GroupedTransactionProtocolComponents, TransactionProtocolComponents}; +use crate::pb::tycho::evm::v1::{BalanceDelta, BlockBalanceDeltas, BlockTransactionProtocolComponents, TransactionProtocolComponents}; use crate::{abi, contract_changes, pool_factories}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -37,10 +37,10 @@ impl PartialEq for TransactionWrapper { } #[substreams::handlers::map] -pub fn map_pools_created(block: eth::v2::Block) -> Result { +pub fn map_pools_created(block: eth::v2::Block) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call // We store these as a hashmap by tx hash since we need to agg by tx hash later - Ok(GroupedTransactionProtocolComponents { + Ok(BlockTransactionProtocolComponents { tx_components: block .transactions() .filter_map(|tx| { @@ -82,7 +82,7 @@ pub fn map_pools_created(block: eth::v2::Block) -> Result Result { +) -> Result { let balance_deltas = block .logs() .filter(|log| log.address() == VAULT_ADDRESS) @@ -169,13 +169,13 @@ pub fn map_balance_deltas( }) .collect::>(); - Ok(BalanceDeltas { balance_deltas }) + Ok(BlockBalanceDeltas { balance_deltas }) } /// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the /// store key to ensure that there's a unique balance being tallied for each. #[substreams::handlers::store] -pub fn store_balance_changes(deltas: BalanceDeltas, store: StoreAddBigInt) { +pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { deltas.balance_deltas.iter().for_each(|delta| { store.add( delta.ord, @@ -198,8 +198,8 @@ pub fn store_balance_changes(deltas: BalanceDeltas, store: StoreAddBigInt) { #[substreams::handlers::map] pub fn map_changes( block: eth::v2::Block, - grouped_components: GroupedTransactionProtocolComponents, - deltas: BalanceDeltas, + grouped_components: BlockTransactionProtocolComponents, + deltas: BlockBalanceDeltas, components_store: StoreGetInt64, balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. ) -> Result { @@ -229,7 +229,7 @@ pub fn map_changes( }); // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating - // `BalanceDeltas`. We essentially just process the changes that occured to the `store` this + // `BlockBalanceDeltas`. We essentially just process the changes that occured to the `store` this // block. Then, these balance changes are merged onto the existing map of tx contract changes, // inserting a new one if it doesn't exist. balance_store diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs index 21d371d..387ff7b 100644 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs @@ -106,7 +106,7 @@ pub struct BalanceChange { /// The address of the ERC20 token whose balance changed. #[prost(bytes="vec", tag="1")] pub token: ::prost::alloc::vec::Vec, - /// The new balance of the token. + /// The new balance of the token. Note: it must be a big endian encoded int. #[prost(bytes="vec", tag="2")] pub balance: ::prost::alloc::vec::Vec, /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. @@ -267,10 +267,15 @@ pub struct BlockContractChanges { #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } -/// A struct for following the changes of Total Value Locked (TVL). +/// A message containing relative balance changes. +/// +/// Used to track token balances of protocol components in case they are only +/// available as relative values within a block. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct BalanceDelta { + /// The ordinal of the balance change. Must be unique & deterministic over all balances + /// changes within a block. #[prost(uint64, tag="1")] pub ord: u64, /// The tx hash of the transaction that caused the balance change. @@ -283,16 +288,19 @@ pub struct BalanceDelta { #[prost(bytes="vec", tag="4")] pub delta: ::prost::alloc::vec::Vec, /// The id of the component whose TVL is tracked. - /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + /// If the protocol component includes multiple contracts, the balance change must be + /// aggregated to reflect how much tokens can be traded. #[prost(bytes="vec", tag="5")] pub component_id: ::prost::alloc::vec::Vec, } +/// A set of balances deltas, usually a group of changes within a single block. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDeltas { +pub struct BlockBalanceDeltas { #[prost(message, repeated, tag="1")] pub balance_deltas: ::prost::alloc::vec::Vec, } +/// A message containing protocol components that were created by a single tx. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct TransactionProtocolComponents { @@ -301,9 +309,10 @@ pub struct TransactionProtocolComponents { #[prost(message, repeated, tag="2")] pub components: ::prost::alloc::vec::Vec, } +/// All protocol components that were created within a block with their corresponding tx. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct GroupedTransactionProtocolComponents { +pub struct BlockTransactionProtocolComponents { #[prost(message, repeated, tag="1")] pub tx_components: ::prost::alloc::vec::Vec, } diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 9919f23..66da244 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -7,7 +7,7 @@ protobuf: files: - tycho/evm/v1/vm.proto - tycho/evm/v1/common.proto - - tycho/evm/v1/balancer.proto + - tycho/evm/v1/utils.proto importPaths: - ../../proto From 92f20d0521dcd16c2ba11fc54d6f51c37873935e Mon Sep 17 00:00:00 2001 From: kayibal Date: Mon, 11 Mar 2024 20:08:10 +0000 Subject: [PATCH 67/86] Add shared tycho-substreams lib. --- crates/tycho-substreams/Cargo.lock | 1050 +++++++++++++++++ crates/tycho-substreams/Cargo.toml | 7 + crates/tycho-substreams/Readme.md | 18 + crates/tycho-substreams/buf.gen.yaml | 12 + crates/tycho-substreams/src/contract.rs | 199 ++++ crates/tycho-substreams/src/lib.rs | 2 + crates/tycho-substreams/src/pb/mod.rs | 10 + .../tycho-substreams/src/pb/tycho.evm.v1.rs | 309 +++++ 8 files changed, 1607 insertions(+) create mode 100644 crates/tycho-substreams/Cargo.lock create mode 100644 crates/tycho-substreams/Cargo.toml create mode 100644 crates/tycho-substreams/Readme.md create mode 100644 crates/tycho-substreams/buf.gen.yaml create mode 100644 crates/tycho-substreams/src/contract.rs create mode 100644 crates/tycho-substreams/src/lib.rs create mode 100644 crates/tycho-substreams/src/pb/mod.rs create mode 100644 crates/tycho-substreams/src/pb/tycho.evm.v1.rs diff --git a/crates/tycho-substreams/Cargo.lock b/crates/tycho-substreams/Cargo.lock new file mode 100644 index 0000000..5e61c4a --- /dev/null +++ b/crates/tycho-substreams/Cargo.lock @@ -0,0 +1,1050 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "ethabi" +version = "17.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +dependencies = [ + "bytes", + "heck", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +dependencies = [ + "prost", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "serde" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.197" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_json" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "substreams" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3520661f782c338f0e3c6cfc001ac790ed5e68d8f28515139e2aa674f8bb54da" +dependencies = [ + "anyhow", + "bigdecimal", + "hex", + "hex-literal", + "num-bigint", + "num-integer", + "num-traits", + "pad", + "prost", + "prost-build", + "prost-types", + "substreams-macro", + "thiserror", +] + +[[package]] +name = "substreams-ethereum" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" +dependencies = [ + "getrandom", + "num-bigint", + "substreams", + "substreams-ethereum-abigen", + "substreams-ethereum-core", + "substreams-ethereum-derive", +] + +[[package]] +name = "substreams-ethereum-abigen" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" +dependencies = [ + "anyhow", + "ethabi", + "heck", + "hex", + "prettyplease", + "proc-macro2", + "quote", + "substreams-ethereum-core", + "syn 1.0.109", +] + +[[package]] +name = "substreams-ethereum-core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" +dependencies = [ + "bigdecimal", + "ethabi", + "getrandom", + "num-bigint", + "prost", + "prost-build", + "prost-types", + "substreams", +] + +[[package]] +name = "substreams-ethereum-derive" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" +dependencies = [ + "ethabi", + "heck", + "hex", + "num-bigint", + "proc-macro2", + "quote", + "substreams-ethereum-abigen", + "syn 1.0.109", +] + +[[package]] +name = "substreams-macro" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c15595ceab80fece579e462d4823048fe85d67922584c681f5e94305727ad9ee" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tycho-substreams" +version = "0.1.0" +dependencies = [ + "substreams-ethereum", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/crates/tycho-substreams/Cargo.toml b/crates/tycho-substreams/Cargo.toml new file mode 100644 index 0000000..269aea3 --- /dev/null +++ b/crates/tycho-substreams/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "tycho-substreams" +version = "0.1.0" +edition = "2021" + +[dependencies] +substreams-ethereum = "0.9.9" \ No newline at end of file diff --git a/crates/tycho-substreams/Readme.md b/crates/tycho-substreams/Readme.md new file mode 100644 index 0000000..56b374b --- /dev/null +++ b/crates/tycho-substreams/Readme.md @@ -0,0 +1,18 @@ +# Tycho Substreams SDK + +Some shared functionality that is used to create tycho substream packages. + +## Protobuf Models + +Protobuf models are manually synced from the `tycho-indexer` repository whenever they +changed. + +To generate the rust structs run the following command from within the `./proto` +directory: + +```bash +buf generate \ + --path tycho \ + --template ../crates/tycho-substreams/buf.gen.yaml \ + --output ../crates/tycho-substreams/ +``` \ No newline at end of file diff --git a/crates/tycho-substreams/buf.gen.yaml b/crates/tycho-substreams/buf.gen.yaml new file mode 100644 index 0000000..07f4f81 --- /dev/null +++ b/crates/tycho-substreams/buf.gen.yaml @@ -0,0 +1,12 @@ +version: v1 +plugins: + - plugin: buf.build/community/neoeinstein-prost:v0.2.2 + out: src/pb + opt: + - file_descriptor_set=false + - type_attribute=.tycho.evm.v1.Transaction=#[derive(Eq\, Hash)] + + - plugin: buf.build/community/neoeinstein-prost-crate:v0.3.1 + out: src/pb + opt: + - no_features diff --git a/crates/tycho-substreams/src/contract.rs b/crates/tycho-substreams/src/contract.rs new file mode 100644 index 0000000..a0391b3 --- /dev/null +++ b/crates/tycho-substreams/src/contract.rs @@ -0,0 +1,199 @@ +/// This file contains helpers to capture contract changes from the expanded block model. These +/// leverage the `code_changes`, `balance_changes`, and `storage_changes` fields available on the +/// `Call` type provided by block model in a substream (i.e. `logs_and_calls`, etc). +/// +/// ⚠️ These helpers *only* work if the **expanded block model** is available, +/// more [here](https://streamingfastio.medium.com/new-block-model-to-accelerate-chain-integration-9f65126e5425) +use std::collections::HashMap; + +use substreams_ethereum::pb::eth; + +use crate::pb::tycho::evm::v1::{self as tycho}; + +struct SlotValue { + new_value: Vec, + start_value: Vec, +} + +impl SlotValue { + fn has_changed(&self) -> bool { + self.start_value != self.new_value + } +} + +// Uses a map for slots, protobuf does not allow bytes in hashmap keys +pub struct InterimContractChange { + address: Vec, + balance: Vec, + code: Vec, + slots: HashMap, SlotValue>, + change: tycho::ChangeType, +} + +impl From for tycho::ContractChange { + fn from(value: InterimContractChange) -> Self { + tycho::ContractChange { + address: value.address, + balance: value.balance, + code: value.code, + slots: value + .slots + .into_iter() + .filter(|(_, value)| value.has_changed()) + .map(|(slot, value)| tycho::ContractSlot { + slot, + value: value.new_value, + }) + .collect(), + change: value.change.into(), + } + } +} + +pub fn extract_contract_changes bool >( + block: ð::v2::Block, + inclusion_predicate: F, + transaction_contract_changes: &mut HashMap, +) { + let mut changed_contracts: HashMap, InterimContractChange> = HashMap::new(); + + // Collect all accounts created in this block + let created_accounts: HashMap<_, _> = block + .transactions() + .flat_map(|tx| { + tx.calls.iter().flat_map(|call| { + call.account_creations + .iter() + .map(|ac| (&ac.account, ac.ordinal)) + }) + }) + .collect(); + + block.transactions().for_each(|block_tx| { + let mut storage_changes = Vec::new(); + let mut balance_changes = Vec::new(); + let mut code_changes = Vec::new(); + + block_tx + .calls + .iter() + .filter(|call| { + !call.state_reverted + && inclusion_predicate(&call.address) + }) + .for_each(|call| { + storage_changes.extend(call.storage_changes.iter()); + balance_changes.extend(call.balance_changes.iter()); + code_changes.extend(call.code_changes.iter()); + }); + + storage_changes.sort_unstable_by_key(|change| change.ordinal); + balance_changes.sort_unstable_by_key(|change| change.ordinal); + code_changes.sort_unstable_by_key(|change| change.ordinal); + + storage_changes + .iter() + .filter(|changes| { + inclusion_predicate(&changes.address) + }) + .for_each(|storage_change| { + let contract_change = changed_contracts + .entry(storage_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: storage_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&storage_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + let slot_value = contract_change + .slots + .entry(storage_change.key.clone()) + .or_insert_with(|| SlotValue { + new_value: storage_change.new_value.clone(), + start_value: storage_change.old_value.clone(), + }); + + slot_value + .new_value + .copy_from_slice(&storage_change.new_value); + }); + + balance_changes + .iter() + .filter(|changes| { + inclusion_predicate(&changes.address) + }) + .for_each(|balance_change| { + let contract_change = changed_contracts + .entry(balance_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: balance_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&balance_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + if let Some(new_balance) = &balance_change.new_value { + contract_change.balance.clear(); + contract_change + .balance + .extend_from_slice(&new_balance.bytes); + } + }); + + code_changes + .iter() + .filter(|changes| { + inclusion_predicate(&changes.address) + }) + .for_each(|code_change| { + let contract_change = changed_contracts + .entry(code_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: code_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&code_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + contract_change.code.clear(); + contract_change + .code + .extend_from_slice(&code_change.new_code); + }); + + if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { + transaction_contract_changes + .entry(block_tx.index.into()) + .or_insert_with(|| tycho::TransactionContractChanges { + tx: Some(tycho::Transaction { + hash: block_tx.hash.clone(), + from: block_tx.from.clone(), + to: block_tx.to.clone(), + index: block_tx.index as u64, + }), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + }) + .contract_changes + .extend(changed_contracts.drain().map(|(_, change)| change.into())); + } + }); +} diff --git a/crates/tycho-substreams/src/lib.rs b/crates/tycho-substreams/src/lib.rs new file mode 100644 index 0000000..2f52c0e --- /dev/null +++ b/crates/tycho-substreams/src/lib.rs @@ -0,0 +1,2 @@ +pub mod contract; +pub mod pb; \ No newline at end of file diff --git a/crates/tycho-substreams/src/pb/mod.rs b/crates/tycho-substreams/src/pb/mod.rs new file mode 100644 index 0000000..43d8838 --- /dev/null +++ b/crates/tycho-substreams/src/pb/mod.rs @@ -0,0 +1,10 @@ +// @generated +pub mod tycho { + pub mod evm { + // @@protoc_insertion_point(attribute:tycho.evm.v1) + pub mod v1 { + include!("tycho.evm.v1.rs"); + // @@protoc_insertion_point(tycho.evm.v1) + } + } +} diff --git a/crates/tycho-substreams/src/pb/tycho.evm.v1.rs b/crates/tycho-substreams/src/pb/tycho.evm.v1.rs new file mode 100644 index 0000000..7424ba2 --- /dev/null +++ b/crates/tycho-substreams/src/pb/tycho.evm.v1.rs @@ -0,0 +1,309 @@ +// @generated +// This file contains the proto definitions for Substreams common to all integrations. + +/// A struct describing a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + /// The blocks hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The parent blocks hash. + #[prost(bytes="vec", tag="2")] + pub parent_hash: ::prost::alloc::vec::Vec, + /// The block number. + #[prost(uint64, tag="3")] + pub number: u64, + /// The block timestamp. + #[prost(uint64, tag="4")] + pub ts: u64, +} +/// A struct describing a transaction. +#[derive(Eq, Hash)] +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Transaction { + /// The transaction hash. + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, + /// The sender of the transaction. + #[prost(bytes="vec", tag="2")] + pub from: ::prost::alloc::vec::Vec, + /// The receiver of the transaction. + #[prost(bytes="vec", tag="3")] + pub to: ::prost::alloc::vec::Vec, + /// The transactions index within the block. + /// TODO: should this be uint32? to match the type from the native substream type? + #[prost(uint64, tag="4")] + pub index: u64, +} +/// A custom struct representing an arbitrary attribute of a protocol component. +/// This is mainly used by the native integration to track the necessary information about the protocol. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Attribute { + /// The name of the attribute. + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + /// The value of the attribute. + #[prost(bytes="vec", tag="2")] + pub value: ::prost::alloc::vec::Vec, + /// The type of change the attribute underwent. + #[prost(enumeration="ChangeType", tag="3")] + pub change: i32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolType { + #[prost(string, tag="1")] + pub name: ::prost::alloc::string::String, + #[prost(enumeration="FinancialType", tag="2")] + pub financial_type: i32, + #[prost(message, repeated, tag="3")] + pub attribute_schema: ::prost::alloc::vec::Vec, + #[prost(enumeration="ImplementationType", tag="4")] + pub implementation_type: i32, +} +/// A struct describing a part of the protocol. +/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, +/// the component would represent a single contract. In case of VM integration, such component would +/// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. +/// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. +/// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ProtocolComponent { + /// A unique identifier for the component within the protocol. + /// Can be e.g. a stringified address or a string describing the trading pair. + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + /// Addresses of the ERC20 tokens used by the component. + #[prost(bytes="vec", repeated, tag="2")] + pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Addresses of the contracts used by the component. + /// Usually it is a single contract, but some protocols use multiple contracts. + #[prost(bytes="vec", repeated, tag="3")] + pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, + /// Attributes of the component. Used mainly be the native integration. + /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. + #[prost(message, repeated, tag="4")] + pub static_att: ::prost::alloc::vec::Vec, + /// Type of change the component underwent. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, + /// / Represents the functionality of the component. + #[prost(message, optional, tag="6")] + pub protocol_type: ::core::option::Option, + /// Transaction where this component was created + #[prost(message, optional, tag="7")] + pub tx: ::core::option::Option, +} +/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. +/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. +/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceChange { + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="1")] + pub token: ::prost::alloc::vec::Vec, + /// The new balance of the token. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. + /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="3")] + pub component_id: ::prost::alloc::vec::Vec, +} +/// Enum to specify the type of a change. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ChangeType { + Unspecified = 0, + Update = 1, + Creation = 2, + Deletion = 3, +} +impl ChangeType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED", + ChangeType::Update => "CHANGE_TYPE_UPDATE", + ChangeType::Creation => "CHANGE_TYPE_CREATION", + ChangeType::Deletion => "CHANGE_TYPE_DELETION", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), + "CHANGE_TYPE_UPDATE" => Some(Self::Update), + "CHANGE_TYPE_CREATION" => Some(Self::Creation), + "CHANGE_TYPE_DELETION" => Some(Self::Deletion), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum FinancialType { + Swap = 0, + Lend = 1, + Leverage = 2, + Psm = 3, +} +impl FinancialType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + FinancialType::Swap => "SWAP", + FinancialType::Lend => "LEND", + FinancialType::Leverage => "LEVERAGE", + FinancialType::Psm => "PSM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "SWAP" => Some(Self::Swap), + "LEND" => Some(Self::Lend), + "LEVERAGE" => Some(Self::Leverage), + "PSM" => Some(Self::Psm), + _ => None, + } + } +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum ImplementationType { + Vm = 0, + Custom = 1, +} +impl ImplementationType { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ImplementationType::Vm => "VM", + ImplementationType::Custom => "CUSTOM", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "VM" => Some(Self::Vm), + "CUSTOM" => Some(Self::Custom), + _ => None, + } + } +} +// This file contains the definition for the native integration of Substreams. + +/// A component is a set of attributes that are associated with a custom entity. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct EntityChanges { + /// A unique identifier of the entity within the protocol. + #[prost(string, tag="1")] + pub component_id: ::prost::alloc::string::String, + /// The set of attributes that are associated with the entity. + #[prost(message, repeated, tag="2")] + pub attributes: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionEntityChanges { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub entity_changes: ::prost::alloc::vec::Vec, + /// An array of newly added components. + #[prost(message, repeated, tag="3")] + pub component_changes: ::prost::alloc::vec::Vec, + /// An array of balance changes to components. + #[prost(message, repeated, tag="4")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// A set of transaction changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockEntityChanges { + /// The block for which these changes are collectively computed. + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + /// The set of transaction changes observed in the specified block. + #[prost(message, repeated, tag="2")] + pub changes: ::prost::alloc::vec::Vec, +} +// This file contains proto definitions specific to the VM integration. + +/// A key value entry into contract storage. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractSlot { + /// A contract's storage slot. + #[prost(bytes="vec", tag="2")] + pub slot: ::prost::alloc::vec::Vec, + /// The new value for this storage slot. + #[prost(bytes="vec", tag="3")] + pub value: ::prost::alloc::vec::Vec, +} +/// Changes made to a single contract's state. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ContractChange { + /// The contract's address + #[prost(bytes="vec", tag="1")] + pub address: ::prost::alloc::vec::Vec, + /// The new native balance of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="2")] + pub balance: ::prost::alloc::vec::Vec, + /// The new code of the contract, empty bytes indicates no change. + #[prost(bytes="vec", tag="3")] + pub code: ::prost::alloc::vec::Vec, + /// The changes to this contract's slots, empty sequence indicates no change. + #[prost(message, repeated, tag="4")] + pub slots: ::prost::alloc::vec::Vec, + /// Whether this is an update, a creation or a deletion. + #[prost(enumeration="ChangeType", tag="5")] + pub change: i32, +} +/// A set of changes aggregated by transaction. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionContractChanges { + /// The transaction instance that results in the changes. + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. + /// Must include changes to every contract that is tracked by all ProtocolComponents. + #[prost(message, repeated, tag="2")] + pub contract_changes: ::prost::alloc::vec::Vec, + /// An array of any component changes. + #[prost(message, repeated, tag="3")] + pub component_changes: ::prost::alloc::vec::Vec, + /// An array of balance changes to components. + #[prost(message, repeated, tag="4")] + pub balance_changes: ::prost::alloc::vec::Vec, +} +/// A set of transaction changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockContractChanges { + /// The block for which these changes are collectively computed. + #[prost(message, optional, tag="1")] + pub block: ::core::option::Option, + /// The set of transaction changes observed in the specified block. + #[prost(message, repeated, tag="2")] + pub changes: ::prost::alloc::vec::Vec, +} +// @@protoc_insertion_point(module) From 3d248f3fa1e18a95efae60237e789d5a6ae6fba8 Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 18:46:10 +0000 Subject: [PATCH 68/86] Implement helpers for relative balances. Adds some helpers that will users help to convert relative balances changes to absolute ones. The goal is to make this as reduce the effort of the user to implementing a simple map handler that extracts relative balances changes. --- crates/tycho-substreams/Cargo.lock | 17 +- crates/tycho-substreams/Cargo.toml | 6 +- crates/tycho-substreams/rustfmt.toml | 13 + crates/tycho-substreams/src/balances.rs | 306 ++++++++++++++++++ crates/tycho-substreams/src/contract.rs | 245 +++++++------- crates/tycho-substreams/src/lib.rs | 6 +- crates/tycho-substreams/src/mock_store.rs | 93 ++++++ .../tycho-substreams/src/pb/tycho.evm.v1.rs | 51 ++- crates/tycho-substreams/src/utils.rs | 24 ++ 9 files changed, 632 insertions(+), 129 deletions(-) create mode 100644 crates/tycho-substreams/rustfmt.toml create mode 100644 crates/tycho-substreams/src/balances.rs create mode 100644 crates/tycho-substreams/src/mock_store.rs create mode 100644 crates/tycho-substreams/src/utils.rs diff --git a/crates/tycho-substreams/Cargo.lock b/crates/tycho-substreams/Cargo.lock index 5e61c4a..cd827d8 100644 --- a/crates/tycho-substreams/Cargo.lock +++ b/crates/tycho-substreams/Cargo.lock @@ -333,6 +333,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -530,7 +539,7 @@ checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" dependencies = [ "bytes", "heck", - "itertools", + "itertools 0.10.5", "lazy_static", "log", "multimap", @@ -551,7 +560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -908,6 +917,10 @@ dependencies = [ name = "tycho-substreams" version = "0.1.0" dependencies = [ + "hex", + "itertools 0.12.1", + "prost", + "substreams", "substreams-ethereum", ] diff --git a/crates/tycho-substreams/Cargo.toml b/crates/tycho-substreams/Cargo.toml index 269aea3..cc0f7bc 100644 --- a/crates/tycho-substreams/Cargo.toml +++ b/crates/tycho-substreams/Cargo.toml @@ -4,4 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -substreams-ethereum = "0.9.9" \ No newline at end of file +substreams-ethereum = "0.9.9" +substreams = "0.5" +prost = "0.11" +hex = "0.4.3" +itertools = "0.12.0" \ No newline at end of file diff --git a/crates/tycho-substreams/rustfmt.toml b/crates/tycho-substreams/rustfmt.toml new file mode 100644 index 0000000..d0c0193 --- /dev/null +++ b/crates/tycho-substreams/rustfmt.toml @@ -0,0 +1,13 @@ +reorder_imports = true +imports_granularity = "Crate" +use_small_heuristics = "Max" +comment_width = 100 +wrap_comments = true +binop_separator = "Back" +trailing_comma = "Vertical" +trailing_semicolon = false +use_field_init_shorthand = true +chain_width = 40 +ignore = [ + "src/pb", +] \ No newline at end of file diff --git a/crates/tycho-substreams/src/balances.rs b/crates/tycho-substreams/src/balances.rs new file mode 100644 index 0000000..dbc780a --- /dev/null +++ b/crates/tycho-substreams/src/balances.rs @@ -0,0 +1,306 @@ +//! Utilities to handle relative balances. +//! +//! +//! To aggregate relative balances changes to absolute balances the general approach is: +//! +//! 1. Use a map function that will extract a `BlockBalanceDeltas` message. BalanceDeltas +//! within this message are required to have increasing ordinals so that +//! the order of relative balance changes is unambiguous. +//! 2. Store the balances changes with a store handler. You can use the +//! `store_balance_changes` library method directly for this. +//! 3. In the output module, use aggregate_balance_changes to receive an +//! aggregated map of absolute balances. +//! +use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas}; +use itertools::Itertools; +use std::collections::HashMap; +use std::str::FromStr; +use substreams::key; +use substreams::pb::substreams::StoreDeltas; +use substreams::prelude::{BigInt, StoreAdd}; + +pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd) { + let mut previous_ordinal = HashMap::::new(); + deltas + .balance_deltas + .iter() + .for_each(|delta| { + let balance_key = format!( + "{0}:{1}", + String::from_utf8(delta.component_id.clone()) + .expect("delta.component_id is not valid utf-8!"), + hex::encode(&delta.token) + ); + let current_ord = delta.ord; + previous_ordinal + .entry(balance_key.clone()) + .and_modify(|ord| { + // ordinals must arrive in increasing order + if *ord >= current_ord { + panic!( + "Invalid ordinal sequence for {}: {} >= {}", + balance_key, *ord, current_ord + ); + } + *ord = current_ord; + }) + .or_insert(delta.ord); + store.add(delta.ord, balance_key, BigInt::from_signed_bytes_be(&delta.delta)); + }); +} + +pub fn aggregate_balances_changes( + balance_store: StoreDeltas, + deltas: BlockBalanceDeltas, +) -> HashMap, HashMap, BalanceChange>> { + balance_store + .deltas + .into_iter() + .zip(deltas.balance_deltas) + .map(|(store_delta, balance_delta)| { + let component_id = key::segment_at(&store_delta.key, 0); + let token_id = key::segment_at(&store_delta.key, 1); + // store_delta.new_value is an ASCII string representing an integer + let ascii_string = + String::from_utf8(store_delta.new_value.clone()).expect("Invalid UTF-8 sequence"); + let balance = BigInt::from_str(&ascii_string).expect("Failed to parse integer"); + let big_endian_bytes_balance = balance.to_bytes_be().1; + + ( + balance_delta.tx.unwrap(), + BalanceChange { + token: hex::decode(token_id).expect("Token ID not valid hex"), + balance: big_endian_bytes_balance, + component_id: component_id.as_bytes().to_vec(), + }, + ) + }) + // We need to group the balance changes by tx hash for the `TransactionContractChanges` agg + .group_by(|(tx, _)| tx.hash.clone()) + .into_iter() + .map(|(txh, group)| { + let balances = group + .into_iter() + .map(|(_, delta)| (delta.token.clone(), delta)) + .collect(); + (txh, balances) + }) + .collect() +} + +mod tests { + use super::*; + use crate::mock_store::MockStore; + use crate::pb::tycho::evm::v1::{BalanceDelta, Transaction}; + use substreams::pb::substreams::StoreDelta; + use substreams::prelude::{StoreGet, StoreNew}; + + fn block_balance_deltas() -> BlockBalanceDeltas { + let comp_id = "0x42c0ffee" + .to_string() + .as_bytes() + .to_vec(); + let token_0 = hex::decode("bad999").unwrap(); + let token_1 = hex::decode("babe00").unwrap(); + BlockBalanceDeltas { + balance_deltas: vec![ + BalanceDelta { + ord: 0, + tx: Some(Transaction { + hash: vec![0, 1], + from: vec![9, 9], + to: vec![8, 8], + index: 0, + }), + token: token_0.clone(), + delta: BigInt::from_str("+1000") + .unwrap() + .to_signed_bytes_be(), + component_id: comp_id.clone(), + }, + BalanceDelta { + ord: 2, + tx: Some(Transaction { + hash: vec![0, 1], + from: vec![9, 9], + to: vec![8, 8], + index: 0, + }), + token: token_1.clone(), + delta: BigInt::from_str("+100") + .unwrap() + .to_signed_bytes_be(), + component_id: comp_id.clone(), + }, + BalanceDelta { + ord: 3, + tx: Some(Transaction { + hash: vec![0, 1], + from: vec![9, 9], + to: vec![8, 8], + index: 0, + }), + token: token_1.clone(), + delta: BigInt::from_str("50") + .unwrap() + .to_signed_bytes_be(), + component_id: comp_id.clone(), + }, + BalanceDelta { + ord: 10, + tx: Some(Transaction { + hash: vec![0, 1], + from: vec![9, 9], + to: vec![8, 8], + index: 0, + }), + token: token_0.clone(), + delta: BigInt::from_str("-1") + .unwrap() + .to_signed_bytes_be(), + component_id: comp_id.clone(), + }, + ], + } + } + fn store_deltas() -> StoreDeltas { + let comp_id = "0x42c0ffee" + .to_string() + .as_bytes() + .to_vec(); + let token_0 = hex::decode("bad999").unwrap(); + let token_1 = hex::decode("babe00").unwrap(); + + let t0_key = + format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(&token_0)); + let t1_key = + format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(&token_1)); + StoreDeltas { + deltas: vec![ + StoreDelta { + operation: 0, + ordinal: 0, + key: t0_key.clone(), + old_value: BigInt::from(0) + .to_string() + .as_bytes() + .to_vec(), + new_value: BigInt::from(1000) + .to_string() + .as_bytes() + .to_vec(), + }, + StoreDelta { + operation: 0, + ordinal: 2, + key: t1_key.clone(), + old_value: BigInt::from(0) + .to_string() + .as_bytes() + .to_vec(), + new_value: BigInt::from(100) + .to_string() + .as_bytes() + .to_vec(), + }, + StoreDelta { + operation: 0, + ordinal: 3, + key: t1_key.clone(), + old_value: BigInt::from(100) + .to_string() + .as_bytes() + .to_vec(), + new_value: BigInt::from(150) + .to_string() + .as_bytes() + .to_vec(), + }, + StoreDelta { + operation: 0, + ordinal: 10, + key: t0_key.clone(), + old_value: BigInt::from(1000) + .to_string() + .as_bytes() + .to_vec(), + new_value: BigInt::from(999) + .to_string() + .as_bytes() + .to_vec(), + }, + ], + } + } + + #[test] + fn test_store_balances() { + let comp_id = "0x42c0ffee" + .to_string() + .as_bytes() + .to_vec(); + let token_0 = hex::decode("bad999").unwrap(); + let token_1 = hex::decode("babe00").unwrap(); + let deltas = block_balance_deltas(); + let store = ::new(); + + store_balance_changes(deltas, store.clone()); + let res_0 = store.get_last(format!( + "{}:{}", + String::from_utf8(comp_id.clone()).unwrap(), + hex::encode(&token_0) + )); + let res_1 = store.get_last(format!( + "{}:{}", + String::from_utf8(comp_id.clone()).unwrap(), + hex::encode(&token_1) + )); + + assert_eq!(res_0, Some(BigInt::from_str("+999").unwrap())); + assert_eq!(res_1, Some(BigInt::from_str("+150").unwrap())); + } + + #[test] + fn test_aggregate_balances_changes() { + let store_deltas = store_deltas(); + let balance_deltas = block_balance_deltas(); + let comp_id = "0x42c0ffee" + .to_string() + .as_bytes() + .to_vec(); + let token_0 = hex::decode("bad999").unwrap(); + let token_1 = hex::decode("babe00").unwrap(); + let exp = [( + vec![0, 1], + [ + ( + token_0.clone(), + BalanceChange { + token: token_0, + balance: BigInt::from(999) + .to_signed_bytes_be() + .to_vec(), + component_id: comp_id.clone(), + }, + ), + ( + token_1.clone(), + BalanceChange { + token: token_1, + balance: vec![150], + component_id: comp_id.clone(), + }, + ), + ] + .into_iter() + .collect(), + )] + .into_iter() + .collect(); + + let res = aggregate_balances_changes(store_deltas, balance_deltas); + dbg!(&res); + + assert_eq!(res, exp); + } +} diff --git a/crates/tycho-substreams/src/contract.rs b/crates/tycho-substreams/src/contract.rs index a0391b3..79ad454 100644 --- a/crates/tycho-substreams/src/contract.rs +++ b/crates/tycho-substreams/src/contract.rs @@ -22,7 +22,7 @@ impl SlotValue { } // Uses a map for slots, protobuf does not allow bytes in hashmap keys -pub struct InterimContractChange { +struct InterimContractChange { address: Vec, balance: Vec, code: Vec, @@ -40,17 +40,14 @@ impl From for tycho::ContractChange { .slots .into_iter() .filter(|(_, value)| value.has_changed()) - .map(|(slot, value)| tycho::ContractSlot { - slot, - value: value.new_value, - }) + .map(|(slot, value)| tycho::ContractSlot { slot, value: value.new_value }) .collect(), change: value.change.into(), } } } -pub fn extract_contract_changes bool >( +pub fn extract_contract_changes bool>( block: ð::v2::Block, inclusion_predicate: F, transaction_contract_changes: &mut HashMap, @@ -69,131 +66,131 @@ pub fn extract_contract_changes bool >( }) .collect(); - block.transactions().for_each(|block_tx| { - let mut storage_changes = Vec::new(); - let mut balance_changes = Vec::new(); - let mut code_changes = Vec::new(); + block + .transactions() + .for_each(|block_tx| { + let mut storage_changes = Vec::new(); + let mut balance_changes = Vec::new(); + let mut code_changes = Vec::new(); - block_tx - .calls - .iter() - .filter(|call| { - !call.state_reverted - && inclusion_predicate(&call.address) - }) - .for_each(|call| { - storage_changes.extend(call.storage_changes.iter()); - balance_changes.extend(call.balance_changes.iter()); - code_changes.extend(call.code_changes.iter()); - }); + block_tx + .calls + .iter() + .filter(|call| !call.state_reverted && inclusion_predicate(&call.address)) + .for_each(|call| { + storage_changes.extend(call.storage_changes.iter()); + balance_changes.extend(call.balance_changes.iter()); + code_changes.extend(call.code_changes.iter()); + }); - storage_changes.sort_unstable_by_key(|change| change.ordinal); - balance_changes.sort_unstable_by_key(|change| change.ordinal); - code_changes.sort_unstable_by_key(|change| change.ordinal); + storage_changes.sort_unstable_by_key(|change| change.ordinal); + balance_changes.sort_unstable_by_key(|change| change.ordinal); + code_changes.sort_unstable_by_key(|change| change.ordinal); - storage_changes - .iter() - .filter(|changes| { - inclusion_predicate(&changes.address) - }) - .for_each(|storage_change| { - let contract_change = changed_contracts - .entry(storage_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: storage_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&storage_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); + storage_changes + .iter() + .filter(|changes| inclusion_predicate(&changes.address)) + .for_each(|storage_change| { + let contract_change = changed_contracts + .entry(storage_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: storage_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&storage_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); - let slot_value = contract_change - .slots - .entry(storage_change.key.clone()) - .or_insert_with(|| SlotValue { - new_value: storage_change.new_value.clone(), - start_value: storage_change.old_value.clone(), - }); + let slot_value = contract_change + .slots + .entry(storage_change.key.clone()) + .or_insert_with(|| SlotValue { + new_value: storage_change.new_value.clone(), + start_value: storage_change.old_value.clone(), + }); - slot_value - .new_value - .copy_from_slice(&storage_change.new_value); - }); + slot_value + .new_value + .copy_from_slice(&storage_change.new_value); + }); - balance_changes - .iter() - .filter(|changes| { - inclusion_predicate(&changes.address) - }) - .for_each(|balance_change| { - let contract_change = changed_contracts - .entry(balance_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: balance_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&balance_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); + balance_changes + .iter() + .filter(|changes| inclusion_predicate(&changes.address)) + .for_each(|balance_change| { + let contract_change = changed_contracts + .entry(balance_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: balance_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&balance_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); - if let Some(new_balance) = &balance_change.new_value { - contract_change.balance.clear(); + if let Some(new_balance) = &balance_change.new_value { + contract_change.balance.clear(); + contract_change + .balance + .extend_from_slice(&new_balance.bytes); + } + }); + + code_changes + .iter() + .filter(|changes| inclusion_predicate(&changes.address)) + .for_each(|code_change| { + let contract_change = changed_contracts + .entry(code_change.address.clone()) + .or_insert_with(|| InterimContractChange { + address: code_change.address.clone(), + balance: Vec::new(), + code: Vec::new(), + slots: HashMap::new(), + change: if created_accounts.contains_key(&code_change.address) { + tycho::ChangeType::Creation + } else { + tycho::ChangeType::Update + }, + }); + + contract_change.code.clear(); contract_change - .balance - .extend_from_slice(&new_balance.bytes); - } - }); + .code + .extend_from_slice(&code_change.new_code); + }); - code_changes - .iter() - .filter(|changes| { - inclusion_predicate(&changes.address) - }) - .for_each(|code_change| { - let contract_change = changed_contracts - .entry(code_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: code_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&code_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); - - contract_change.code.clear(); - contract_change - .code - .extend_from_slice(&code_change.new_code); - }); - - if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { - transaction_contract_changes - .entry(block_tx.index.into()) - .or_insert_with(|| tycho::TransactionContractChanges { - tx: Some(tycho::Transaction { - hash: block_tx.hash.clone(), - from: block_tx.from.clone(), - to: block_tx.to.clone(), - index: block_tx.index as u64, - }), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - }) - .contract_changes - .extend(changed_contracts.drain().map(|(_, change)| change.into())); - } - }); + if !storage_changes.is_empty() + || !balance_changes.is_empty() + || !code_changes.is_empty() + { + transaction_contract_changes + .entry(block_tx.index.into()) + .or_insert_with(|| tycho::TransactionContractChanges { + tx: Some(tycho::Transaction { + hash: block_tx.hash.clone(), + from: block_tx.from.clone(), + to: block_tx.to.clone(), + index: block_tx.index as u64, + }), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + }) + .contract_changes + .extend( + changed_contracts + .drain() + .map(|(_, change)| change.into()), + ); + } + }); } diff --git a/crates/tycho-substreams/src/lib.rs b/crates/tycho-substreams/src/lib.rs index 2f52c0e..d5b0d0f 100644 --- a/crates/tycho-substreams/src/lib.rs +++ b/crates/tycho-substreams/src/lib.rs @@ -1,2 +1,6 @@ +pub mod balances; pub mod contract; -pub mod pb; \ No newline at end of file +mod mock_store; +pub mod pb; +// TODO: consider removing this module, after integrating with balancer +pub mod utils; diff --git a/crates/tycho-substreams/src/mock_store.rs b/crates/tycho-substreams/src/mock_store.rs new file mode 100644 index 0000000..a1c0cd2 --- /dev/null +++ b/crates/tycho-substreams/src/mock_store.rs @@ -0,0 +1,93 @@ +//! Contains a mock store for internal testing. +//! +//! Might make this public alter to users can test their store handlers. +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; +use substreams::prelude::{BigInt, StoreDelete, StoreGet, StoreNew}; +use substreams::store::StoreAdd; + +#[derive(Debug, Clone)] +pub struct MockStore { + data: Rc>>>, +} + +impl StoreDelete for MockStore { + fn delete_prefix(&self, _ord: i64, prefix: &String) { + self.data + .borrow_mut() + .retain(|k, _| !k.starts_with(prefix)); + } +} + +impl StoreNew for MockStore { + fn new() -> Self { + Self { data: Rc::new(RefCell::new(HashMap::new())) } + } +} + +impl StoreAdd for MockStore { + fn add>(&self, ord: u64, key: K, value: BigInt) { + let mut guard = self.data.borrow_mut(); + guard + .entry(key.as_ref().to_string()) + .and_modify(|v| { + let prev_value = v.last().unwrap().1.clone(); + v.push((ord, prev_value + value.clone())); + }) + .or_insert(vec![(ord, value)]); + } + + fn add_many>(&self, _ord: u64, _keys: &Vec, _value: BigInt) { + todo!() + } +} + +impl StoreGet for MockStore { + fn new(_idx: u32) -> Self { + Self { data: Rc::new(RefCell::new(HashMap::new())) } + } + + fn get_at>(&self, ord: u64, key: K) -> Option { + self.data + .borrow() + .get(&key.as_ref().to_string()) + .map(|v| { + v.iter() + .find(|(current_ord, _)| *current_ord == ord) + .unwrap() + .1 + .clone() + }) + } + + fn get_last>(&self, key: K) -> Option { + self.data + .borrow() + .get(&key.as_ref().to_string()) + .map(|v| v.last().unwrap().1.clone()) + } + + fn get_first>(&self, key: K) -> Option { + self.data + .borrow() + .get(&key.as_ref().to_string()) + .map(|v| v.first().unwrap().1.clone()) + } + + fn has_at>(&self, ord: u64, key: K) -> bool { + self.data + .borrow() + .get(&key.as_ref().to_string()) + .map(|v| v.iter().any(|(v, _)| *v == ord)) + .unwrap_or(false) + } + + fn has_last>(&self, _key: K) -> bool { + todo!() + } + + fn has_first>(&self, _key: K) -> bool { + todo!() + } +} diff --git a/crates/tycho-substreams/src/pb/tycho.evm.v1.rs b/crates/tycho-substreams/src/pb/tycho.evm.v1.rs index 7424ba2..5409eff 100644 --- a/crates/tycho-substreams/src/pb/tycho.evm.v1.rs +++ b/crates/tycho-substreams/src/pb/tycho.evm.v1.rs @@ -107,7 +107,7 @@ pub struct BalanceChange { /// The address of the ERC20 token whose balance changed. #[prost(bytes="vec", tag="1")] pub token: ::prost::alloc::vec::Vec, - /// The new balance of the token. + /// The new balance of the token. Note: it must be a big endian encoded int. #[prost(bytes="vec", tag="2")] pub balance: ::prost::alloc::vec::Vec, /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. @@ -244,6 +244,55 @@ pub struct BlockEntityChanges { #[prost(message, repeated, tag="2")] pub changes: ::prost::alloc::vec::Vec, } +/// A message containing relative balance changes. +/// +/// Used to track token balances of protocol components in case they are only +/// available as relative values within a block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BalanceDelta { + /// The ordinal of the balance change. Must be unique & deterministic over all balances + /// changes within a block. + #[prost(uint64, tag="1")] + pub ord: u64, + /// The tx hash of the transaction that caused the balance change. + #[prost(message, optional, tag="2")] + pub tx: ::core::option::Option, + /// The address of the ERC20 token whose balance changed. + #[prost(bytes="vec", tag="3")] + pub token: ::prost::alloc::vec::Vec, + /// The delta balance of the token. + #[prost(bytes="vec", tag="4")] + pub delta: ::prost::alloc::vec::Vec, + /// The id of the component whose TVL is tracked. + /// If the protocol component includes multiple contracts, the balance change must be + /// aggregated to reflect how much tokens can be traded. + #[prost(bytes="vec", tag="5")] + pub component_id: ::prost::alloc::vec::Vec, +} +/// A set of balances deltas, usually a group of changes within a single block. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockBalanceDeltas { + #[prost(message, repeated, tag="1")] + pub balance_deltas: ::prost::alloc::vec::Vec, +} +/// A message containing protocol components that were created by a single tx. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TransactionProtocolComponents { + #[prost(message, optional, tag="1")] + pub tx: ::core::option::Option, + #[prost(message, repeated, tag="2")] + pub components: ::prost::alloc::vec::Vec, +} +/// All protocol components that were created within a block with their corresponding tx. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct BlockTransactionProtocolComponents { + #[prost(message, repeated, tag="1")] + pub tx_components: ::prost::alloc::vec::Vec, +} // This file contains proto definitions specific to the VM integration. /// A key value entry into contract storage. diff --git a/crates/tycho-substreams/src/utils.rs b/crates/tycho-substreams/src/utils.rs new file mode 100644 index 0000000..e4729db --- /dev/null +++ b/crates/tycho-substreams/src/utils.rs @@ -0,0 +1,24 @@ +use crate::pb::tycho::evm::v1::Transaction; + +/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in +/// a later groupby operation. +#[derive(Debug)] +pub struct TransactionWrapper(Transaction); + +impl TransactionWrapper { + pub fn new(tx: Transaction) -> Self { + Self(tx) + } +} + +impl PartialEq for TransactionWrapper { + fn eq(&self, other: &Self) -> bool { + self.0.hash == other.0.hash + } +} + +impl From for Transaction { + fn from(value: TransactionWrapper) -> Self { + value.0 + } +} From d9fe9b1e1cad391413d2a14bb144554dbb4ab633 Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 21:06:55 +0000 Subject: [PATCH 69/86] Integrate balancer substream with sdk. We defer the contract storage extraction as well as the balance handling (apart from actually extracing relative deltas) to the SDK. --- crates/tycho-substreams/src/balances.rs | 65 ++-- crates/tycho-substreams/src/pb/mod.rs | 11 + substreams/ethereum-balancer/Cargo.lock | 12 + substreams/ethereum-balancer/Cargo.toml | 1 + .../ethereum-balancer/src/contract_changes.rs | 211 ------------ substreams/ethereum-balancer/src/lib.rs | 2 - substreams/ethereum-balancer/src/modules.rs | 115 +++---- substreams/ethereum-balancer/src/pb/mod.rs | 10 - .../ethereum-balancer/src/pb/tycho.evm.v1.rs | 319 ------------------ .../ethereum-balancer/src/pool_factories.rs | 6 +- 10 files changed, 102 insertions(+), 650 deletions(-) delete mode 100644 substreams/ethereum-balancer/src/contract_changes.rs delete mode 100644 substreams/ethereum-balancer/src/pb/mod.rs delete mode 100644 substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs diff --git a/crates/tycho-substreams/src/balances.rs b/crates/tycho-substreams/src/balances.rs index dbc780a..2547723 100644 --- a/crates/tycho-substreams/src/balances.rs +++ b/crates/tycho-substreams/src/balances.rs @@ -11,7 +11,7 @@ //! 3. In the output module, use aggregate_balance_changes to receive an //! aggregated map of absolute balances. //! -use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas}; +use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas, Transaction}; use itertools::Itertools; use std::collections::HashMap; use std::str::FromStr; @@ -52,7 +52,7 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd HashMap, HashMap, BalanceChange>> { +) -> HashMap, (Transaction, HashMap, BalanceChange>)> { balance_store .deltas .into_iter() @@ -79,15 +79,18 @@ pub fn aggregate_balances_changes( .group_by(|(tx, _)| tx.hash.clone()) .into_iter() .map(|(txh, group)| { - let balances = group + let (mut transactions, balance_changes): (Vec<_>, Vec<_>) = group.into_iter().unzip(); + + let balances = balance_changes .into_iter() - .map(|(_, delta)| (delta.token.clone(), delta)) + .map(|balance_change| (balance_change.token.clone(), balance_change)) .collect(); - (txh, balances) + (txh, (transactions.pop().unwrap(), balances)) }) .collect() } +#[cfg(test)] mod tests { use super::*; use crate::mock_store::MockStore; @@ -270,37 +273,39 @@ mod tests { .to_vec(); let token_0 = hex::decode("bad999").unwrap(); let token_1 = hex::decode("babe00").unwrap(); + let exp = [( vec![0, 1], - [ - ( - token_0.clone(), - BalanceChange { - token: token_0, - balance: BigInt::from(999) - .to_signed_bytes_be() - .to_vec(), - component_id: comp_id.clone(), - }, - ), - ( - token_1.clone(), - BalanceChange { - token: token_1, - balance: vec![150], - component_id: comp_id.clone(), - }, - ), - ] - .into_iter() - .collect(), + ( + Transaction { hash: vec![0, 1], from: vec![9, 9], to: vec![8, 8], index: 0 }, + [ + ( + token_0.clone(), + BalanceChange { + token: token_0, + balance: BigInt::from(999) + .to_signed_bytes_be() + .to_vec(), + component_id: comp_id.clone(), + }, + ), + ( + token_1.clone(), + BalanceChange { + token: token_1, + balance: vec![150], + component_id: comp_id.clone(), + }, + ), + ] + .into_iter() + .collect::>(), + ), )] .into_iter() - .collect(); + .collect::>(); let res = aggregate_balances_changes(store_deltas, balance_deltas); - dbg!(&res); - assert_eq!(res, exp); } } diff --git a/crates/tycho-substreams/src/pb/mod.rs b/crates/tycho-substreams/src/pb/mod.rs index 43d8838..f5cd0b0 100644 --- a/crates/tycho-substreams/src/pb/mod.rs +++ b/crates/tycho-substreams/src/pb/mod.rs @@ -5,6 +5,17 @@ pub mod tycho { pub mod v1 { include!("tycho.evm.v1.rs"); // @@protoc_insertion_point(tycho.evm.v1) + + impl TransactionContractChanges { + pub fn new(tx: &Transaction) -> Self { + Self { + tx: Some(tx.clone()), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + } + } + } } } } diff --git a/substreams/ethereum-balancer/Cargo.lock b/substreams/ethereum-balancer/Cargo.lock index b05dce5..e2d81a0 100644 --- a/substreams/ethereum-balancer/Cargo.lock +++ b/substreams/ethereum-balancer/Cargo.lock @@ -931,6 +931,7 @@ dependencies = [ "prost-types 0.12.3", "substreams", "substreams-ethereum", + "tycho-substreams", ] [[package]] @@ -1064,6 +1065,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "tycho-substreams" +version = "0.1.0" +dependencies = [ + "hex", + "itertools 0.12.0", + "prost 0.11.9", + "substreams", + "substreams-ethereum", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml index ace53d3..0a964e5 100644 --- a/substreams/ethereum-balancer/Cargo.toml +++ b/substreams/ethereum-balancer/Cargo.toml @@ -19,6 +19,7 @@ anyhow = "1.0.75" prost-types = "0.12.3" num-bigint = "0.4.4" itertools = "0.12.0" +tycho-substreams = {path ="../../crates/tycho-substreams"} [build-dependencies] anyhow = "1" diff --git a/substreams/ethereum-balancer/src/contract_changes.rs b/substreams/ethereum-balancer/src/contract_changes.rs deleted file mode 100644 index 664b0e7..0000000 --- a/substreams/ethereum-balancer/src/contract_changes.rs +++ /dev/null @@ -1,211 +0,0 @@ -/// This file contains helpers to capture contract changes from the expanded block model. These -/// leverage the `code_changes`, `balance_changes`, and `storage_changes` fields available on the -/// `Call` type provided by block model in a substream (i.e. `logs_and_calls`, etc). -/// -/// ⚠️ These helpers *only* work if the **expanded block model** is available, more info blow. -/// https://streamingfastio.medium.com/new-block-model-to-accelerate-chain-integration-9f65126e5425 -use std::collections::HashMap; - -use substreams_ethereum::pb::eth; - -use pb::tycho::evm::v1::{self as tycho}; - -use substreams::store::{StoreGet, StoreGetInt64}; - -use crate::pb; - -struct SlotValue { - new_value: Vec, - start_value: Vec, -} - -impl SlotValue { - fn has_changed(&self) -> bool { - self.start_value != self.new_value - } -} - -// Uses a map for slots, protobuf does not allow bytes in hashmap keys -pub struct InterimContractChange { - address: Vec, - balance: Vec, - code: Vec, - slots: HashMap, SlotValue>, - change: tycho::ChangeType, -} - -impl From for tycho::ContractChange { - fn from(value: InterimContractChange) -> Self { - tycho::ContractChange { - address: value.address, - balance: value.balance, - code: value.code, - slots: value - .slots - .into_iter() - .filter(|(_, value)| value.has_changed()) - .map(|(slot, value)| tycho::ContractSlot { - slot, - value: value.new_value, - }) - .collect(), - change: value.change.into(), - } - } -} - -pub fn extract_contract_changes( - block: ð::v2::Block, - contracts: StoreGetInt64, - transaction_contract_changes: &mut HashMap, -) { - let mut changed_contracts: HashMap, InterimContractChange> = HashMap::new(); - - // Collect all accounts created in this block - let created_accounts: HashMap<_, _> = block - .transactions() - .flat_map(|tx| { - tx.calls.iter().flat_map(|call| { - call.account_creations - .iter() - .map(|ac| (&ac.account, ac.ordinal)) - }) - }) - .collect(); - - block.transactions().for_each(|block_tx| { - let mut storage_changes = Vec::new(); - let mut balance_changes = Vec::new(); - let mut code_changes = Vec::new(); - - block_tx - .calls - .iter() - .filter(|call| { - !call.state_reverted - && contracts - .get_last(format!("pool:{0}", hex::encode(&call.address))) - .is_some() - }) - .for_each(|call| { - storage_changes.extend(call.storage_changes.iter()); - balance_changes.extend(call.balance_changes.iter()); - code_changes.extend(call.code_changes.iter()); - }); - - storage_changes.sort_unstable_by_key(|change| change.ordinal); - balance_changes.sort_unstable_by_key(|change| change.ordinal); - code_changes.sort_unstable_by_key(|change| change.ordinal); - - storage_changes - .iter() - .filter(|changes| { - contracts - .get_last(format!("pool:{0}", hex::encode(&changes.address))) - .is_some() - }) - .for_each(|storage_change| { - let contract_change = changed_contracts - .entry(storage_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: storage_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&storage_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); - - let slot_value = contract_change - .slots - .entry(storage_change.key.clone()) - .or_insert_with(|| SlotValue { - new_value: storage_change.new_value.clone(), - start_value: storage_change.old_value.clone(), - }); - - slot_value - .new_value - .copy_from_slice(&storage_change.new_value); - }); - - balance_changes - .iter() - .filter(|changes| { - contracts - .get_last(format!("pool:{0}", hex::encode(&changes.address))) - .is_some() - }) - .for_each(|balance_change| { - let contract_change = changed_contracts - .entry(balance_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: balance_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&balance_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); - - if let Some(new_balance) = &balance_change.new_value { - contract_change.balance.clear(); - contract_change - .balance - .extend_from_slice(&new_balance.bytes); - } - }); - - code_changes - .iter() - .filter(|changes| { - contracts - .get_last(format!("pool:{0}", hex::encode(&changes.address))) - .is_some() - }) - .for_each(|code_change| { - let contract_change = changed_contracts - .entry(code_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: code_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&code_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, - }); - - contract_change.code.clear(); - contract_change - .code - .extend_from_slice(&code_change.new_code); - }); - - if !storage_changes.is_empty() || !balance_changes.is_empty() || !code_changes.is_empty() { - transaction_contract_changes - .entry(block_tx.index.into()) - .or_insert_with(|| tycho::TransactionContractChanges { - tx: Some(tycho::Transaction { - hash: block_tx.hash.clone(), - from: block_tx.from.clone(), - to: block_tx.to.clone(), - index: block_tx.index as u64, - }), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - }) - .contract_changes - .extend(changed_contracts.drain().map(|(_, change)| change.into())); - } - }); -} diff --git a/substreams/ethereum-balancer/src/lib.rs b/substreams/ethereum-balancer/src/lib.rs index 88ecc50..27bd15a 100644 --- a/substreams/ethereum-balancer/src/lib.rs +++ b/substreams/ethereum-balancer/src/lib.rs @@ -1,5 +1,3 @@ mod abi; -mod contract_changes; mod modules; -mod pb; mod pool_factories; diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index c4fcb4a..9923167 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -1,27 +1,20 @@ -use std::collections::HashMap; -use std::str::FromStr; - +use crate::{abi, pool_factories}; use anyhow::Result; +use itertools::Itertools; +use std::collections::HashMap; use substreams::hex; use substreams::pb::substreams::StoreDeltas; use substreams::store::{ StoreAdd, StoreAddBigInt, StoreAddInt64, StoreGet, StoreGetInt64, StoreNew, }; - -use substreams::key; -use substreams::scalar::BigInt; - use substreams_ethereum::pb::eth; - -use itertools::Itertools; - - -use contract_changes::extract_contract_changes; use substreams_ethereum::Event; - -use crate::pb::tycho::evm::v1::{self as tycho}; -use crate::pb::tycho::evm::v1::{BalanceDelta, BlockBalanceDeltas, BlockTransactionProtocolComponents, TransactionProtocolComponents}; -use crate::{abi, contract_changes, pool_factories}; +use tycho_substreams::balances; +use tycho_substreams::contract::extract_contract_changes; +use tycho_substreams::pb::tycho::evm::v1::{ + self as tycho, BalanceDelta, BlockBalanceDeltas, BlockTransactionProtocolComponents, + TransactionProtocolComponents, +}; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -110,7 +103,13 @@ pub fn map_balance_deltas( if let Some(ev) = abi::vault::events::PoolBalanceChanged::match_and_decode(vault_log.log) { - let component_id = ev.pool_id[..20].to_vec(); + let component_id = format!( + "0x{}", + String::from_utf8(ev.pool_id[..20].to_vec()).unwrap() + ) + .as_bytes() + .to_vec(); + if store .get_last(format!("pool:{}", hex::encode(&component_id))) .is_some() @@ -131,7 +130,13 @@ pub fn map_balance_deltas( } } } else if let Some(ev) = abi::vault::events::Swap::match_and_decode(vault_log.log) { - let component_id = ev.pool_id[..20].to_vec(); + let component_id = format!( + "0x{}", + String::from_utf8(ev.pool_id[..20].to_vec()).unwrap() + ) + .as_bytes() + .to_vec(); + if store .get_last(format!("pool:{}", hex::encode(&component_id))) .is_some() @@ -176,17 +181,7 @@ pub fn map_balance_deltas( /// store key to ensure that there's a unique balance being tallied for each. #[substreams::handlers::store] pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { - deltas.balance_deltas.iter().for_each(|delta| { - store.add( - delta.ord, - format!( - "pool:{0}:token:{1}", - hex::encode(&delta.component_id), - hex::encode(&delta.token) - ), - BigInt::from_signed_bytes_be(&delta.delta), - ); - }); + balances::store_balance_changes(deltas, store); } /// This is the main map that handles most of the indexing of this substream. @@ -215,67 +210,37 @@ pub fn map_changes( .iter() .for_each(|tx_component| { let tx = tx_component.tx.as_ref().unwrap(); - transaction_contract_changes .entry(tx.index) - .or_insert_with(|| tycho::TransactionContractChanges { - tx: Some(tx.clone()), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - }) + .or_insert_with(|| tycho::TransactionContractChanges::new(&tx)) .component_changes .extend_from_slice(&tx_component.components); }); // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating - // `BlockBalanceDeltas`. We essentially just process the changes that occured to the `store` this + // `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store` this // block. Then, these balance changes are merged onto the existing map of tx contract changes, // inserting a new one if it doesn't exist. - balance_store - .deltas + balances::aggregate_balances_changes(balance_store, deltas) .into_iter() - .zip(deltas.balance_deltas) - .map(|(store_delta, balance_delta)| { - let pool_id = key::segment_at(&store_delta.key, 1); - let token_id = key::segment_at(&store_delta.key, 3); - // store_delta.new_value is an ASCII string representing an integer - let ascii_string = - String::from_utf8(store_delta.new_value.clone()).expect("Invalid UTF-8 sequence"); - let balance = BigInt::from_str(&ascii_string).expect("Failed to parse integer"); - let big_endian_bytes_balance = balance.to_bytes_be().1; - - ( - balance_delta.tx.unwrap(), - tycho::BalanceChange { - token: hex::decode(token_id).expect("Token ID not valid hex"), - balance: big_endian_bytes_balance, - component_id: pool_id.as_bytes().to_vec(), - }, - ) - }) - // We need to group the balance changes by tx hash for the `TransactionContractChanges` agg - .group_by(|(tx, _)| TransactionWrapper(tx.clone())) - .into_iter() - .for_each(|(tx_wrapped, group)| { - let tx = tx_wrapped.0; - + .for_each(|(_, (tx, balances))| { transaction_contract_changes .entry(tx.index) - .or_insert_with(|| tycho::TransactionContractChanges { - tx: Some(tx.clone()), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - }) + .or_insert_with(|| tycho::TransactionContractChanges::new(&tx)) .balance_changes - .extend(group.map(|(_, change)| change)); + .extend(balances.into_iter().map(|(_, change)| change)); }); - // General helper for extracting contract changes. Uses block, our component store which holds - // all of our tracked deployed pool addresses, and the map of tx contract changes which we - // output into for final processing later. - extract_contract_changes(&block, components_store, &mut transaction_contract_changes); + // Extract and insert any storage changes that happened for any of the components. + extract_contract_changes( + &block, + |addr| { + components_store + .get_last(format!("pool:{0}", hex::encode(&addr))) + .is_some() + }, + &mut transaction_contract_changes, + ); // Process all `transaction_contract_changes` for final output in the `BlockContractChanges`, // sorted by transaction index (the key). diff --git a/substreams/ethereum-balancer/src/pb/mod.rs b/substreams/ethereum-balancer/src/pb/mod.rs deleted file mode 100644 index 43d8838..0000000 --- a/substreams/ethereum-balancer/src/pb/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -// @generated -pub mod tycho { - pub mod evm { - // @@protoc_insertion_point(attribute:tycho.evm.v1) - pub mod v1 { - include!("tycho.evm.v1.rs"); - // @@protoc_insertion_point(tycho.evm.v1) - } - } -} diff --git a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs b/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs deleted file mode 100644 index 387ff7b..0000000 --- a/substreams/ethereum-balancer/src/pb/tycho.evm.v1.rs +++ /dev/null @@ -1,319 +0,0 @@ -// @generated -// This file contains the proto definitions for Substreams common to all integrations. - -/// A struct describing a block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Block { - /// The blocks hash. - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, - /// The parent blocks hash. - #[prost(bytes="vec", tag="2")] - pub parent_hash: ::prost::alloc::vec::Vec, - /// The block number. - #[prost(uint64, tag="3")] - pub number: u64, - /// The block timestamp. - #[prost(uint64, tag="4")] - pub ts: u64, -} -/// A struct describing a transaction. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transaction { - /// The transaction hash. - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, - /// The sender of the transaction. - #[prost(bytes="vec", tag="2")] - pub from: ::prost::alloc::vec::Vec, - /// The receiver of the transaction. - #[prost(bytes="vec", tag="3")] - pub to: ::prost::alloc::vec::Vec, - /// The transactions index within the block. - /// TODO: should this be uint32? to match the type from the native substream type? - #[prost(uint64, tag="4")] - pub index: u64, -} -/// A custom struct representing an arbitrary attribute of a protocol component. -/// This is mainly used by the native integration to track the necessary information about the protocol. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Attribute { - /// The name of the attribute. - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - /// The value of the attribute. - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, - /// The type of change the attribute underwent. - #[prost(enumeration="ChangeType", tag="3")] - pub change: i32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProtocolType { - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - #[prost(enumeration="FinancialType", tag="2")] - pub financial_type: i32, - #[prost(message, repeated, tag="3")] - pub attribute_schema: ::prost::alloc::vec::Vec, - #[prost(enumeration="ImplementationType", tag="4")] - pub implementation_type: i32, -} -/// A struct describing a part of the protocol. -/// Note: For example this can be a UniswapV2 pair, that tracks the two ERC20 tokens used by the pair, -/// the component would represent a single contract. In case of VM integration, such component would -/// not need any attributes, because all the relevant info would be tracked via storage slots and balance changes. -/// It can also be a wrapping contract, like WETH, that has a constant price, but it allows swapping tokens. -/// This is why the name ProtocolComponent is used instead of "Pool" or "Pair". -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProtocolComponent { - /// A unique identifier for the component within the protocol. - /// Can be e.g. a stringified address or a string describing the trading pair. - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - /// Addresses of the ERC20 tokens used by the component. - #[prost(bytes="vec", repeated, tag="2")] - pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, - /// Addresses of the contracts used by the component. - /// Usually it is a single contract, but some protocols use multiple contracts. - #[prost(bytes="vec", repeated, tag="3")] - pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, - /// Attributes of the component. Used mainly be the native integration. - /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. - #[prost(message, repeated, tag="4")] - pub static_att: ::prost::alloc::vec::Vec, - /// Type of change the component underwent. - #[prost(enumeration="ChangeType", tag="5")] - pub change: i32, - /// / Represents the functionality of the component. - #[prost(message, optional, tag="6")] - pub protocol_type: ::core::option::Option, - /// Transaction where this component was created - #[prost(message, optional, tag="7")] - pub tx: ::core::option::Option, -} -/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. -/// Note that if a ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. -/// E.g. for UniswapV2 pair WETH/USDC, this tracks the USDC and WETH balance of the pair contract. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceChange { - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="1")] - pub token: ::prost::alloc::vec::Vec, - /// The new balance of the token. Note: it must be a big endian encoded int. - #[prost(bytes="vec", tag="2")] - pub balance: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. Note: This MUST be utf8 encoded. - /// If the protocol component includes multiple contracts, the balance change must be aggregated to reflect how much tokens can be traded. - #[prost(bytes="vec", tag="3")] - pub component_id: ::prost::alloc::vec::Vec, -} -/// Enum to specify the type of a change. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ChangeType { - Unspecified = 0, - Update = 1, - Creation = 2, - Deletion = 3, -} -impl ChangeType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED", - ChangeType::Update => "CHANGE_TYPE_UPDATE", - ChangeType::Creation => "CHANGE_TYPE_CREATION", - ChangeType::Deletion => "CHANGE_TYPE_DELETION", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), - "CHANGE_TYPE_UPDATE" => Some(Self::Update), - "CHANGE_TYPE_CREATION" => Some(Self::Creation), - "CHANGE_TYPE_DELETION" => Some(Self::Deletion), - _ => None, - } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum FinancialType { - Swap = 0, - Lend = 1, - Leverage = 2, - Psm = 3, -} -impl FinancialType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - FinancialType::Swap => "SWAP", - FinancialType::Lend => "LEND", - FinancialType::Leverage => "LEVERAGE", - FinancialType::Psm => "PSM", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "SWAP" => Some(Self::Swap), - "LEND" => Some(Self::Lend), - "LEVERAGE" => Some(Self::Leverage), - "PSM" => Some(Self::Psm), - _ => None, - } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ImplementationType { - Vm = 0, - Custom = 1, -} -impl ImplementationType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ImplementationType::Vm => "VM", - ImplementationType::Custom => "CUSTOM", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "VM" => Some(Self::Vm), - "CUSTOM" => Some(Self::Custom), - _ => None, - } - } -} -// This file contains proto definitions specific to the VM integration. - -/// A key value entry into contract storage. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ContractSlot { - /// A contract's storage slot. - #[prost(bytes="vec", tag="2")] - pub slot: ::prost::alloc::vec::Vec, - /// The new value for this storage slot. - #[prost(bytes="vec", tag="3")] - pub value: ::prost::alloc::vec::Vec, -} -/// Changes made to a single contract's state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ContractChange { - /// The contract's address - #[prost(bytes="vec", tag="1")] - pub address: ::prost::alloc::vec::Vec, - /// The new native balance of the contract, empty bytes indicates no change. - #[prost(bytes="vec", tag="2")] - pub balance: ::prost::alloc::vec::Vec, - /// The new code of the contract, empty bytes indicates no change. - #[prost(bytes="vec", tag="3")] - pub code: ::prost::alloc::vec::Vec, - /// The changes to this contract's slots, empty sequence indicates no change. - #[prost(message, repeated, tag="4")] - pub slots: ::prost::alloc::vec::Vec, - /// Whether this is an update, a creation or a deletion. - #[prost(enumeration="ChangeType", tag="5")] - pub change: i32, -} -/// A set of changes aggregated by transaction. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionContractChanges { - /// The transaction instance that results in the changes. - #[prost(message, optional, tag="1")] - pub tx: ::core::option::Option, - /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. - /// Must include changes to every contract that is tracked by all ProtocolComponents. - #[prost(message, repeated, tag="2")] - pub contract_changes: ::prost::alloc::vec::Vec, - /// An array of any component changes. - #[prost(message, repeated, tag="3")] - pub component_changes: ::prost::alloc::vec::Vec, - /// An array of balance changes to components. - #[prost(message, repeated, tag="4")] - pub balance_changes: ::prost::alloc::vec::Vec, -} -/// A set of transaction changes within a single block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockContractChanges { - /// The block for which these changes are collectively computed. - #[prost(message, optional, tag="1")] - pub block: ::core::option::Option, - /// The set of transaction changes observed in the specified block. - #[prost(message, repeated, tag="2")] - pub changes: ::prost::alloc::vec::Vec, -} -/// A message containing relative balance changes. -/// -/// Used to track token balances of protocol components in case they are only -/// available as relative values within a block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceDelta { - /// The ordinal of the balance change. Must be unique & deterministic over all balances - /// changes within a block. - #[prost(uint64, tag="1")] - pub ord: u64, - /// The tx hash of the transaction that caused the balance change. - #[prost(message, optional, tag="2")] - pub tx: ::core::option::Option, - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="3")] - pub token: ::prost::alloc::vec::Vec, - /// The delta balance of the token. - #[prost(bytes="vec", tag="4")] - pub delta: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. - /// If the protocol component includes multiple contracts, the balance change must be - /// aggregated to reflect how much tokens can be traded. - #[prost(bytes="vec", tag="5")] - pub component_id: ::prost::alloc::vec::Vec, -} -/// A set of balances deltas, usually a group of changes within a single block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockBalanceDeltas { - #[prost(message, repeated, tag="1")] - pub balance_deltas: ::prost::alloc::vec::Vec, -} -/// A message containing protocol components that were created by a single tx. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionProtocolComponents { - #[prost(message, optional, tag="1")] - pub tx: ::core::option::Option, - #[prost(message, repeated, tag="2")] - pub components: ::prost::alloc::vec::Vec, -} -/// All protocol components that were created within a block with their corresponding tx. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockTransactionProtocolComponents { - #[prost(message, repeated, tag="1")] - pub tx_components: ::prost::alloc::vec::Vec, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index e19933c..27c5ced 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -2,10 +2,10 @@ use substreams_ethereum::pb::eth::v2::{Call, Log}; use substreams_ethereum::{Event, Function}; use crate::abi; -use crate::pb; -use crate::pb::tycho::evm::v1::{FinancialType, ImplementationType, ProtocolType, Transaction}; -use pb::tycho::evm::v1::{self as tycho}; use substreams::hex; +use tycho_substreams::pb::tycho::evm::v1::{ + self as tycho, FinancialType, ImplementationType, ProtocolType, Transaction, +}; use substreams::scalar::BigInt; From 18e9dfcec497aea9715671e5df65086ca2ca3bb4 Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 21:07:46 +0000 Subject: [PATCH 70/86] Remove TransactionWrapper from SDK & Balancer. This type is not needed anymore. --- crates/tycho-substreams/src/lib.rs | 2 -- crates/tycho-substreams/src/utils.rs | 24 --------------------- substreams/ethereum-balancer/src/modules.rs | 11 ---------- 3 files changed, 37 deletions(-) delete mode 100644 crates/tycho-substreams/src/utils.rs diff --git a/crates/tycho-substreams/src/lib.rs b/crates/tycho-substreams/src/lib.rs index d5b0d0f..78c7e2e 100644 --- a/crates/tycho-substreams/src/lib.rs +++ b/crates/tycho-substreams/src/lib.rs @@ -2,5 +2,3 @@ pub mod balances; pub mod contract; mod mock_store; pub mod pb; -// TODO: consider removing this module, after integrating with balancer -pub mod utils; diff --git a/crates/tycho-substreams/src/utils.rs b/crates/tycho-substreams/src/utils.rs deleted file mode 100644 index e4729db..0000000 --- a/crates/tycho-substreams/src/utils.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::pb::tycho::evm::v1::Transaction; - -/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in -/// a later groupby operation. -#[derive(Debug)] -pub struct TransactionWrapper(Transaction); - -impl TransactionWrapper { - pub fn new(tx: Transaction) -> Self { - Self(tx) - } -} - -impl PartialEq for TransactionWrapper { - fn eq(&self, other: &Self) -> bool { - self.0.hash == other.0.hash - } -} - -impl From for Transaction { - fn from(value: TransactionWrapper) -> Self { - value.0 - } -} diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 9923167..a3658ad 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -18,17 +18,6 @@ use tycho_substreams::pb::tycho::evm::v1::{ const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); -/// This struct purely exists to spoof the `PartialEq` trait for `Transaction` so we can use it in -/// a later groupby operation. -#[derive(Debug)] -struct TransactionWrapper(tycho::Transaction); - -impl PartialEq for TransactionWrapper { - fn eq(&self, other: &Self) -> bool { - self.0.hash == other.0.hash - } -} - #[substreams::handlers::map] pub fn map_pools_created(block: eth::v2::Block) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call From 312d322585f2e2dd91bf2f11e43ed56614f569a1 Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 22:10:54 +0000 Subject: [PATCH 71/86] Add tycho pb type constructors. This allows us to remove a lot of unnecessary boilerplate code. --- crates/tycho-substreams/src/contract.rs | 87 +++--- crates/tycho-substreams/src/pb/mod.rs | 99 +++++++ substreams/ethereum-balancer/src/modules.rs | 47 +--- .../ethereum-balancer/src/pool_factories.rs | 261 ++++++------------ 4 files changed, 228 insertions(+), 266 deletions(-) diff --git a/crates/tycho-substreams/src/contract.rs b/crates/tycho-substreams/src/contract.rs index 79ad454..633ef35 100644 --- a/crates/tycho-substreams/src/contract.rs +++ b/crates/tycho-substreams/src/contract.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; use substreams_ethereum::pb::eth; +use substreams_ethereum::pb::eth::v2::StorageChange; use crate::pb::tycho::evm::v1::{self as tycho}; @@ -15,6 +16,12 @@ struct SlotValue { start_value: Vec, } +impl From<&StorageChange> for SlotValue { + fn from(change: &StorageChange) -> Self { + Self { new_value: change.new_value.clone(), start_value: change.old_value.clone() } + } +} + impl SlotValue { fn has_changed(&self) -> bool { self.start_value != self.new_value @@ -30,6 +37,22 @@ struct InterimContractChange { change: tycho::ChangeType, } +impl InterimContractChange { + fn new(address: &[u8], creation: bool) -> Self { + Self { + address: address.to_vec(), + balance: vec![], + code: vec![], + slots: Default::default(), + change: if creation { + tycho::ChangeType::Creation.into() + } else { + tycho::ChangeType::Update.into() + }, + } + } +} + impl From for tycho::ContractChange { fn from(value: InterimContractChange) -> Self { tycho::ContractChange { @@ -90,28 +113,20 @@ pub fn extract_contract_changes bool>( storage_changes .iter() .filter(|changes| inclusion_predicate(&changes.address)) - .for_each(|storage_change| { + .for_each(|&storage_change| { let contract_change = changed_contracts .entry(storage_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: storage_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&storage_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, + .or_insert_with(|| { + InterimContractChange::new( + &storage_change.address, + created_accounts.contains_key(&storage_change.address), + ) }); let slot_value = contract_change .slots .entry(storage_change.key.clone()) - .or_insert_with(|| SlotValue { - new_value: storage_change.new_value.clone(), - start_value: storage_change.old_value.clone(), - }); + .or_insert_with(|| storage_change.into()); slot_value .new_value @@ -124,16 +139,11 @@ pub fn extract_contract_changes bool>( .for_each(|balance_change| { let contract_change = changed_contracts .entry(balance_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: balance_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&balance_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, + .or_insert_with(|| { + InterimContractChange::new( + &balance_change.address, + created_accounts.contains_key(&balance_change.address), + ) }); if let Some(new_balance) = &balance_change.new_value { @@ -150,16 +160,11 @@ pub fn extract_contract_changes bool>( .for_each(|code_change| { let contract_change = changed_contracts .entry(code_change.address.clone()) - .or_insert_with(|| InterimContractChange { - address: code_change.address.clone(), - balance: Vec::new(), - code: Vec::new(), - slots: HashMap::new(), - change: if created_accounts.contains_key(&code_change.address) { - tycho::ChangeType::Creation - } else { - tycho::ChangeType::Update - }, + .or_insert_with(|| { + InterimContractChange::new( + &code_change.address, + created_accounts.contains_key(&code_change.address), + ) }); contract_change.code.clear(); @@ -174,17 +179,7 @@ pub fn extract_contract_changes bool>( { transaction_contract_changes .entry(block_tx.index.into()) - .or_insert_with(|| tycho::TransactionContractChanges { - tx: Some(tycho::Transaction { - hash: block_tx.hash.clone(), - from: block_tx.from.clone(), - to: block_tx.to.clone(), - index: block_tx.index as u64, - }), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - }) + .or_insert_with(|| tycho::TransactionContractChanges::new(&(block_tx.into()))) .contract_changes .extend( changed_contracts diff --git a/crates/tycho-substreams/src/pb/mod.rs b/crates/tycho-substreams/src/pb/mod.rs index f5cd0b0..ceced59 100644 --- a/crates/tycho-substreams/src/pb/mod.rs +++ b/crates/tycho-substreams/src/pb/mod.rs @@ -3,6 +3,7 @@ pub mod tycho { pub mod evm { // @@protoc_insertion_point(attribute:tycho.evm.v1) pub mod v1 { + use substreams_ethereum::pb::eth::v2::{self as sf}; include!("tycho.evm.v1.rs"); // @@protoc_insertion_point(tycho.evm.v1) @@ -16,6 +17,104 @@ pub mod tycho { } } } + + impl From<&sf::TransactionTrace> for Transaction { + fn from(tx: &sf::TransactionTrace) -> Self { + Self { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: tx.index.into(), + } + } + } + + impl From<&sf::Block> for Block { + fn from(block: &sf::Block) -> Self { + Self { + number: block.number, + hash: block.hash.clone(), + parent_hash: block + .header + .as_ref() + .expect("Block header not present") + .parent_hash + .clone(), + ts: block.timestamp_seconds(), + } + } + } + + impl ProtocolComponent { + pub fn new(id: &str, tx: &Transaction) -> Self { + Self { + id: id.to_string(), + tokens: vec![], + contracts: vec![], + static_att: vec![], + change: ChangeType::Creation.into(), + protocol_type: None, + tx: Some(tx.clone()), + } + } + + pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { + Self { + id: format!("0x{}", hex::encode(id)), + tokens: vec![], + contracts: vec![id.to_vec()], + static_att: vec![], + change: ChangeType::Creation.into(), + protocol_type: None, + tx: Some(tx.clone()), + } + } + + pub fn with_tokens>(mut self, tokens: &[B]) -> Self { + self.tokens = tokens + .iter() + .map(|e| e.as_ref().to_vec()) + .collect::>>(); + self + } + + pub fn with_contracts>(mut self, contracts: &[B]) -> Self { + self.contracts = contracts + .iter() + .map(|e| e.as_ref().to_vec()) + .collect::>>(); + self + } + + pub fn with_attributes, V: AsRef<[u8]>>( + mut self, + attributes: &[(K, V)], + ) -> Self { + self.static_att = attributes + .iter() + .map(|(k, v)| Attribute { + name: k.as_ref().to_string(), + value: v.as_ref().to_vec(), + change: ChangeType::Creation.into(), + }) + .collect::>(); + self + } + + pub fn as_swap_type( + mut self, + name: &str, + implementation_type: ImplementationType, + ) -> Self { + self.protocol_type = Some(ProtocolType { + name: name.to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: implementation_type.into(), + }); + self + } + } } } } diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index a3658ad..81411f4 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -34,24 +34,14 @@ pub fn map_pools_created(block: eth::v2::Block) -> Result>(); if !components.is_empty() { Some(TransactionProtocolComponents { - tx: Some(tycho::Transaction { - hash: tx.hash.clone(), - from: tx.from.clone(), - to: tx.to.clone(), - index: Into::::into(tx.index), - }), + tx: Some(tx.into()), components, }) } else { @@ -106,12 +96,7 @@ pub fn map_balance_deltas( for (token, delta) in ev.tokens.iter().zip(ev.deltas.iter()) { deltas.push(BalanceDelta { ord: vault_log.ordinal(), - tx: Some(tycho::Transaction { - hash: vault_log.receipt.transaction.hash.clone(), - from: vault_log.receipt.transaction.from.clone(), - to: vault_log.receipt.transaction.to.clone(), - index: vault_log.receipt.transaction.index.into(), - }), + tx: Some(vault_log.receipt.transaction.into()), token: token.to_vec(), delta: delta.to_signed_bytes_be(), component_id: component_id.clone(), @@ -133,24 +118,14 @@ pub fn map_balance_deltas( deltas.extend_from_slice(&[ BalanceDelta { ord: vault_log.ordinal(), - tx: Some(tycho::Transaction { - hash: vault_log.receipt.transaction.hash.clone(), - from: vault_log.receipt.transaction.from.clone(), - to: vault_log.receipt.transaction.to.clone(), - index: vault_log.receipt.transaction.index.into(), - }), + tx: Some(vault_log.receipt.transaction.into()), token: ev.token_in.to_vec(), delta: ev.amount_in.to_signed_bytes_be(), component_id: component_id.clone(), }, BalanceDelta { ord: vault_log.ordinal(), - tx: Some(tycho::Transaction { - hash: vault_log.receipt.transaction.hash.clone(), - from: vault_log.receipt.transaction.from.clone(), - to: vault_log.receipt.transaction.to.clone(), - index: vault_log.receipt.transaction.index.into(), - }), + tx: Some(vault_log.receipt.transaction.into()), token: ev.token_out.to_vec(), delta: ev.amount_out.neg().to_signed_bytes_be(), component_id, @@ -234,17 +209,7 @@ pub fn map_changes( // Process all `transaction_contract_changes` for final output in the `BlockContractChanges`, // sorted by transaction index (the key). Ok(tycho::BlockContractChanges { - block: Some(tycho::Block { - number: block.number, - hash: block.hash.clone(), - parent_hash: block - .header - .as_ref() - .expect("Block header not present") - .parent_hash - .clone(), - ts: block.timestamp_seconds(), - }), + block: Some((&block).into()), changes: transaction_contract_changes .drain() .sorted_unstable_by_key(|(index, _)| *index) diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index 27c5ced..2ef1bc8 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -3,9 +3,7 @@ use substreams_ethereum::{Event, Function}; use crate::abi; use substreams::hex; -use tycho_substreams::pb::tycho::evm::v1::{ - self as tycho, FinancialType, ImplementationType, ProtocolType, Transaction, -}; +use tycho_substreams::pb::tycho::evm::v1::{ImplementationType, ProtocolComponent, Transaction}; use substreams::scalar::BigInt; @@ -39,16 +37,16 @@ impl SerializableVecBigInt for Vec { /// - Stable Pool Factories /// (Balancer does have a bit more (esp. in the deprecated section) that could be implemented as /// desired.) -/// We use the specific ABIs to decode both the log event and cooresponding call to gather -/// `PoolCreated` event information alongside the `Create` calldata that provide us details to -/// fufill both the required details + any extra `Attributes` +/// We use the specific ABIs to decode both the log event and corresponding call to gather +/// `PoolCreated` event information alongside the `Create` call data that provide us details to +/// fulfill both the required details + any extra `Attributes` /// Ref: https://docs.balancer.fi/reference/contracts/deployment-addresses/mainnet.html pub fn address_map( pool_factory_address: &[u8], log: &Log, call: &Call, tx: &Transaction, -) -> Option { +) -> Option { match *pool_factory_address { hex!("897888115Ada5773E02aA29F775430BFB5F34c51") => { let create_call = @@ -56,31 +54,18 @@ pub fn address_map( let pool_created = abi::weighted_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "WeightedPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "normalized_weights".into(), - value: create_call.normalized_weights.serialize_bytes(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&create_call.tokens) + .with_attributes(&[ + ("pool_type", "WeightedPoolFactory".as_bytes()), + ( + "normalized_weights", + &create_call.normalized_weights.serialize_bytes(), + ), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } hex!("DB8d758BCb971e482B2C45f7F8a7740283A1bd3A") => { let create_call = @@ -88,24 +73,12 @@ pub fn address_map( let pool_created = abi::composable_stable_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_created.pool], - static_att: vec![tycho::Attribute { - name: "pool_type".into(), - value: "ComposableStablePoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&create_call.tokens) + .with_attributes(&[("pool_type", "ComposableStablePoolFactory".as_bytes())]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } hex!("813EE7a840CE909E7Fea2117A44a90b8063bd4fd") => { let create_call = @@ -113,33 +86,18 @@ pub fn address_map( let pool_created = abi::erc_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "ERC4626LinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - // Note, `lower_target` is generally hardcoded for all pools, not located in call data - // Note, rate provider might be provided as `create.protocol_id`, but as a BigInt. needs investigation - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&[create_call.main_token, create_call.wrapped_token]) + .with_attributes(&[ + ("pool_type", "ERC4626LinearPoolFactory".as_bytes()), + ( + "upper_target", + &create_call.upper_target.to_signed_bytes_be(), + ), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } hex!("5F43FBa61f63Fa6bFF101a0A0458cEA917f6B347") => { let create_call = @@ -147,31 +105,18 @@ pub fn address_map( let pool_created = abi::euler_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "EulerLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&[create_call.main_token, create_call.wrapped_token]) + .with_attributes(&[ + ("pool_type", "EulerLinearPoolFactory".as_bytes()), + ( + "upper_target", + &create_call.upper_target.to_signed_bytes_be(), + ), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } // ❌ Reading the deployed factory for Gearbox showcases that it's currently disabled // hex!("39A79EB449Fc05C92c39aA6f0e9BfaC03BE8dE5B") => { @@ -226,31 +171,18 @@ pub fn address_map( let pool_created = abi::silo_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "SiloLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&[create_call.main_token, create_call.wrapped_token]) + .with_attributes(&[ + ("pool_type", "SiloLinearPoolFactory".as_bytes()), + ( + "upper_target", + &create_call.upper_target.to_signed_bytes_be(), + ), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } hex!("5F5222Ffa40F2AEd6380D022184D6ea67C776eE0") => { let create_call = @@ -258,65 +190,36 @@ pub fn address_map( let pool_created = abi::yearn_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: vec![create_call.main_token, create_call.wrapped_token], - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "YearnLinearPoolFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "upper_target".into(), - value: create_call.upper_target.to_signed_bytes_be(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&[create_call.main_token, create_call.wrapped_token]) + .with_attributes(&[ + ("pool_type", "YearnLinearPoolFactory".as_bytes()), + ( + "upper_target", + &create_call.upper_target.to_signed_bytes_be(), + ), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } - // The `WeightedPool2TokenFactory` is a deprecated contract but we've included it since one - // of the highest TVL pools, 80BAL-20WETH, is able to be tracked. + // The `WeightedPool2TokenFactory` is a deprecated contract, but we've included + // it to be able to track one of the highest TVL pools: 80BAL-20WETH. hex!("A5bf2ddF098bb0Ef6d120C98217dD6B141c74EE0") => { let create_call = abi::weighted_pool_tokens_factory::functions::Create::match_and_decode(call)?; let pool_created = abi::weighted_pool_tokens_factory::events::PoolCreated::match_and_decode(log)?; - Some(tycho::ProtocolComponent { - id: hex::encode(&pool_created.pool), - tokens: create_call.tokens, - contracts: vec![pool_created.pool], - static_att: vec![ - tycho::Attribute { - name: "pool_type".into(), - value: "WeightedPool2TokensFactory".into(), - change: tycho::ChangeType::Creation.into(), - }, - tycho::Attribute { - name: "weights".into(), - value: create_call.weights.serialize_bytes(), - change: tycho::ChangeType::Creation.into(), - }, - ], - change: tycho::ChangeType::Creation.into(), - protocol_type: Some(ProtocolType { - name: "balancer_pool".to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: ImplementationType::Vm.into(), - }), - tx: Some(tx.clone()), - }) + Some( + ProtocolComponent::at_contract(&pool_created.pool, &tx) + .with_tokens(&create_call.tokens) + .with_attributes(&[ + ("pool_type", "WeightedPool2TokensFactory".as_bytes()), + ("weights", &create_call.weights.serialize_bytes()), + ]) + .as_swap_type("balancer_pool", ImplementationType::Vm), + ) } _ => None, } From cfdb31b0c5c470ae665a85a3fe9624c492217e4f Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 23:12:30 +0000 Subject: [PATCH 72/86] Add documentation for the main methods added. --- crates/tycho-substreams/src/balances.rs | 30 +++++++++++++++++++++++++ crates/tycho-substreams/src/contract.rs | 28 +++++++++++++++++++---- crates/tycho-substreams/src/pb/mod.rs | 17 ++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/crates/tycho-substreams/src/balances.rs b/crates/tycho-substreams/src/balances.rs index 2547723..66ff2b5 100644 --- a/crates/tycho-substreams/src/balances.rs +++ b/crates/tycho-substreams/src/balances.rs @@ -19,6 +19,20 @@ use substreams::key; use substreams::pb::substreams::StoreDeltas; use substreams::prelude::{BigInt, StoreAdd}; +/// Store relative balances changes in a additive manner. +/// +/// Effectively aggregates the relative balances changes into an absolute balances. +/// +/// ## Arguments +/// +/// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. +/// Note: relative balance deltas must have strictly increasing ordinals per token +/// address, will panic otherwise. +/// * `store` - An AddStore that will add relative balance changes. +/// +/// This method is meant to be used in combination with `aggregate_balances_changes` +/// which consumes the store filled with this methods in +/// [deltas mode](https://substreams.streamingfast.io/documentation/develop/manifest-modules/types#deltas-mode). pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd) { let mut previous_ordinal = HashMap::::new(); deltas @@ -49,6 +63,22 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd for tycho::ContractChange { } } +/// Extracts relevant contract changes from the block. +/// +/// Contract changes include changes in storage, code and native balance. +/// +/// ## Arguments +/// +/// * `block` - The block to extract changes from. Must be the extended block model. +/// * `inclusion_predicate` - A predicate function that determines if a contract address is relevant. +/// * `transaction_contract_changes` - A mutable map to store the contract changes in. +/// +/// ## Panics +/// Will panic in case the detail level of the block is not extended. pub fn extract_contract_changes bool>( block: ð::v2::Block, inclusion_predicate: F, transaction_contract_changes: &mut HashMap, ) { + if block.detail_level != Into::::into(DetailLevel::DetaillevelExtended) { + panic!("Only extended blocks are supported"); + } let mut changed_contracts: HashMap, InterimContractChange> = HashMap::new(); // Collect all accounts created in this block diff --git a/crates/tycho-substreams/src/pb/mod.rs b/crates/tycho-substreams/src/pb/mod.rs index ceced59..5e6abdd 100644 --- a/crates/tycho-substreams/src/pb/mod.rs +++ b/crates/tycho-substreams/src/pb/mod.rs @@ -8,6 +8,7 @@ pub mod tycho { // @@protoc_insertion_point(tycho.evm.v1) impl TransactionContractChanges { + /// Creates a new empty `TransactionContractChanges` instance. pub fn new(tx: &Transaction) -> Self { Self { tx: Some(tx.clone()), @@ -46,6 +47,9 @@ pub mod tycho { } impl ProtocolComponent { + /// Creates a new empty `ProtocolComponent` instance. + /// + /// You can use the `with_*` methods to set the fields in a convience way. pub fn new(id: &str, tx: &Transaction) -> Self { Self { id: id.to_string(), @@ -58,6 +62,10 @@ pub mod tycho { } } + /// Shorthand to create a component with a 1-1 relationship to a contract. + /// + /// Will set the component id to a hex encoded address with a 0x prefix + /// and add the contract to contracts attributes. pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { Self { id: format!("0x{}", hex::encode(id)), @@ -70,6 +78,7 @@ pub mod tycho { } } + /// Replaces the tokens on this component. pub fn with_tokens>(mut self, tokens: &[B]) -> Self { self.tokens = tokens .iter() @@ -78,6 +87,7 @@ pub mod tycho { self } + /// Replaces the contracts associated with this component. pub fn with_contracts>(mut self, contracts: &[B]) -> Self { self.contracts = contracts .iter() @@ -86,6 +96,9 @@ pub mod tycho { self } + /// Replaces the static attributes on this component. + /// + /// The change type will be set to Creation. pub fn with_attributes, V: AsRef<[u8]>>( mut self, attributes: &[(K, V)], @@ -101,6 +114,10 @@ pub mod tycho { self } + /// Sets the protocol_type on this component. + /// + /// Will set the `financial_type` to FinancialType::Swap and the + /// `attribute_schema` to an empty list. pub fn as_swap_type( mut self, name: &str, From ba2a4ced08a4da23da2be668c3bc5f9c95995444 Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 23:19:45 +0000 Subject: [PATCH 73/86] Use expect instead of unwrap. --- crates/tycho-substreams/src/balances.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/tycho-substreams/src/balances.rs b/crates/tycho-substreams/src/balances.rs index 66ff2b5..8046fe1 100644 --- a/crates/tycho-substreams/src/balances.rs +++ b/crates/tycho-substreams/src/balances.rs @@ -97,7 +97,9 @@ pub fn aggregate_balances_changes( let big_endian_bytes_balance = balance.to_bytes_be().1; ( - balance_delta.tx.unwrap(), + balance_delta + .tx + .expect("Missing transaction on delta"), BalanceChange { token: hex::decode(token_id).expect("Token ID not valid hex"), balance: big_endian_bytes_balance, From 29e5984a3a8be00a77f0efe9eb095d8e6f1e31fb Mon Sep 17 00:00:00 2001 From: kayibal Date: Wed, 13 Mar 2024 23:49:40 +0000 Subject: [PATCH 74/86] Add prelude; Move pb implementations. Else the implementations would get overwritten. --- crates/tycho-substreams/src/lib.rs | 7 +- crates/tycho-substreams/src/models.rs | 123 +++++++++++++++++ crates/tycho-substreams/src/pb/mod.rs | 127 ------------------ substreams/ethereum-balancer/src/modules.rs | 22 ++- .../ethereum-balancer/src/pool_factories.rs | 8 +- 5 files changed, 141 insertions(+), 146 deletions(-) create mode 100644 crates/tycho-substreams/src/models.rs diff --git a/crates/tycho-substreams/src/lib.rs b/crates/tycho-substreams/src/lib.rs index 78c7e2e..03e9e03 100644 --- a/crates/tycho-substreams/src/lib.rs +++ b/crates/tycho-substreams/src/lib.rs @@ -1,4 +1,9 @@ pub mod balances; pub mod contract; mod mock_store; -pub mod pb; +pub mod models; +mod pb; + +pub mod prelude { + pub use super::models::*; +} diff --git a/crates/tycho-substreams/src/models.rs b/crates/tycho-substreams/src/models.rs new file mode 100644 index 0000000..14ab6f5 --- /dev/null +++ b/crates/tycho-substreams/src/models.rs @@ -0,0 +1,123 @@ +use substreams_ethereum::pb::eth::v2::{self as sf}; + +// re-export the protobuf types here. +pub use crate::pb::tycho::evm::v1::*; + +impl TransactionContractChanges { + /// Creates a new empty `TransactionContractChanges` instance. + pub fn new(tx: &Transaction) -> Self { + Self { + tx: Some(tx.clone()), + contract_changes: vec![], + component_changes: vec![], + balance_changes: vec![], + } + } +} + +impl From<&sf::TransactionTrace> for Transaction { + fn from(tx: &sf::TransactionTrace) -> Self { + Self { + hash: tx.hash.clone(), + from: tx.from.clone(), + to: tx.to.clone(), + index: tx.index.into(), + } + } +} + +impl From<&sf::Block> for Block { + fn from(block: &sf::Block) -> Self { + Self { + number: block.number, + hash: block.hash.clone(), + parent_hash: block + .header + .as_ref() + .expect("Block header not present") + .parent_hash + .clone(), + ts: block.timestamp_seconds(), + } + } +} + +impl ProtocolComponent { + /// Creates a new empty `ProtocolComponent` instance. + /// + /// You can use the `with_*` methods to set the fields in a convience way. + pub fn new(id: &str, tx: &Transaction) -> Self { + Self { + id: id.to_string(), + tokens: vec![], + contracts: vec![], + static_att: vec![], + change: ChangeType::Creation.into(), + protocol_type: None, + tx: Some(tx.clone()), + } + } + + /// Shorthand to create a component with a 1-1 relationship to a contract. + /// + /// Will set the component id to a hex encoded address with a 0x prefix + /// and add the contract to contracts attributes. + pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { + Self { + id: format!("0x{}", hex::encode(id)), + tokens: vec![], + contracts: vec![id.to_vec()], + static_att: vec![], + change: ChangeType::Creation.into(), + protocol_type: None, + tx: Some(tx.clone()), + } + } + + /// Replaces the tokens on this component. + pub fn with_tokens>(mut self, tokens: &[B]) -> Self { + self.tokens = tokens + .iter() + .map(|e| e.as_ref().to_vec()) + .collect::>>(); + self + } + + /// Replaces the contracts associated with this component. + pub fn with_contracts>(mut self, contracts: &[B]) -> Self { + self.contracts = contracts + .iter() + .map(|e| e.as_ref().to_vec()) + .collect::>>(); + self + } + + /// Replaces the static attributes on this component. + /// + /// The change type will be set to Creation. + pub fn with_attributes, V: AsRef<[u8]>>(mut self, attributes: &[(K, V)]) -> Self { + self.static_att = attributes + .iter() + .map(|(k, v)| Attribute { + name: k.as_ref().to_string(), + value: v.as_ref().to_vec(), + change: ChangeType::Creation.into(), + }) + .collect::>(); + self + } + + /// Sets the protocol_type on this component. + /// + /// Will set the `financial_type` to FinancialType::Swap and the + /// `attribute_schema` to an empty list. + pub fn as_swap_type(mut self, name: &str, implementation_type: ImplementationType) -> Self { + self.protocol_type = Some(ProtocolType { + name: name.to_string(), + financial_type: FinancialType::Swap.into(), + attribute_schema: vec![], + implementation_type: implementation_type.into(), + }); + self + } +} diff --git a/crates/tycho-substreams/src/pb/mod.rs b/crates/tycho-substreams/src/pb/mod.rs index 5e6abdd..43d8838 100644 --- a/crates/tycho-substreams/src/pb/mod.rs +++ b/crates/tycho-substreams/src/pb/mod.rs @@ -3,135 +3,8 @@ pub mod tycho { pub mod evm { // @@protoc_insertion_point(attribute:tycho.evm.v1) pub mod v1 { - use substreams_ethereum::pb::eth::v2::{self as sf}; include!("tycho.evm.v1.rs"); // @@protoc_insertion_point(tycho.evm.v1) - - impl TransactionContractChanges { - /// Creates a new empty `TransactionContractChanges` instance. - pub fn new(tx: &Transaction) -> Self { - Self { - tx: Some(tx.clone()), - contract_changes: vec![], - component_changes: vec![], - balance_changes: vec![], - } - } - } - - impl From<&sf::TransactionTrace> for Transaction { - fn from(tx: &sf::TransactionTrace) -> Self { - Self { - hash: tx.hash.clone(), - from: tx.from.clone(), - to: tx.to.clone(), - index: tx.index.into(), - } - } - } - - impl From<&sf::Block> for Block { - fn from(block: &sf::Block) -> Self { - Self { - number: block.number, - hash: block.hash.clone(), - parent_hash: block - .header - .as_ref() - .expect("Block header not present") - .parent_hash - .clone(), - ts: block.timestamp_seconds(), - } - } - } - - impl ProtocolComponent { - /// Creates a new empty `ProtocolComponent` instance. - /// - /// You can use the `with_*` methods to set the fields in a convience way. - pub fn new(id: &str, tx: &Transaction) -> Self { - Self { - id: id.to_string(), - tokens: vec![], - contracts: vec![], - static_att: vec![], - change: ChangeType::Creation.into(), - protocol_type: None, - tx: Some(tx.clone()), - } - } - - /// Shorthand to create a component with a 1-1 relationship to a contract. - /// - /// Will set the component id to a hex encoded address with a 0x prefix - /// and add the contract to contracts attributes. - pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { - Self { - id: format!("0x{}", hex::encode(id)), - tokens: vec![], - contracts: vec![id.to_vec()], - static_att: vec![], - change: ChangeType::Creation.into(), - protocol_type: None, - tx: Some(tx.clone()), - } - } - - /// Replaces the tokens on this component. - pub fn with_tokens>(mut self, tokens: &[B]) -> Self { - self.tokens = tokens - .iter() - .map(|e| e.as_ref().to_vec()) - .collect::>>(); - self - } - - /// Replaces the contracts associated with this component. - pub fn with_contracts>(mut self, contracts: &[B]) -> Self { - self.contracts = contracts - .iter() - .map(|e| e.as_ref().to_vec()) - .collect::>>(); - self - } - - /// Replaces the static attributes on this component. - /// - /// The change type will be set to Creation. - pub fn with_attributes, V: AsRef<[u8]>>( - mut self, - attributes: &[(K, V)], - ) -> Self { - self.static_att = attributes - .iter() - .map(|(k, v)| Attribute { - name: k.as_ref().to_string(), - value: v.as_ref().to_vec(), - change: ChangeType::Creation.into(), - }) - .collect::>(); - self - } - - /// Sets the protocol_type on this component. - /// - /// Will set the `financial_type` to FinancialType::Swap and the - /// `attribute_schema` to an empty list. - pub fn as_swap_type( - mut self, - name: &str, - implementation_type: ImplementationType, - ) -> Self { - self.protocol_type = Some(ProtocolType { - name: name.to_string(), - financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], - implementation_type: implementation_type.into(), - }); - self - } - } } } } diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 81411f4..728a53e 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -9,12 +9,9 @@ use substreams::store::{ }; use substreams_ethereum::pb::eth; use substreams_ethereum::Event; -use tycho_substreams::balances; +use tycho_substreams::balances::aggregate_balances_changes; use tycho_substreams::contract::extract_contract_changes; -use tycho_substreams::pb::tycho::evm::v1::{ - self as tycho, BalanceDelta, BlockBalanceDeltas, BlockTransactionProtocolComponents, - TransactionProtocolComponents, -}; +use tycho_substreams::prelude::*; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -145,7 +142,7 @@ pub fn map_balance_deltas( /// store key to ensure that there's a unique balance being tallied for each. #[substreams::handlers::store] pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { - balances::store_balance_changes(deltas, store); + tycho_substreams::balances::store_balance_changes(deltas, store); } /// This is the main map that handles most of the indexing of this substream. @@ -161,11 +158,10 @@ pub fn map_changes( deltas: BlockBalanceDeltas, components_store: StoreGetInt64, balance_store: StoreDeltas, // Note, this map module is using the `deltas` mode for the store. -) -> Result { +) -> Result { // We merge contract changes by transaction (identified by transaction index) making it easy to // sort them at the very end. - let mut transaction_contract_changes: HashMap<_, tycho::TransactionContractChanges> = - HashMap::new(); + let mut transaction_contract_changes: HashMap<_, TransactionContractChanges> = HashMap::new(); // `ProtocolComponents` are gathered from `map_pools_created` which just need a bit of work to // convert into `TransactionContractChanges` @@ -176,7 +172,7 @@ pub fn map_changes( let tx = tx_component.tx.as_ref().unwrap(); transaction_contract_changes .entry(tx.index) - .or_insert_with(|| tycho::TransactionContractChanges::new(&tx)) + .or_insert_with(|| TransactionContractChanges::new(&tx)) .component_changes .extend_from_slice(&tx_component.components); }); @@ -185,12 +181,12 @@ pub fn map_changes( // `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store` this // block. Then, these balance changes are merged onto the existing map of tx contract changes, // inserting a new one if it doesn't exist. - balances::aggregate_balances_changes(balance_store, deltas) + aggregate_balances_changes(balance_store, deltas) .into_iter() .for_each(|(_, (tx, balances))| { transaction_contract_changes .entry(tx.index) - .or_insert_with(|| tycho::TransactionContractChanges::new(&tx)) + .or_insert_with(|| TransactionContractChanges::new(&tx)) .balance_changes .extend(balances.into_iter().map(|(_, change)| change)); }); @@ -208,7 +204,7 @@ pub fn map_changes( // Process all `transaction_contract_changes` for final output in the `BlockContractChanges`, // sorted by transaction index (the key). - Ok(tycho::BlockContractChanges { + Ok(BlockContractChanges { block: Some((&block).into()), changes: transaction_contract_changes .drain() diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index 2ef1bc8..16691c3 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -1,11 +1,9 @@ -use substreams_ethereum::pb::eth::v2::{Call, Log}; -use substreams_ethereum::{Event, Function}; - use crate::abi; use substreams::hex; -use tycho_substreams::pb::tycho::evm::v1::{ImplementationType, ProtocolComponent, Transaction}; - use substreams::scalar::BigInt; +use substreams_ethereum::pb::eth::v2::{Call, Log}; +use substreams_ethereum::{Event, Function}; +use tycho_substreams::prelude::*; /// This trait defines some helpers for serializing and deserializing `Vec Date: Wed, 13 Mar 2024 23:31:08 +0000 Subject: [PATCH 75/86] Move crates under substreams directory. This way we can run GHA jobs depending on what files changed. --- .github/workflows/{test.yml => evm.yml} | 7 +++++-- {crates => substreams/crates}/tycho-substreams/Cargo.lock | 0 {crates => substreams/crates}/tycho-substreams/Cargo.toml | 0 {crates => substreams/crates}/tycho-substreams/Readme.md | 4 ++-- .../crates}/tycho-substreams/buf.gen.yaml | 0 .../crates}/tycho-substreams/rustfmt.toml | 0 .../crates}/tycho-substreams/src/balances.rs | 0 .../crates}/tycho-substreams/src/contract.rs | 0 {crates => substreams/crates}/tycho-substreams/src/lib.rs | 0 .../crates}/tycho-substreams/src/mock_store.rs | 0 .../crates}/tycho-substreams/src/models.rs | 0 .../crates}/tycho-substreams/src/pb/mod.rs | 0 .../crates}/tycho-substreams/src/pb/tycho.evm.v1.rs | 0 substreams/ethereum-balancer/Cargo.toml | 2 +- 14 files changed, 8 insertions(+), 5 deletions(-) rename .github/workflows/{test.yml => evm.yml} (92%) rename {crates => substreams/crates}/tycho-substreams/Cargo.lock (100%) rename {crates => substreams/crates}/tycho-substreams/Cargo.toml (100%) rename {crates => substreams/crates}/tycho-substreams/Readme.md (75%) rename {crates => substreams/crates}/tycho-substreams/buf.gen.yaml (100%) rename {crates => substreams/crates}/tycho-substreams/rustfmt.toml (100%) rename {crates => substreams/crates}/tycho-substreams/src/balances.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/contract.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/lib.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/mock_store.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/models.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/pb/mod.rs (100%) rename {crates => substreams/crates}/tycho-substreams/src/pb/tycho.evm.v1.rs (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/evm.yml similarity index 92% rename from .github/workflows/test.yml rename to .github/workflows/evm.yml index c64c94f..c75f40d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/evm.yml @@ -1,6 +1,9 @@ -name: test +name: test evm -on: workflow_dispatch +on: + push: + paths: + - "evm/**" env: FOUNDRY_PROFILE: ci diff --git a/crates/tycho-substreams/Cargo.lock b/substreams/crates/tycho-substreams/Cargo.lock similarity index 100% rename from crates/tycho-substreams/Cargo.lock rename to substreams/crates/tycho-substreams/Cargo.lock diff --git a/crates/tycho-substreams/Cargo.toml b/substreams/crates/tycho-substreams/Cargo.toml similarity index 100% rename from crates/tycho-substreams/Cargo.toml rename to substreams/crates/tycho-substreams/Cargo.toml diff --git a/crates/tycho-substreams/Readme.md b/substreams/crates/tycho-substreams/Readme.md similarity index 75% rename from crates/tycho-substreams/Readme.md rename to substreams/crates/tycho-substreams/Readme.md index 56b374b..20f868b 100644 --- a/crates/tycho-substreams/Readme.md +++ b/substreams/crates/tycho-substreams/Readme.md @@ -13,6 +13,6 @@ directory: ```bash buf generate \ --path tycho \ - --template ../crates/tycho-substreams/buf.gen.yaml \ - --output ../crates/tycho-substreams/ + --template ../substreams/crates/tycho-substreams/buf.gen.yaml \ + --output ../substreams/crates/tycho-substreams/ ``` \ No newline at end of file diff --git a/crates/tycho-substreams/buf.gen.yaml b/substreams/crates/tycho-substreams/buf.gen.yaml similarity index 100% rename from crates/tycho-substreams/buf.gen.yaml rename to substreams/crates/tycho-substreams/buf.gen.yaml diff --git a/crates/tycho-substreams/rustfmt.toml b/substreams/crates/tycho-substreams/rustfmt.toml similarity index 100% rename from crates/tycho-substreams/rustfmt.toml rename to substreams/crates/tycho-substreams/rustfmt.toml diff --git a/crates/tycho-substreams/src/balances.rs b/substreams/crates/tycho-substreams/src/balances.rs similarity index 100% rename from crates/tycho-substreams/src/balances.rs rename to substreams/crates/tycho-substreams/src/balances.rs diff --git a/crates/tycho-substreams/src/contract.rs b/substreams/crates/tycho-substreams/src/contract.rs similarity index 100% rename from crates/tycho-substreams/src/contract.rs rename to substreams/crates/tycho-substreams/src/contract.rs diff --git a/crates/tycho-substreams/src/lib.rs b/substreams/crates/tycho-substreams/src/lib.rs similarity index 100% rename from crates/tycho-substreams/src/lib.rs rename to substreams/crates/tycho-substreams/src/lib.rs diff --git a/crates/tycho-substreams/src/mock_store.rs b/substreams/crates/tycho-substreams/src/mock_store.rs similarity index 100% rename from crates/tycho-substreams/src/mock_store.rs rename to substreams/crates/tycho-substreams/src/mock_store.rs diff --git a/crates/tycho-substreams/src/models.rs b/substreams/crates/tycho-substreams/src/models.rs similarity index 100% rename from crates/tycho-substreams/src/models.rs rename to substreams/crates/tycho-substreams/src/models.rs diff --git a/crates/tycho-substreams/src/pb/mod.rs b/substreams/crates/tycho-substreams/src/pb/mod.rs similarity index 100% rename from crates/tycho-substreams/src/pb/mod.rs rename to substreams/crates/tycho-substreams/src/pb/mod.rs diff --git a/crates/tycho-substreams/src/pb/tycho.evm.v1.rs b/substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs similarity index 100% rename from crates/tycho-substreams/src/pb/tycho.evm.v1.rs rename to substreams/crates/tycho-substreams/src/pb/tycho.evm.v1.rs diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml index 0a964e5..16ddbdf 100644 --- a/substreams/ethereum-balancer/Cargo.toml +++ b/substreams/ethereum-balancer/Cargo.toml @@ -19,7 +19,7 @@ anyhow = "1.0.75" prost-types = "0.12.3" num-bigint = "0.4.4" itertools = "0.12.0" -tycho-substreams = {path ="../../crates/tycho-substreams"} +tycho-substreams = {path ="../crates/tycho-substreams"} [build-dependencies] anyhow = "1" From 425628ae97dbfb7391d22abfdf57d9763e197dfe Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 00:19:54 +0000 Subject: [PATCH 76/86] Create a workspace and make clippy happy. --- .../{crates/tycho-substreams => }/Cargo.lock | 195 ++- substreams/Cargo.toml | 22 + substreams/crates/tycho-substreams/Cargo.toml | 8 +- .../crates/tycho-substreams/src/balances.rs | 12 +- .../crates/tycho-substreams/src/contract.rs | 6 +- .../crates/tycho-substreams/src/mock_store.rs | 4 +- substreams/ethereum-balancer/Cargo.lock | 1281 ----------------- substreams/ethereum-balancer/Cargo.toml | 16 +- substreams/ethereum-balancer/src/modules.rs | 6 +- .../ethereum-balancer/src/pool_factories.rs | 14 +- .../tycho-substreams => }/rustfmt.toml | 3 +- 11 files changed, 222 insertions(+), 1345 deletions(-) rename substreams/{crates/tycho-substreams => }/Cargo.lock (87%) create mode 100644 substreams/Cargo.toml delete mode 100644 substreams/ethereum-balancer/Cargo.lock rename substreams/{crates/tycho-substreams => }/rustfmt.toml (91%) diff --git a/substreams/crates/tycho-substreams/Cargo.lock b/substreams/Cargo.lock similarity index 87% rename from substreams/crates/tycho-substreams/Cargo.lock rename to substreams/Cargo.lock index cd827d8..f5fe0e5 100644 --- a/substreams/crates/tycho-substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arrayvec" @@ -154,7 +154,24 @@ version = "17.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" dependencies = [ - "ethereum-types", + "ethereum-types 0.13.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror", + "uint", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types 0.14.1", "hex", "once_cell", "regex", @@ -172,9 +189,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" dependencies = [ "crunchy", - "fixed-hash", + "fixed-hash 0.7.0", "impl-rlp", - "impl-serde", + "impl-serde 0.3.2", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "impl-rlp", + "impl-serde 0.4.0", "tiny-keccak", ] @@ -184,11 +214,25 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" dependencies = [ - "ethbloom", - "fixed-hash", + "ethbloom 0.12.1", + "fixed-hash 0.7.0", "impl-rlp", - "impl-serde", - "primitive-types", + "impl-serde 0.3.2", + "primitive-types 0.11.1", + "uint", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash 0.8.0", + "impl-rlp", + "impl-serde 0.4.0", + "primitive-types 0.12.2", "uint", ] @@ -210,6 +254,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -267,6 +323,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "home" version = "0.5.9" @@ -303,6 +365,15 @@ dependencies = [ "serde", ] +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -495,10 +566,23 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" dependencies = [ - "fixed-hash", + "fixed-hash 0.7.0", "impl-codec", "impl-rlp", - "impl-serde", + "impl-serde 0.3.2", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "impl-serde 0.4.0", "uint", ] @@ -514,9 +598,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -528,7 +612,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive 0.12.3", ] [[package]] @@ -545,8 +639,8 @@ dependencies = [ "multimap", "petgraph", "prettyplease", - "prost", - "prost-types", + "prost 0.11.9", + "prost-types 0.11.9", "regex", "syn 1.0.109", "tempfile", @@ -566,13 +660,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "prost-types" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "prost", + "prost 0.11.9", +] + +[[package]] +name = "prost-types" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" +dependencies = [ + "prost 0.12.3", ] [[package]] @@ -740,14 +856,14 @@ dependencies = [ "anyhow", "bigdecimal", "hex", - "hex-literal", + "hex-literal 0.3.4", "num-bigint", "num-integer", "num-traits", "pad", - "prost", + "prost 0.11.9", "prost-build", - "prost-types", + "prost-types 0.11.9", "substreams-macro", "thiserror", ] @@ -773,7 +889,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" dependencies = [ "anyhow", - "ethabi", + "ethabi 17.2.0", "heck", "hex", "prettyplease", @@ -783,6 +899,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "substreams-ethereum-balancer" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "ethabi 18.0.0", + "getrandom", + "hex", + "hex-literal 0.4.1", + "itertools 0.12.1", + "num-bigint", + "prost 0.11.9", + "prost-types 0.12.3", + "substreams", + "substreams-ethereum", + "tycho-substreams", +] + [[package]] name = "substreams-ethereum-core" version = "0.9.9" @@ -790,12 +925,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" dependencies = [ "bigdecimal", - "ethabi", + "ethabi 17.2.0", "getrandom", "num-bigint", - "prost", + "prost 0.11.9", "prost-build", - "prost-types", + "prost-types 0.11.9", "substreams", ] @@ -805,7 +940,7 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" dependencies = [ - "ethabi", + "ethabi 17.2.0", "heck", "hex", "num-bigint", @@ -869,18 +1004,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", @@ -919,7 +1054,7 @@ version = "0.1.0" dependencies = [ "hex", "itertools 0.12.1", - "prost", + "prost 0.11.9", "substreams", "substreams-ethereum", ] diff --git a/substreams/Cargo.toml b/substreams/Cargo.toml new file mode 100644 index 0000000..8bcd85d --- /dev/null +++ b/substreams/Cargo.toml @@ -0,0 +1,22 @@ +[workspace] +members = [ + "ethereum-balancer", + "crates/tycho-substreams", +] +resolver = "2" + + +[workspace.dependencies] +substreams-ethereum = "0.9.9" +substreams = "0.5" +prost = "0.11" +prost-types = "0.12.3" +hex-literal = "0.4.1" +hex = "0.4.3" +ethabi = "18.0.0" +tycho-substreams = {path ="crates/tycho-substreams"} + +[profile.release] +lto = true +opt-level = 's' +strip = "debuginfo" \ No newline at end of file diff --git a/substreams/crates/tycho-substreams/Cargo.toml b/substreams/crates/tycho-substreams/Cargo.toml index cc0f7bc..3908f81 100644 --- a/substreams/crates/tycho-substreams/Cargo.toml +++ b/substreams/crates/tycho-substreams/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2021" [dependencies] -substreams-ethereum = "0.9.9" -substreams = "0.5" -prost = "0.11" -hex = "0.4.3" +substreams-ethereum.workspace = true +substreams.workspace = true +prost.workspace = true +hex.workspace = true itertools = "0.12.0" \ No newline at end of file diff --git a/substreams/crates/tycho-substreams/src/balances.rs b/substreams/crates/tycho-substreams/src/balances.rs index 8046fe1..74a38fa 100644 --- a/substreams/crates/tycho-substreams/src/balances.rs +++ b/substreams/crates/tycho-substreams/src/balances.rs @@ -63,6 +63,8 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd, (Transaction, HashMap, BalanceChange>)>; + /// Aggregates absolute balances per transaction and token. /// /// ## Arguments @@ -82,7 +84,7 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd HashMap, (Transaction, HashMap, BalanceChange>)> { +) -> TxAggregatedBalances { balance_store .deltas .into_iter() @@ -207,9 +209,9 @@ mod tests { let token_1 = hex::decode("babe00").unwrap(); let t0_key = - format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(&token_0)); + format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(token_0)); let t1_key = - format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(&token_1)); + format!("{}:{}", String::from_utf8(comp_id.clone()).unwrap(), hex::encode(token_1)); StoreDeltas { deltas: vec![ StoreDelta { @@ -283,12 +285,12 @@ mod tests { let res_0 = store.get_last(format!( "{}:{}", String::from_utf8(comp_id.clone()).unwrap(), - hex::encode(&token_0) + hex::encode(token_0) )); let res_1 = store.get_last(format!( "{}:{}", String::from_utf8(comp_id.clone()).unwrap(), - hex::encode(&token_1) + hex::encode(token_1) )); assert_eq!(res_0, Some(BigInt::from_str("+999").unwrap())); diff --git a/substreams/crates/tycho-substreams/src/contract.rs b/substreams/crates/tycho-substreams/src/contract.rs index f054380..e02ba2e 100644 --- a/substreams/crates/tycho-substreams/src/contract.rs +++ b/substreams/crates/tycho-substreams/src/contract.rs @@ -49,11 +49,7 @@ impl InterimContractChange { balance: vec![], code: vec![], slots: Default::default(), - change: if creation { - tycho::ChangeType::Creation.into() - } else { - tycho::ChangeType::Update.into() - }, + change: if creation { tycho::ChangeType::Creation } else { tycho::ChangeType::Update }, } } } diff --git a/substreams/crates/tycho-substreams/src/mock_store.rs b/substreams/crates/tycho-substreams/src/mock_store.rs index a1c0cd2..6c1349f 100644 --- a/substreams/crates/tycho-substreams/src/mock_store.rs +++ b/substreams/crates/tycho-substreams/src/mock_store.rs @@ -7,9 +7,11 @@ use std::rc::Rc; use substreams::prelude::{BigInt, StoreDelete, StoreGet, StoreNew}; use substreams::store::StoreAdd; +type BigIntStore = HashMap>; + #[derive(Debug, Clone)] pub struct MockStore { - data: Rc>>>, + data: Rc>, } impl StoreDelete for MockStore { diff --git a/substreams/ethereum-balancer/Cargo.lock b/substreams/ethereum-balancer/Cargo.lock deleted file mode 100644 index e2d81a0..0000000 --- a/substreams/ethereum-balancer/Cargo.lock +++ /dev/null @@ -1,1281 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cpufeatures" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "ethabi" -version = "17.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" -dependencies = [ - "ethereum-types 0.13.1", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethabi" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" -dependencies = [ - "ethereum-types 0.14.1", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "tiny-keccak", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash 0.8.0", - "impl-rlp", - "impl-serde 0.4.0", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" -dependencies = [ - "ethbloom 0.12.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde 0.3.2", - "primitive-types 0.11.1", - "uint", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom 0.13.0", - "fixed-hash 0.8.0", - "impl-rlp", - "impl-serde 0.4.0", - "primitive-types 0.12.2", - "uint", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-literal" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" - -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "pad" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "parity-scale-codec" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "primitive-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" -dependencies = [ - "fixed-hash 0.7.0", - "impl-codec", - "impl-rlp", - "impl-serde 0.3.2", - "uint", -] - -[[package]] -name = "primitive-types" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" -dependencies = [ - "fixed-hash 0.8.0", - "impl-codec", - "impl-rlp", - "impl-serde 0.4.0", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" -dependencies = [ - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" -dependencies = [ - "bytes", - "prost-derive 0.12.3", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 2.0.41", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost 0.11.9", -] - -[[package]] -name = "prost-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" -dependencies = [ - "prost 0.12.3", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.41", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "substreams" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3524a4e2931ff6cd58783e62adbd7e44f461752eca0c423793cfb462351f24" -dependencies = [ - "anyhow", - "bigdecimal", - "hex", - "hex-literal 0.3.4", - "num-bigint", - "num-integer", - "num-traits", - "pad", - "prost 0.11.9", - "prost-build", - "prost-types 0.11.9", - "substreams-macro", - "thiserror", -] - -[[package]] -name = "substreams-ethereum" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" -dependencies = [ - "getrandom", - "num-bigint", - "substreams", - "substreams-ethereum-abigen", - "substreams-ethereum-core", - "substreams-ethereum-derive", -] - -[[package]] -name = "substreams-ethereum-abigen" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" -dependencies = [ - "anyhow", - "ethabi 17.2.0", - "heck", - "hex", - "prettyplease", - "proc-macro2", - "quote", - "substreams-ethereum-core", - "syn 1.0.109", -] - -[[package]] -name = "substreams-ethereum-balancer" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "ethabi 18.0.0", - "getrandom", - "hex", - "hex-literal 0.4.1", - "itertools 0.12.0", - "num-bigint", - "prost 0.11.9", - "prost-types 0.12.3", - "substreams", - "substreams-ethereum", - "tycho-substreams", -] - -[[package]] -name = "substreams-ethereum-core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" -dependencies = [ - "bigdecimal", - "ethabi 17.2.0", - "getrandom", - "num-bigint", - "prost 0.11.9", - "prost-build", - "prost-types 0.11.9", - "substreams", -] - -[[package]] -name = "substreams-ethereum-derive" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" -dependencies = [ - "ethabi 17.2.0", - "heck", - "hex", - "num-bigint", - "proc-macro2", - "quote", - "substreams-ethereum-abigen", - "syn 1.0.109", -] - -[[package]] -name = "substreams-macro" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c2b15adf5b4d7a6d1a73c73df951a6b2df6fbb4f0b41304dc28c5550ce0ed0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "thiserror", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "thiserror" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.41", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tycho-substreams" -version = "0.1.0" -dependencies = [ - "hex", - "itertools 0.12.0", - "prost 0.11.9", - "substreams", - "substreams-ethereum", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml index 16ddbdf..885ab93 100644 --- a/substreams/ethereum-balancer/Cargo.toml +++ b/substreams/ethereum-balancer/Cargo.toml @@ -8,18 +8,18 @@ name = "substreams_ethereum_balancer" crate-type = ["cdylib"] [dependencies] -substreams = "0.5" -substreams-ethereum = "0.9.9" -prost = "0.11" -hex-literal = "0.4.1" -ethabi = "18.0.0" -hex = "0.4.2" +substreams.workspace = true +substreams-ethereum.workspace = true +prost.workspace = true +prost-types.workspace = true +hex-literal.workspace = true +ethabi.workspace = true +hex.workspace = true bytes = "1.5.0" anyhow = "1.0.75" -prost-types = "0.12.3" num-bigint = "0.4.4" itertools = "0.12.0" -tycho-substreams = {path ="../crates/tycho-substreams"} +tycho-substreams.workspace = true [build-dependencies] anyhow = "1" diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index 728a53e..d5bf495 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -172,7 +172,7 @@ pub fn map_changes( let tx = tx_component.tx.as_ref().unwrap(); transaction_contract_changes .entry(tx.index) - .or_insert_with(|| TransactionContractChanges::new(&tx)) + .or_insert_with(|| TransactionContractChanges::new(tx)) .component_changes .extend_from_slice(&tx_component.components); }); @@ -188,7 +188,7 @@ pub fn map_changes( .entry(tx.index) .or_insert_with(|| TransactionContractChanges::new(&tx)) .balance_changes - .extend(balances.into_iter().map(|(_, change)| change)); + .extend(balances.into_values()); }); // Extract and insert any storage changes that happened for any of the components. @@ -196,7 +196,7 @@ pub fn map_changes( &block, |addr| { components_store - .get_last(format!("pool:{0}", hex::encode(&addr))) + .get_last(format!("pool:{0}", hex::encode(addr))) .is_some() }, &mut transaction_contract_changes, diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index 16691c3..d2cfc2f 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -53,7 +53,7 @@ pub fn address_map( abi::weighted_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&create_call.tokens) .with_attributes(&[ ("pool_type", "WeightedPoolFactory".as_bytes()), @@ -72,7 +72,7 @@ pub fn address_map( abi::composable_stable_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&create_call.tokens) .with_attributes(&[("pool_type", "ComposableStablePoolFactory".as_bytes())]) .as_swap_type("balancer_pool", ImplementationType::Vm), @@ -85,7 +85,7 @@ pub fn address_map( abi::erc_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&[create_call.main_token, create_call.wrapped_token]) .with_attributes(&[ ("pool_type", "ERC4626LinearPoolFactory".as_bytes()), @@ -104,7 +104,7 @@ pub fn address_map( abi::euler_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&[create_call.main_token, create_call.wrapped_token]) .with_attributes(&[ ("pool_type", "EulerLinearPoolFactory".as_bytes()), @@ -170,7 +170,7 @@ pub fn address_map( abi::silo_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&[create_call.main_token, create_call.wrapped_token]) .with_attributes(&[ ("pool_type", "SiloLinearPoolFactory".as_bytes()), @@ -189,7 +189,7 @@ pub fn address_map( abi::yearn_linear_pool_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&[create_call.main_token, create_call.wrapped_token]) .with_attributes(&[ ("pool_type", "YearnLinearPoolFactory".as_bytes()), @@ -210,7 +210,7 @@ pub fn address_map( abi::weighted_pool_tokens_factory::events::PoolCreated::match_and_decode(log)?; Some( - ProtocolComponent::at_contract(&pool_created.pool, &tx) + ProtocolComponent::at_contract(&pool_created.pool, tx) .with_tokens(&create_call.tokens) .with_attributes(&[ ("pool_type", "WeightedPool2TokensFactory".as_bytes()), diff --git a/substreams/crates/tycho-substreams/rustfmt.toml b/substreams/rustfmt.toml similarity index 91% rename from substreams/crates/tycho-substreams/rustfmt.toml rename to substreams/rustfmt.toml index d0c0193..ce9e1ec 100644 --- a/substreams/crates/tycho-substreams/rustfmt.toml +++ b/substreams/rustfmt.toml @@ -9,5 +9,6 @@ trailing_semicolon = false use_field_init_shorthand = true chain_width = 40 ignore = [ - "src/pb", + "*/pb", + "*/abi", ] \ No newline at end of file From 6b6e42e2f8697c4f65de0122844a799309ad3f5e Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 00:27:52 +0000 Subject: [PATCH 77/86] Run rustfmt --- .../crates/tycho-substreams/src/balances.rs | 47 +++++++------- .../crates/tycho-substreams/src/contract.rs | 16 ++--- .../crates/tycho-substreams/src/mock_store.rs | 10 +-- substreams/ethereum-balancer/src/modules.rs | 62 ++++++++----------- .../ethereum-balancer/src/pool_factories.rs | 36 +++++++---- substreams/rustfmt.toml | 4 +- 6 files changed, 92 insertions(+), 83 deletions(-) diff --git a/substreams/crates/tycho-substreams/src/balances.rs b/substreams/crates/tycho-substreams/src/balances.rs index 74a38fa..85e1311 100644 --- a/substreams/crates/tycho-substreams/src/balances.rs +++ b/substreams/crates/tycho-substreams/src/balances.rs @@ -3,21 +3,21 @@ //! //! To aggregate relative balances changes to absolute balances the general approach is: //! -//! 1. Use a map function that will extract a `BlockBalanceDeltas` message. BalanceDeltas -//! within this message are required to have increasing ordinals so that -//! the order of relative balance changes is unambiguous. -//! 2. Store the balances changes with a store handler. You can use the -//! `store_balance_changes` library method directly for this. -//! 3. In the output module, use aggregate_balance_changes to receive an -//! aggregated map of absolute balances. -//! +//! 1. Use a map function that will extract a `BlockBalanceDeltas` message. BalanceDeltas within +//! this message are required to have increasing ordinals so that the order of relative balance +//! changes is unambiguous. +//! 2. Store the balances changes with a store handler. You can use the `store_balance_changes` +//! library method directly for this. +//! 3. In the output module, use aggregate_balance_changes to receive an aggregated map of absolute +//! balances. use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas, Transaction}; use itertools::Itertools; -use std::collections::HashMap; -use std::str::FromStr; -use substreams::key; -use substreams::pb::substreams::StoreDeltas; -use substreams::prelude::{BigInt, StoreAdd}; +use std::{collections::HashMap, str::FromStr}; +use substreams::{ + key, + pb::substreams::StoreDeltas, + prelude::{BigInt, StoreAdd}, +}; /// Store relative balances changes in a additive manner. /// @@ -25,9 +25,9 @@ use substreams::prelude::{BigInt, StoreAdd}; /// /// ## Arguments /// -/// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. -/// Note: relative balance deltas must have strictly increasing ordinals per token -/// address, will panic otherwise. +/// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. Note: +/// relative balance deltas must have strictly increasing ordinals per token address, will panic +/// otherwise. /// * `store` - An AddStore that will add relative balance changes. /// /// This method is meant to be used in combination with `aggregate_balances_changes` @@ -68,8 +68,7 @@ type TxAggregatedBalances = HashMap, (Transaction, HashMap, Bala /// Aggregates absolute balances per transaction and token. /// /// ## Arguments -/// * `balance_store` - A `StoreDeltas` with all changes that occured in the source -/// store module. +/// * `balance_store` - A `StoreDeltas` with all changes that occured in the source store module. /// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. /// /// Reads absolute balance values from the additive store (see `store_balance_changes` @@ -127,10 +126,14 @@ pub fn aggregate_balances_changes( #[cfg(test)] mod tests { use super::*; - use crate::mock_store::MockStore; - use crate::pb::tycho::evm::v1::{BalanceDelta, Transaction}; - use substreams::pb::substreams::StoreDelta; - use substreams::prelude::{StoreGet, StoreNew}; + use crate::{ + mock_store::MockStore, + pb::tycho::evm::v1::{BalanceDelta, Transaction}, + }; + use substreams::{ + pb::substreams::StoreDelta, + prelude::{StoreGet, StoreNew}, + }; fn block_balance_deltas() -> BlockBalanceDeltas { let comp_id = "0x42c0ffee" diff --git a/substreams/crates/tycho-substreams/src/contract.rs b/substreams/crates/tycho-substreams/src/contract.rs index e02ba2e..a99fd60 100644 --- a/substreams/crates/tycho-substreams/src/contract.rs +++ b/substreams/crates/tycho-substreams/src/contract.rs @@ -10,9 +10,10 @@ /// more [here](https://streamingfastio.medium.com/new-block-model-to-accelerate-chain-integration-9f65126e5425) use std::collections::HashMap; -use substreams_ethereum::pb::eth; -use substreams_ethereum::pb::eth::v2::block::DetailLevel; -use substreams_ethereum::pb::eth::v2::StorageChange; +use substreams_ethereum::pb::{ + eth, + eth::v2::{block::DetailLevel, StorageChange}, +}; use crate::pb::tycho::evm::v1::{self as tycho}; @@ -78,7 +79,8 @@ impl From for tycho::ContractChange { /// ## Arguments /// /// * `block` - The block to extract changes from. Must be the extended block model. -/// * `inclusion_predicate` - A predicate function that determines if a contract address is relevant. +/// * `inclusion_predicate` - A predicate function that determines if a contract address is +/// relevant. /// * `transaction_contract_changes` - A mutable map to store the contract changes in. /// /// ## Panics @@ -189,9 +191,9 @@ pub fn extract_contract_changes bool>( .extend_from_slice(&code_change.new_code); }); - if !storage_changes.is_empty() - || !balance_changes.is_empty() - || !code_changes.is_empty() + if !storage_changes.is_empty() || + !balance_changes.is_empty() || + !code_changes.is_empty() { transaction_contract_changes .entry(block_tx.index.into()) diff --git a/substreams/crates/tycho-substreams/src/mock_store.rs b/substreams/crates/tycho-substreams/src/mock_store.rs index 6c1349f..70b252b 100644 --- a/substreams/crates/tycho-substreams/src/mock_store.rs +++ b/substreams/crates/tycho-substreams/src/mock_store.rs @@ -1,11 +1,11 @@ //! Contains a mock store for internal testing. //! //! Might make this public alter to users can test their store handlers. -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; -use substreams::prelude::{BigInt, StoreDelete, StoreGet, StoreNew}; -use substreams::store::StoreAdd; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; +use substreams::{ + prelude::{BigInt, StoreDelete, StoreGet, StoreNew}, + store::StoreAdd, +}; type BigIntStore = HashMap>; diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index d5bf495..b1747b1 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -2,16 +2,15 @@ use crate::{abi, pool_factories}; use anyhow::Result; use itertools::Itertools; use std::collections::HashMap; -use substreams::hex; -use substreams::pb::substreams::StoreDeltas; -use substreams::store::{ - StoreAdd, StoreAddBigInt, StoreAddInt64, StoreGet, StoreGetInt64, StoreNew, +use substreams::{ + hex, + pb::substreams::StoreDeltas, + store::{StoreAdd, StoreAddBigInt, StoreAddInt64, StoreGet, StoreGetInt64, StoreNew}, +}; +use substreams_ethereum::{pb::eth, Event}; +use tycho_substreams::{ + balances::aggregate_balances_changes, contract::extract_contract_changes, prelude::*, }; -use substreams_ethereum::pb::eth; -use substreams_ethereum::Event; -use tycho_substreams::balances::aggregate_balances_changes; -use tycho_substreams::contract::extract_contract_changes; -use tycho_substreams::prelude::*; const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); @@ -37,10 +36,7 @@ pub fn map_pools_created(block: eth::v2::Block) -> Result>(); if !components.is_empty() { - Some(TransactionProtocolComponents { - tx: Some(tx.into()), - components, - }) + Some(TransactionProtocolComponents { tx: Some(tx.into()), components }) } else { None } @@ -63,8 +59,8 @@ pub fn store_pools_created(map: BlockTransactionProtocolComponents, store: Store ); } -/// Since the `PoolBalanceChanged` and `Swap` events administer only deltas, we need to leverage a map and a -/// store to be able to tally up final balances for tokens in a pool. +/// Since the `PoolBalanceChanged` and `Swap` events administer only deltas, we need to leverage a +/// map and a store to be able to tally up final balances for tokens in a pool. #[substreams::handlers::map] pub fn map_balance_deltas( block: eth::v2::Block, @@ -79,12 +75,10 @@ pub fn map_balance_deltas( if let Some(ev) = abi::vault::events::PoolBalanceChanged::match_and_decode(vault_log.log) { - let component_id = format!( - "0x{}", - String::from_utf8(ev.pool_id[..20].to_vec()).unwrap() - ) - .as_bytes() - .to_vec(); + let component_id = + format!("0x{}", String::from_utf8(ev.pool_id[..20].to_vec()).unwrap()) + .as_bytes() + .to_vec(); if store .get_last(format!("pool:{}", hex::encode(&component_id))) @@ -101,12 +95,10 @@ pub fn map_balance_deltas( } } } else if let Some(ev) = abi::vault::events::Swap::match_and_decode(vault_log.log) { - let component_id = format!( - "0x{}", - String::from_utf8(ev.pool_id[..20].to_vec()).unwrap() - ) - .as_bytes() - .to_vec(); + let component_id = + format!("0x{}", String::from_utf8(ev.pool_id[..20].to_vec()).unwrap()) + .as_bytes() + .to_vec(); if store .get_last(format!("pool:{}", hex::encode(&component_id))) @@ -149,8 +141,8 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) /// Every contract change is grouped by transaction index via the `transaction_contract_changes` /// map. Each block of code will extend the `TransactionContractChanges` struct with the /// cooresponding changes (balance, component, contract), inserting a new one if it doesn't exist. -/// At the very end, the map can easily be sorted by index to ensure the final `BlockContractChanges` -/// is ordered by transactions properly. +/// At the very end, the map can easily be sorted by index to ensure the final +/// `BlockContractChanges` is ordered by transactions properly. #[substreams::handlers::map] pub fn map_changes( block: eth::v2::Block, @@ -178,9 +170,9 @@ pub fn map_changes( }); // Balance changes are gathered by the `StoreDelta` based on `PoolBalanceChanged` creating - // `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store` this - // block. Then, these balance changes are merged onto the existing map of tx contract changes, - // inserting a new one if it doesn't exist. + // `BlockBalanceDeltas`. We essentially just process the changes that occurred to the `store` + // this block. Then, these balance changes are merged onto the existing map of tx contract + // changes, inserting a new one if it doesn't exist. aggregate_balances_changes(balance_store, deltas) .into_iter() .for_each(|(_, (tx, balances))| { @@ -210,9 +202,9 @@ pub fn map_changes( .drain() .sorted_unstable_by_key(|(index, _)| *index) .filter_map(|(_, change)| { - if change.contract_changes.is_empty() - && change.component_changes.is_empty() - && change.balance_changes.is_empty() + if change.contract_changes.is_empty() && + change.component_changes.is_empty() && + change.balance_changes.is_empty() { None } else { diff --git a/substreams/ethereum-balancer/src/pool_factories.rs b/substreams/ethereum-balancer/src/pool_factories.rs index d2cfc2f..5c2cd59 100644 --- a/substreams/ethereum-balancer/src/pool_factories.rs +++ b/substreams/ethereum-balancer/src/pool_factories.rs @@ -1,8 +1,9 @@ use crate::abi; -use substreams::hex; -use substreams::scalar::BigInt; -use substreams_ethereum::pb::eth::v2::{Call, Log}; -use substreams_ethereum::{Event, Function}; +use substreams::{hex, scalar::BigInt}; +use substreams_ethereum::{ + pb::eth::v2::{Call, Log}, + Event, Function, +}; use tycho_substreams::prelude::*; /// This trait defines some helpers for serializing and deserializing `Vec { - // let create_call = abi::managed_pool_factory::functions::Create::match_and_decode(call)?; + // let create_call = + // abi::managed_pool_factory::functions::Create::match_and_decode(call)?; // let pool_created = // abi::managed_pool_factory::events::PoolCreated::match_and_decode(log)?; @@ -176,7 +184,9 @@ pub fn address_map( ("pool_type", "SiloLinearPoolFactory".as_bytes()), ( "upper_target", - &create_call.upper_target.to_signed_bytes_be(), + &create_call + .upper_target + .to_signed_bytes_be(), ), ]) .as_swap_type("balancer_pool", ImplementationType::Vm), @@ -195,7 +205,9 @@ pub fn address_map( ("pool_type", "YearnLinearPoolFactory".as_bytes()), ( "upper_target", - &create_call.upper_target.to_signed_bytes_be(), + &create_call + .upper_target + .to_signed_bytes_be(), ), ]) .as_swap_type("balancer_pool", ImplementationType::Vm), diff --git a/substreams/rustfmt.toml b/substreams/rustfmt.toml index ce9e1ec..1f27a7b 100644 --- a/substreams/rustfmt.toml +++ b/substreams/rustfmt.toml @@ -9,6 +9,6 @@ trailing_semicolon = false use_field_init_shorthand = true chain_width = 40 ignore = [ - "*/pb", - "*/abi", + "crates/tycho-substreams/src/pb", + "ethereum-balancer/src/abi", ] \ No newline at end of file From 981a0917278f84b4db886c115c0f0aae06d45918 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 01:21:06 +0000 Subject: [PATCH 78/86] Add check and release scripts. Had to slightly adjust package names to make this work. --- substreams/Cargo.lock | 38 ++++++------- substreams/check.sh | 6 ++ substreams/ethereum-balancer/Cargo.toml | 4 +- substreams/ethereum-balancer/substreams.yaml | 12 +--- substreams/release.sh | 60 ++++++++++++++++++++ 5 files changed, 89 insertions(+), 31 deletions(-) create mode 100755 substreams/check.sh create mode 100755 substreams/release.sh diff --git a/substreams/Cargo.lock b/substreams/Cargo.lock index f5fe0e5..f89bb92 100644 --- a/substreams/Cargo.lock +++ b/substreams/Cargo.lock @@ -208,6 +208,25 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "ethereum-balancer" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "ethabi 18.0.0", + "getrandom", + "hex", + "hex-literal 0.4.1", + "itertools 0.12.1", + "num-bigint", + "prost 0.11.9", + "prost-types 0.12.3", + "substreams", + "substreams-ethereum", + "tycho-substreams", +] + [[package]] name = "ethereum-types" version = "0.13.1" @@ -899,25 +918,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "substreams-ethereum-balancer" -version = "0.1.0" -dependencies = [ - "anyhow", - "bytes", - "ethabi 18.0.0", - "getrandom", - "hex", - "hex-literal 0.4.1", - "itertools 0.12.1", - "num-bigint", - "prost 0.11.9", - "prost-types 0.12.3", - "substreams", - "substreams-ethereum", - "tycho-substreams", -] - [[package]] name = "substreams-ethereum-core" version = "0.9.9" diff --git a/substreams/check.sh b/substreams/check.sh new file mode 100755 index 0000000..1821d18 --- /dev/null +++ b/substreams/check.sh @@ -0,0 +1,6 @@ +set -e + +cargo +nightly fmt -- --check +cargo +nightly clippy --all --all-features --all-targets -- -D warnings +cargo build --target wasm32-unknown-unknown --all-targets --all-features +cargo test --workspace --all-targets --all-features diff --git a/substreams/ethereum-balancer/Cargo.toml b/substreams/ethereum-balancer/Cargo.toml index 885ab93..2aca957 100644 --- a/substreams/ethereum-balancer/Cargo.toml +++ b/substreams/ethereum-balancer/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "substreams-ethereum-balancer" +name = "ethereum-balancer" version = "0.1.0" edition = "2021" [lib] -name = "substreams_ethereum_balancer" +name = "ethereum_balancer" crate-type = ["cdylib"] [dependencies] diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 66da244..06f2ee7 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -1,20 +1,12 @@ specVersion: v0.1.0 package: - name: "substreams_ethereum_balancer" + name: "ethereum_balancer" version: v0.1.0 -protobuf: - files: - - tycho/evm/v1/vm.proto - - tycho/evm/v1/common.proto - - tycho/evm/v1/utils.proto - importPaths: - - ../../proto - binaries: default: type: wasm/rust-v1 - file: target/wasm32-unknown-unknown/release/substreams_ethereum_balancer.wasm + file: ../target/wasm32-unknown-unknown/release/ethereum_balancer.wasm modules: - name: map_pools_created diff --git a/substreams/release.sh b/substreams/release.sh new file mode 100755 index 0000000..27b50e6 --- /dev/null +++ b/substreams/release.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Allows releasing multiple substream packages within the same repo. +# To trigger a release simply create a tag with [package-name]-[semver]. +# The script will look for these tags, then infer which package needs to be built and +# released. + +# Try to get the tag name associated with the current HEAD commit +current_tag=$(git describe --tags --exact-match HEAD 2>/dev/null) + +if [ -n "$current_tag" ]; then + # If the HEAD is at a tag, extract the prefix and version + if [[ $current_tag =~ ^([a-zA-Z-]*-)?([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then + # Prefix without the trailing hyphen (if any) + package="${BASH_REMATCH[1]%?}" + # Semantic version + version="${BASH_REMATCH[2]}" + tag=$current_tag + + cargo_version=$(cargo pkgid -p ethereum-balancer | cut -d# -f2 | cut -d: -f2) + if [[ "$cargo_version" != "$version" ]]; then + echo "Error: Cargo version: ${cargo_version} does not match tag version: ${version}!" + exit 1 + fi + # Check if the Git repository is dirty + if [ -n "$(git status --porcelain)" ]; then + echo "Error: The repository is dirty. Please commit or stash your changes." + exit 1 + fi + else + echo "Error: Current tag ($current_tag) does not match the expected format." + exit 1 + fi +else + # If the HEAD is not at a tag, construct the tag name with the pre-release postfix + if [ -z "$1" ]; then + echo "Error: package argument is required to create a pre release!" + exit 1 + fi + package=$1 + + version_prefix=$(git describe --tags --match "$package-*" --abbrev=0 2>/dev/null) + if [ -z "$version_prefix" ]; then + # If no tags are found in the history, default to version 0.0.1 + version_prefix="0.0.1" + fi + + # Get the short commit hash of the current HEAD + commit_hash=$(git rev-parse --short HEAD) + version="${version_prefix}-pre.${commit_hash}" + # Combine version prefix with commit hash + tag="${package}-${version}" +fi + +cargo build --target wasm32-unknown-unknown --release -p "$package" +mkdir -p ./target/spkg/ +substreams pack $package/substreams.yaml -o ./target/spkg/$package-$version.spkg +aws s3 cp ./target/spkg/$package-$version.spkg "s3://repository.propeller/substreams/$package/$version.spkg" + +echo "Released substreams package: "s3://repository.propeller/substreams/$package/$version.spkg"" \ No newline at end of file From b0fe5bc4e11df0a14dbe1f082fc190e50679c097 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 01:35:21 +0000 Subject: [PATCH 79/86] Add github CI for substreams --- .github/workflows/substream.ci.yaml | 59 +++++++++++++++++++ .../crates/tycho-substreams/src/balances.rs | 5 +- 2 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/substream.ci.yaml diff --git a/.github/workflows/substream.ci.yaml b/.github/workflows/substream.ci.yaml new file mode 100644 index 0000000..32c2aee --- /dev/null +++ b/.github/workflows/substream.ci.yaml @@ -0,0 +1,59 @@ +name: Substreams CI + +on: + push: + paths: + - "substreams/**" + +jobs: + lint: + name: Substreams Lint + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: nightly + components: clippy, rustfmt + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Run checks + run: | + cd substreams + cargo +nightly fmt -- --check + cargo +nightly clippy --all --all-features --all-targets -- -D warnings + + test: + name: Substreams Test + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: stable + targets: wasm32-unknown-unknown + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Run checks + run: | + cd substreams + cargo build --target wasm32-unknown-unknown --all-targets --all-features + cargo test --workspace --all-targets --all-features diff --git a/substreams/crates/tycho-substreams/src/balances.rs b/substreams/crates/tycho-substreams/src/balances.rs index 85e1311..862e1a2 100644 --- a/substreams/crates/tycho-substreams/src/balances.rs +++ b/substreams/crates/tycho-substreams/src/balances.rs @@ -126,10 +126,7 @@ pub fn aggregate_balances_changes( #[cfg(test)] mod tests { use super::*; - use crate::{ - mock_store::MockStore, - pb::tycho::evm::v1::{BalanceDelta, Transaction}, - }; + use crate::{mock_store::MockStore, pb::tycho::evm::v1::BalanceDelta}; use substreams::{ pb::substreams::StoreDelta, prelude::{StoreGet, StoreNew}, From 2288e12032441f930690d397cce43e716c393cab Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 01:42:28 +0000 Subject: [PATCH 80/86] Implement a substreams CD --- .github/workflows/substream.cd.yaml | 37 +++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/substream.cd.yaml diff --git a/.github/workflows/substream.cd.yaml b/.github/workflows/substream.cd.yaml new file mode 100644 index 0000000..307c4de --- /dev/null +++ b/.github/workflows/substream.cd.yaml @@ -0,0 +1,37 @@ +name: Substreams CD + +on: + push: + tags: + - "ethereum-*" + workflow_dispatch: + inputs: + package: + required: true + description: "Package to build" + +jobs: + Release: + name: Release ${{ inputs.package }} + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@v1 + with: + toolchain: stable + targets: wasm32-unknown-unknown + + - name: Setup Rust Cache + uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + + - name: Run checks + run: | + cd substreams + ./release.sh ${{ inputs.package }} From f88fb952b0e4c1f08c5957c8a2966d37ae521ecc Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 02:10:53 +0000 Subject: [PATCH 81/86] Add substreams cli installation. Comment out S3 upload for now. --- .github/workflows/substream.cd.yaml | 8 ++++++++ substreams/release.sh | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/substream.cd.yaml b/.github/workflows/substream.cd.yaml index 307c4de..8e99d96 100644 --- a/.github/workflows/substream.cd.yaml +++ b/.github/workflows/substream.cd.yaml @@ -31,6 +31,14 @@ jobs: with: cache-on-failure: true + - name: Install Substreams CLI + run: | + # Use correct binary for your platform + LINK=$(curl -s https://api.github.com/repos/streamingfast/substreams/releases/latest | awk "/download.url.*linux_$(uname -m)/ {print \$2}" | sed 's/"//g') + curl -L "$LINK" | tar zxf - -C /usr/local/bin + chmod +x /usr/local/bin/substreams + substreams --version + - name: Run checks run: | cd substreams diff --git a/substreams/release.sh b/substreams/release.sh index 27b50e6..d6dc840 100755 --- a/substreams/release.sh +++ b/substreams/release.sh @@ -55,6 +55,6 @@ fi cargo build --target wasm32-unknown-unknown --release -p "$package" mkdir -p ./target/spkg/ substreams pack $package/substreams.yaml -o ./target/spkg/$package-$version.spkg -aws s3 cp ./target/spkg/$package-$version.spkg "s3://repository.propeller/substreams/$package/$version.spkg" +# aws s3 cp ./target/spkg/$package-$version.spkg "s3://repository.propeller/substreams/$package/$version.spkg" echo "Released substreams package: "s3://repository.propeller/substreams/$package/$version.spkg"" \ No newline at end of file From 3f5a74260d49aa45be93636879419e91335b5a89 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 09:30:16 +0000 Subject: [PATCH 82/86] Adjust and uncomment s3 path. --- substreams/release.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/substreams/release.sh b/substreams/release.sh index d6dc840..e011e95 100755 --- a/substreams/release.sh +++ b/substreams/release.sh @@ -15,7 +15,6 @@ if [ -n "$current_tag" ]; then package="${BASH_REMATCH[1]%?}" # Semantic version version="${BASH_REMATCH[2]}" - tag=$current_tag cargo_version=$(cargo pkgid -p ethereum-balancer | cut -d# -f2 | cut -d: -f2) if [[ "$cargo_version" != "$version" ]]; then @@ -48,13 +47,14 @@ else # Get the short commit hash of the current HEAD commit_hash=$(git rev-parse --short HEAD) version="${version_prefix}-pre.${commit_hash}" - # Combine version prefix with commit hash - tag="${package}-${version}" fi +REPOSITORY=${REPOSITORY:-"s3://repo.propellerheads/substreams"} +repository_path="$REPOSITORY/$package/$package-$version.spkg" + cargo build --target wasm32-unknown-unknown --release -p "$package" mkdir -p ./target/spkg/ substreams pack $package/substreams.yaml -o ./target/spkg/$package-$version.spkg -# aws s3 cp ./target/spkg/$package-$version.spkg "s3://repository.propeller/substreams/$package/$version.spkg" +aws s3 cp ./target/spkg/$package-$version.spkg $repository_path -echo "Released substreams package: "s3://repository.propeller/substreams/$package/$version.spkg"" \ No newline at end of file +echo "Released substreams package: '$repository_path'" \ No newline at end of file From e70d5f0e86320abf9def12ffa5da14ed31aab884 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 11:04:41 +0000 Subject: [PATCH 83/86] Clip balances at 0. In case we get negative balances, which happens sometimes e.g. in balancer and seems to be due to some rounding issues within the protocol, we simply clip the balance at 0 so we never emit negative balances as tycho-indexer the upstream system will interpret the balance bytes as unsigned integers. --- .../crates/tycho-substreams/src/balances.rs | 85 +++++++++++++------ .../crates/tycho-substreams/src/contract.rs | 30 +++++-- .../crates/tycho-substreams/src/models.rs | 58 +++++++++---- 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/substreams/crates/tycho-substreams/src/balances.rs b/substreams/crates/tycho-substreams/src/balances.rs index 862e1a2..707f60d 100644 --- a/substreams/crates/tycho-substreams/src/balances.rs +++ b/substreams/crates/tycho-substreams/src/balances.rs @@ -1,15 +1,26 @@ -//! Utilities to handle relative balances. +//! Module for Handling Relative Balance Changes. //! +//! This module facilitates the conversion of relative balance changes into absolute balances, +//! employing a structured approach to ensure the accurate representation of balance data. //! -//! To aggregate relative balances changes to absolute balances the general approach is: +//! Process Overview: //! -//! 1. Use a map function that will extract a `BlockBalanceDeltas` message. BalanceDeltas within -//! this message are required to have increasing ordinals so that the order of relative balance -//! changes is unambiguous. -//! 2. Store the balances changes with a store handler. You can use the `store_balance_changes` -//! library method directly for this. -//! 3. In the output module, use aggregate_balance_changes to receive an aggregated map of absolute -//! balances. +//! 1. **Mapping (User-Implemented)**: The initial step requires the user to implement a mapping +//! function that extracts `BlockBalanceDeltas` messages. It's crucial that `BalanceDelta` +//! messages within these messages have strictly increasing ordinals, which guarantees the order +//! of balance changes is preserved and unambiguous. This step is not provided by the SDK and +//! must be custom-implemented to suit the specific protocol. +//! +//! 2. **Storing Changes**: Utilize the `store_balance_changes` function to apply relative balance +//! changes. This function handles changes additively, preparing them for final aggregation. +//! +//! 3. **Aggregation**: Use the `aggregate_balance_changes` function to compile the processed +//! changes into a detailed map of absolute balances. This final step produces the comprehensive +//! balance data ready for output modules or further analysis. +//! +//! Through this sequence, the module ensures the transformation from relative to absolute +//! balances is conducted with high fidelity, upholding the integrity of transactional data. + use crate::pb::tycho::evm::v1::{BalanceChange, BlockBalanceDeltas, Transaction}; use itertools::Itertools; use std::{collections::HashMap, str::FromStr}; @@ -19,20 +30,29 @@ use substreams::{ prelude::{BigInt, StoreAdd}, }; -/// Store relative balances changes in a additive manner. +/// Stores relative balance changes in an additive manner. /// -/// Effectively aggregates the relative balances changes into an absolute balances. +/// Aggregates the relative balance changes from a `BlockBalanceDeltas` message into the store +/// in an additive way. This function ensures that balance changes are applied correctly +/// according to the order specified by their ordinal values. Each token's balance changes +/// must have strictly increasing ordinals; otherwise, the function will panic. +/// +/// This method is designed to work in conjunction with `aggregate_balances_changes`, +/// which consumes the data stored by this function. The stored data is intended for use +/// in a "deltas mode" processing pattern, as described in the +/// [Substreams documentation](https://substreams.streamingfast.io/documentation/develop/manifest-modules/types#deltas-mode). /// /// ## Arguments +/// * `deltas` - A `BlockBalanceDeltas` message containing the relative balance changes. It is +/// crucial that the relative balance deltas for each token address have strictly increasing +/// ordinals; the function will panic otherwise. +/// * `store` - An implementation of the `StoreAdd` trait that will be used to add relative balance +/// changes. This store should support the addition of `BigInt` values. /// -/// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. Note: -/// relative balance deltas must have strictly increasing ordinals per token address, will panic -/// otherwise. -/// * `store` - An AddStore that will add relative balance changes. -/// -/// This method is meant to be used in combination with `aggregate_balances_changes` -/// which consumes the store filled with this methods in -/// [deltas mode](https://substreams.streamingfast.io/documentation/develop/manifest-modules/types#deltas-mode). +/// ## Panics +/// This function will panic if: +/// - The `component_id` of any delta is not valid UTF-8. +/// - The ordinals for any given token address are not strictly increasing. pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: impl StoreAdd) { let mut previous_ordinal = HashMap::::new(); deltas @@ -71,14 +91,23 @@ type TxAggregatedBalances = HashMap, (Transaction, HashMap, Bala /// * `balance_store` - A `StoreDeltas` with all changes that occured in the source store module. /// * `deltas` - A `BlockBalanceDeltas` message containing the relative balances changes. /// -/// Reads absolute balance values from the additive store (see `store_balance_changes` -/// on how to create such a store), proceeds to zip them with the relative balance -/// deltas to associate balance values to token and component. +/// This function reads absolute balance values from an additive store (see `store_balance_changes` +/// for how to create such a store). It zips these values with the relative balance deltas to +/// associate balance values with tokens and components, ensuring the last balance change per token +/// per transaction is kept if there are multiple changes. Negative balances are set to 0, adhering +/// to the expectation that absolute balances must be non-negative. /// /// Will keep the last balance change per token per transaction if there are multiple -/// changes. +/// changes. In case a balance ends up being negative, it will be clipped to 0 since +/// absolute balances are expected to be either zero or positive. /// -/// Returns a map of transactions hashes to the full transaction and aggregated +/// ## Panics +/// May panic if the store deltas values are not in the correct format. Values are +/// expected to be utf-8 encoded string integers, which is the default behaviour +/// for substreams stores. +/// +/// ## Returns +/// A map of transactions hashes to a tuple of `Transaction` and aggregated /// absolute balance changes. pub fn aggregate_balances_changes( balance_store: StoreDeltas, @@ -95,7 +124,13 @@ pub fn aggregate_balances_changes( let ascii_string = String::from_utf8(store_delta.new_value.clone()).expect("Invalid UTF-8 sequence"); let balance = BigInt::from_str(&ascii_string).expect("Failed to parse integer"); - let big_endian_bytes_balance = balance.to_bytes_be().1; + + // If the absolute balance is negative, we set it to zero. + let big_endian_bytes_balance = if balance < BigInt::zero() { + BigInt::zero().to_bytes_be().1 + } else { + balance.to_bytes_be().1 + }; ( balance_delta diff --git a/substreams/crates/tycho-substreams/src/contract.rs b/substreams/crates/tycho-substreams/src/contract.rs index a99fd60..250da36 100644 --- a/substreams/crates/tycho-substreams/src/contract.rs +++ b/substreams/crates/tycho-substreams/src/contract.rs @@ -72,19 +72,33 @@ impl From for tycho::ContractChange { } } -/// Extracts relevant contract changes from the block. +/// Extracts and aggregates contract changes from a block. /// -/// Contract changes include changes in storage, code and native balance. +/// This function identifies and collects changes to contract storage, code, and native balance for +/// contracts of interest within a given block. It filters contracts based on a user-defined +/// predicate and aggregates changes into a provided mutable map. /// /// ## Arguments -/// -/// * `block` - The block to extract changes from. Must be the extended block model. -/// * `inclusion_predicate` - A predicate function that determines if a contract address is -/// relevant. -/// * `transaction_contract_changes` - A mutable map to store the contract changes in. +/// * `block` - The block from which to extract contract changes, expected to be an extended block +/// model. +/// * `inclusion_predicate` - A closure that determines if a contract's address is of interest for +/// the collection of changes. Only contracts satisfying this predicate are included. +/// * `transaction_contract_changes` - A mutable reference to a map where extracted contract changes +/// are stored. Keyed by transaction index, it aggregates changes into +/// `tycho::TransactionContractChanges`. /// /// ## Panics -/// Will panic in case the detail level of the block is not extended. +/// Panics if the provided block is not an extended block model, as indicated by its detail level. +/// +/// ## Operation +/// The function iterates over transactions and their calls within the block, collecting contract +/// changes (storage, balance, code) that pass the inclusion predicate. Changes are then sorted by +/// their ordinals to maintain the correct sequence of events. Aggregated changes for each contract +/// are stored in `transaction_contract_changes`, categorized by transaction index. +/// +/// Contracts created within the block are tracked to differentiate between new and existing +/// contracts. The aggregation process respects transaction boundaries, ensuring that changes are +/// mapped accurately to their originating transactions. pub fn extract_contract_changes bool>( block: ð::v2::Block, inclusion_predicate: F, diff --git a/substreams/crates/tycho-substreams/src/models.rs b/substreams/crates/tycho-substreams/src/models.rs index 14ab6f5..fa0fa07 100644 --- a/substreams/crates/tycho-substreams/src/models.rs +++ b/substreams/crates/tycho-substreams/src/models.rs @@ -43,38 +43,50 @@ impl From<&sf::Block> for Block { } impl ProtocolComponent { - /// Creates a new empty `ProtocolComponent` instance. + /// Constructs a new, empty `ProtocolComponent`. /// - /// You can use the `with_*` methods to set the fields in a convience way. + /// Initializes an instance with default values. Use `with_*` methods to populate fields + /// conveniently. + /// + /// ## Parameters + /// - `id`: Identifier for the component. + /// - `tx`: Reference to the associated transaction. pub fn new(id: &str, tx: &Transaction) -> Self { Self { id: id.to_string(), - tokens: vec![], - contracts: vec![], - static_att: vec![], + tokens: Vec::new(), + contracts: Vec::new(), + static_att: Vec::new(), change: ChangeType::Creation.into(), protocol_type: None, tx: Some(tx.clone()), } } - /// Shorthand to create a component with a 1-1 relationship to a contract. + /// Initializes a `ProtocolComponent` with a direct association to a contract. /// - /// Will set the component id to a hex encoded address with a 0x prefix - /// and add the contract to contracts attributes. + /// Sets the component's ID to the hex-encoded address with a `0x` prefix and includes the + /// contract in the contracts list. + /// + /// ## Parameters + /// - `id`: Contract address to be encoded and set as the component's ID. + /// - `tx`: Reference to the associated transaction. pub fn at_contract(id: &[u8], tx: &Transaction) -> Self { Self { id: format!("0x{}", hex::encode(id)), - tokens: vec![], + tokens: Vec::new(), contracts: vec![id.to_vec()], - static_att: vec![], + static_att: Vec::new(), change: ChangeType::Creation.into(), protocol_type: None, tx: Some(tx.clone()), } } - /// Replaces the tokens on this component. + /// Updates the tokens associated with this component. + /// + /// ## Parameters + /// - `tokens`: Slice of byte slices representing the tokens to associate. pub fn with_tokens>(mut self, tokens: &[B]) -> Self { self.tokens = tokens .iter() @@ -83,7 +95,10 @@ impl ProtocolComponent { self } - /// Replaces the contracts associated with this component. + /// Updates the contracts associated with this component. + /// + /// ## Parameters + /// - `contracts`: Slice of byte slices representing the contracts to associate. pub fn with_contracts>(mut self, contracts: &[B]) -> Self { self.contracts = contracts .iter() @@ -92,9 +107,12 @@ impl ProtocolComponent { self } - /// Replaces the static attributes on this component. + /// Updates the static attributes of this component. /// - /// The change type will be set to Creation. + /// Sets the change type to `Creation` for all attributes. + /// + /// ## Parameters + /// - `attributes`: Slice of key-value pairs representing the attributes to set. pub fn with_attributes, V: AsRef<[u8]>>(mut self, attributes: &[(K, V)]) -> Self { self.static_att = attributes .iter() @@ -107,15 +125,19 @@ impl ProtocolComponent { self } - /// Sets the protocol_type on this component. + /// Designates this component as a swap type within the protocol. /// - /// Will set the `financial_type` to FinancialType::Swap and the - /// `attribute_schema` to an empty list. + /// Sets the `protocol_type` accordingly, including `financial_type` as `Swap` and leaving + /// `attribute_schema` empty. + /// + /// ## Parameters + /// - `name`: The name of the swap protocol. + /// - `implementation_type`: The implementation type of the protocol. pub fn as_swap_type(mut self, name: &str, implementation_type: ImplementationType) -> Self { self.protocol_type = Some(ProtocolType { name: name.to_string(), financial_type: FinancialType::Swap.into(), - attribute_schema: vec![], + attribute_schema: Vec::new(), implementation_type: implementation_type.into(), }); self From 3b511233115848a9174c1d7deec1497a7bff5b9a Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 12:52:29 +0000 Subject: [PATCH 84/86] Normalise module names for balancer. This way the module names are in sync with the gitbook docs. --- .gitignore | 2 ++ substreams/ethereum-balancer/src/modules.rs | 10 ++++----- substreams/ethereum-balancer/substreams.yaml | 22 ++++++++++---------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 2c65d74..8ab5a15 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ target/ .vscode .idea *.log + +substreams/ethereum-template/Cargo.lock diff --git a/substreams/ethereum-balancer/src/modules.rs b/substreams/ethereum-balancer/src/modules.rs index b1747b1..af6db11 100644 --- a/substreams/ethereum-balancer/src/modules.rs +++ b/substreams/ethereum-balancer/src/modules.rs @@ -15,7 +15,7 @@ use tycho_substreams::{ const VAULT_ADDRESS: &[u8] = &hex!("BA12222222228d8Ba445958a75a0704d566BF2C8"); #[substreams::handlers::map] -pub fn map_pools_created(block: eth::v2::Block) -> Result { +pub fn map_components(block: eth::v2::Block) -> Result { // Gather contract changes by indexing `PoolCreated` events and analysing the `Create` call // We store these as a hashmap by tx hash since we need to agg by tx hash later Ok(BlockTransactionProtocolComponents { @@ -47,7 +47,7 @@ pub fn map_pools_created(block: eth::v2::Block) -> Result Result { @@ -133,7 +133,7 @@ pub fn map_balance_deltas( /// It's significant to include both the `pool_id` and the `token_id` for each balance delta as the /// store key to ensure that there's a unique balance being tallied for each. #[substreams::handlers::store] -pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { +pub fn store_balances(deltas: BlockBalanceDeltas, store: StoreAddBigInt) { tycho_substreams::balances::store_balance_changes(deltas, store); } @@ -144,7 +144,7 @@ pub fn store_balance_changes(deltas: BlockBalanceDeltas, store: StoreAddBigInt) /// At the very end, the map can easily be sorted by index to ensure the final /// `BlockContractChanges` is ordered by transactions properly. #[substreams::handlers::map] -pub fn map_changes( +pub fn map_protocol_changes( block: eth::v2::Block, grouped_components: BlockTransactionProtocolComponents, deltas: BlockBalanceDeltas, diff --git a/substreams/ethereum-balancer/substreams.yaml b/substreams/ethereum-balancer/substreams.yaml index 06f2ee7..9597334 100644 --- a/substreams/ethereum-balancer/substreams.yaml +++ b/substreams/ethereum-balancer/substreams.yaml @@ -9,7 +9,7 @@ binaries: file: ../target/wasm32-unknown-unknown/release/ethereum_balancer.wasm modules: - - name: map_pools_created + - name: map_components kind: map initialBlock: 12369300 inputs: @@ -17,40 +17,40 @@ modules: output: type: proto:tycho.evm.v1.GroupedTransactionProtocolComponents - - name: store_pools_created + - name: store_components kind: store initialBlock: 12369300 updatePolicy: add valueType: int64 inputs: - - map: map_pools_created + - map: map_components - - name: map_balance_deltas + - name: map_relative_balances kind: map initialBlock: 12369300 # An arbitrary block that should change based on your requirements inputs: - source: sf.ethereum.type.v2.Block - - store: store_pools_created + - store: store_components output: type: proto:tycho.evm.v1.BalanceDeltas - - name: store_balance_changes + - name: store_balances kind: store initialBlock: 12369300 updatePolicy: add valueType: bigint inputs: - - map: map_balance_deltas + - map: map_relative_balances - name: map_changes kind: map initialBlock: 12369300 inputs: - source: sf.ethereum.type.v2.Block - - map: map_pools_created - - map: map_balance_deltas - - store: store_pools_created - - store: store_balance_changes + - map: map_components + - map: map_relative_balances + - store: store_components + - store: store_balances mode: deltas # This is the key property that simplifies `BalanceChange` handling output: type: proto:tycho.evm.v1.BlockContractChanges From 2e774053428c5b3967ddc0c8911f24192089162d Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 12:53:12 +0000 Subject: [PATCH 85/86] Update ethereum-template Remove unecessary pb module, import models from tycho-substreams instead. Integrate package directly into workspace. --- substreams/ethereum-template/Cargo.lock | 1135 ----------------- substreams/ethereum-template/Cargo.toml | 11 +- substreams/ethereum-template/src/lib.rs | 8 +- substreams/ethereum-template/src/modules.rs | 12 + substreams/ethereum-template/src/pb/mod.rs | 10 - .../ethereum-template/src/pb/tycho.evm.v1.rs | 183 --- substreams/ethereum-template/substreams.yaml | 13 +- 7 files changed, 23 insertions(+), 1349 deletions(-) delete mode 100644 substreams/ethereum-template/Cargo.lock create mode 100644 substreams/ethereum-template/src/modules.rs delete mode 100644 substreams/ethereum-template/src/pb/mod.rs delete mode 100644 substreams/ethereum-template/src/pb/tycho.evm.v1.rs diff --git a/substreams/ethereum-template/Cargo.lock b/substreams/ethereum-template/Cargo.lock deleted file mode 100644 index ada8eab..0000000 --- a/substreams/ethereum-template/Cargo.lock +++ /dev/null @@ -1,1135 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bigdecimal" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cpufeatures" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" -dependencies = [ - "libc", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "ethabi" -version = "17.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" -dependencies = [ - "ethereum-types", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-rlp", - "impl-serde", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" -dependencies = [ - "ethbloom", - "fixed-hash", - "impl-rlp", - "impl-serde", - "primitive-types", - "uint", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-literal" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "pad" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "parity-scale-codec" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "primitive-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" -dependencies = [ - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" -dependencies = [ - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.41", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "substreams" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3524a4e2931ff6cd58783e62adbd7e44f461752eca0c423793cfb462351f24" -dependencies = [ - "anyhow", - "bigdecimal", - "hex", - "hex-literal", - "num-bigint", - "num-integer", - "num-traits", - "pad", - "prost", - "prost-build", - "prost-types", - "substreams-macro", - "thiserror", -] - -[[package]] -name = "substreams-ethereum" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f45dc04be50b7ca08d6d5c4560ee3eeba16ccaa1c124d0361bb30b5b84e28b" -dependencies = [ - "getrandom", - "num-bigint", - "substreams", - "substreams-ethereum-abigen", - "substreams-ethereum-core", - "substreams-ethereum-derive", -] - -[[package]] -name = "substreams-ethereum-abigen" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c04307913a355aaf2a1bb7186d4bc7e36875f3d4aff77b47e83f1b63b24da55" -dependencies = [ - "anyhow", - "ethabi", - "heck", - "hex", - "prettyplease", - "proc-macro2", - "quote", - "substreams-ethereum-core", - "syn 1.0.109", -] - -[[package]] -name = "substreams-ethereum-core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db9048cc9a66873ab7069ef958c2684994e6ee323da49c186b19156fdb4ca131" -dependencies = [ - "bigdecimal", - "ethabi", - "getrandom", - "num-bigint", - "prost", - "prost-build", - "prost-types", - "substreams", -] - -[[package]] -name = "substreams-ethereum-derive" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e862928bee8653f5c9291ac619c8dc0da14ca61d8cd8d89b3acdbbde4d0bf304" -dependencies = [ - "ethabi", - "heck", - "hex", - "num-bigint", - "proc-macro2", - "quote", - "substreams-ethereum-abigen", - "syn 1.0.109", -] - -[[package]] -name = "substreams-ethereum-template" -version = "0.1.0" -dependencies = [ - "prost", - "substreams", - "substreams-ethereum", -] - -[[package]] -name = "substreams-macro" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c2b15adf5b4d7a6d1a73c73df951a6b2df6fbb4f0b41304dc28c5550ce0ed0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "thiserror", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "thiserror" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.41", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] diff --git a/substreams/ethereum-template/Cargo.toml b/substreams/ethereum-template/Cargo.toml index 82ae8f3..fa4ecad 100644 --- a/substreams/ethereum-template/Cargo.toml +++ b/substreams/ethereum-template/Cargo.toml @@ -1,13 +1,14 @@ [package] -name = "substreams-ethereum-template" +name = "ethereum-template" version = "0.1.0" edition = "2021" [lib] -name = "substreams_ethereum_template" +name = "ethereum_template" crate-type = ["cdylib"] [dependencies] -substreams = "0.5" -substreams-ethereum = "0.9" -prost = "0.11" +substreams.workspace = true +substreams-ethereum.workspace = true +prost.workspace = true +tycho-substreams.workspace = true \ No newline at end of file diff --git a/substreams/ethereum-template/src/lib.rs b/substreams/ethereum-template/src/lib.rs index 6e10475..94324fd 100644 --- a/substreams/ethereum-template/src/lib.rs +++ b/substreams/ethereum-template/src/lib.rs @@ -1,13 +1,9 @@ - use substreams_ethereum::pb::eth; - -use pb::tycho::evm::v1::{self as tycho}; - -mod pb; +mod modules; #[substreams::handlers::map] fn map_changes( block: eth::v2::Block, ) -> Result { todo!("Not implemented") -} \ No newline at end of file +} diff --git a/substreams/ethereum-template/src/modules.rs b/substreams/ethereum-template/src/modules.rs new file mode 100644 index 0000000..136d351 --- /dev/null +++ b/substreams/ethereum-template/src/modules.rs @@ -0,0 +1,12 @@ +use std::collections::HashMap; +use substreams_ethereum::pb::eth; +use tycho_substreams::prelude::*; + +#[substreams::handlers::map] +fn map_protocol_changes( + block: eth::v2::Block, +) -> Result { + let mut transaction_contract_changes = Vec::::new(); + // TODO: protocol specific logic goes here + Ok(BlockContractChanges { block: Some((&block).into()), changes: transaction_contract_changes }) +} diff --git a/substreams/ethereum-template/src/pb/mod.rs b/substreams/ethereum-template/src/pb/mod.rs deleted file mode 100644 index 43d8838..0000000 --- a/substreams/ethereum-template/src/pb/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -// @generated -pub mod tycho { - pub mod evm { - // @@protoc_insertion_point(attribute:tycho.evm.v1) - pub mod v1 { - include!("tycho.evm.v1.rs"); - // @@protoc_insertion_point(tycho.evm.v1) - } - } -} diff --git a/substreams/ethereum-template/src/pb/tycho.evm.v1.rs b/substreams/ethereum-template/src/pb/tycho.evm.v1.rs deleted file mode 100644 index b59b5f7..0000000 --- a/substreams/ethereum-template/src/pb/tycho.evm.v1.rs +++ /dev/null @@ -1,183 +0,0 @@ -// @generated -// This file contains the proto definitions for Substreams common to all integrations. - -/// A struct describing a block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Block { - /// The blocks hash. - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, - /// The parent blocks hash. - #[prost(bytes="vec", tag="2")] - pub parent_hash: ::prost::alloc::vec::Vec, - /// The block number. - #[prost(uint64, tag="3")] - pub number: u64, - /// The block timestamp. - #[prost(uint64, tag="4")] - pub ts: u64, -} -/// A struct describing a transaction. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Transaction { - /// The transaction hash. - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, - /// The sender of the transaction. - #[prost(bytes="vec", tag="2")] - pub from: ::prost::alloc::vec::Vec, - /// The receiver of the transaction. - #[prost(bytes="vec", tag="3")] - pub to: ::prost::alloc::vec::Vec, - /// The transactions index within the block. - #[prost(uint64, tag="4")] - pub index: u64, -} -/// A custom struct representing an arbitrary attribute of a protocol component. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Attribute { - /// The name of the attribute. - #[prost(string, tag="1")] - pub name: ::prost::alloc::string::String, - /// The value of the attribute. - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, - /// The type of change the attribute underwent. - #[prost(enumeration="ChangeType", tag="3")] - pub change: i32, -} -/// A struct describing a part of the protocol. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ProtocolComponent { - /// A unique identifier for the component within the protocol. - /// Can be a stringified address or a string describing the trading pair. - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - /// Addresses of the ERC20 tokens used by the component. - #[prost(bytes="vec", repeated, tag="2")] - pub tokens: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, - /// Addresses of the contracts used by the component. - #[prost(bytes="vec", repeated, tag="3")] - pub contracts: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, - /// Attributes of the component. - /// The inner ChangeType of the attribute has to match the ChangeType of the ProtocolComponent. - #[prost(message, repeated, tag="4")] - pub static_att: ::prost::alloc::vec::Vec, - /// Type of change the component underwent. - #[prost(enumeration="ChangeType", tag="5")] - pub change: i32, -} -/// A struct for following the changes of Total Value Locked (TVL) of a protocol component. -/// Note that if the ProtocolComponent contains multiple contracts, the TVL is tracked for the component as a whole. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BalanceChange { - /// The address of the ERC20 token whose balance changed. - #[prost(bytes="vec", tag="1")] - pub token: ::prost::alloc::vec::Vec, - /// The new balance of the token. - #[prost(bytes="vec", tag="2")] - pub balance: ::prost::alloc::vec::Vec, - /// The id of the component whose TVL is tracked. - #[prost(bytes="vec", tag="3")] - pub component_id: ::prost::alloc::vec::Vec, -} -/// Enum to specify the type of a change. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ChangeType { - Unspecified = 0, - Update = 1, - Creation = 2, - Deletion = 3, -} -impl ChangeType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ChangeType::Unspecified => "CHANGE_TYPE_UNSPECIFIED", - ChangeType::Update => "CHANGE_TYPE_UPDATE", - ChangeType::Creation => "CHANGE_TYPE_CREATION", - ChangeType::Deletion => "CHANGE_TYPE_DELETION", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "CHANGE_TYPE_UNSPECIFIED" => Some(Self::Unspecified), - "CHANGE_TYPE_UPDATE" => Some(Self::Update), - "CHANGE_TYPE_CREATION" => Some(Self::Creation), - "CHANGE_TYPE_DELETION" => Some(Self::Deletion), - _ => None, - } - } -} -// This file contains proto definitions specific to the VM integration. - -/// A key value entry into contract storage. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ContractSlot { - /// A contract's storage slot. - #[prost(bytes="vec", tag="2")] - pub slot: ::prost::alloc::vec::Vec, - /// The new value for this storage slot. - #[prost(bytes="vec", tag="3")] - pub value: ::prost::alloc::vec::Vec, -} -/// Changes made to a single contract's state. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ContractChange { - /// The contract's address - #[prost(bytes="vec", tag="1")] - pub address: ::prost::alloc::vec::Vec, - /// The new balance of the contract, empty bytes indicates no change. - #[prost(bytes="vec", tag="2")] - pub balance: ::prost::alloc::vec::Vec, - /// The new code of the contract, empty bytes indicates no change. - #[prost(bytes="vec", tag="3")] - pub code: ::prost::alloc::vec::Vec, - /// The changes to this contract's slots, empty sequence indicates no change. - #[prost(message, repeated, tag="4")] - pub slots: ::prost::alloc::vec::Vec, - /// Whether this is an update, a creation or a deletion. - #[prost(enumeration="ChangeType", tag="5")] - pub change: i32, -} -/// A set of changes aggregated by transaction. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransactionContractChanges { - /// The transaction instance that results in the changes. - #[prost(message, optional, tag="1")] - pub tx: ::core::option::Option, - /// Contains the changes induced by the above transaction, aggregated on a per-contract basis. - #[prost(message, repeated, tag="2")] - pub contract_changes: ::prost::alloc::vec::Vec, - /// An array of newly added components. - #[prost(message, repeated, tag="3")] - pub component_changes: ::prost::alloc::vec::Vec, - /// An array of balance changes to components. - #[prost(message, repeated, tag="4")] - pub balance_changes: ::prost::alloc::vec::Vec, -} -/// A set of transaction changes within a single block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockContractChanges { - /// The block for which these changes are collectively computed. - #[prost(message, optional, tag="1")] - pub block: ::core::option::Option, - /// The set of transaction changes observed in the specified block. - #[prost(message, repeated, tag="2")] - pub changes: ::prost::alloc::vec::Vec, -} -// @@protoc_insertion_point(module) diff --git a/substreams/ethereum-template/substreams.yaml b/substreams/ethereum-template/substreams.yaml index b3fa3fb..de5dcbf 100644 --- a/substreams/ethereum-template/substreams.yaml +++ b/substreams/ethereum-template/substreams.yaml @@ -1,22 +1,15 @@ specVersion: v0.1.0 package: - name: "substreams_ethereum_template" + name: "ethereum_template" version: v0.1.0 -protobuf: - files: - - vm.proto - - common.proto - importPaths: - - ../../proto/tycho/evm/v1/ - binaries: default: type: wasm/rust-v1 - file: ../../target/wasm32-unknown-unknown/substreams/substreams_ethereum_template.wasm + file: ../target/wasm32-unknown-unknown/release/ethereum_template.wasm modules: - - name: map_changes + - name: map_protocol_changes kind: map inputs: - source: sf.ethereum.type.v2.Block From d972da244f291a8e39dcc42b15028e252526a3a8 Mon Sep 17 00:00:00 2001 From: kayibal Date: Thu, 14 Mar 2024 13:05:06 +0000 Subject: [PATCH 86/86] Remove outdated readme. Add docs about releasing. --- substreams/Readme.md | 107 +++++++------------------------------------ 1 file changed, 16 insertions(+), 91 deletions(-) diff --git a/substreams/Readme.md b/substreams/Readme.md index 530d858..0ceaea5 100644 --- a/substreams/Readme.md +++ b/substreams/Readme.md @@ -1,99 +1,24 @@ -# Subtreams packages +# Substreams Indexing Integrations -This directory contains all substream packages that are used to index integrated protocols across different blockchains. +Please refer to the official [Substreams Indexing](https://app.gitbook.com/o/9wMvRDQIhk1xOsIZ0Zde/s/Yx9kvxtpT2xWdzvFiB3t/indexing/substreams-integration) docs. -## Adding a new package +## Release -To add a new package add a folder. The naming convention is `[CHAIN]-[PROTOCOL_SYSTEM]`. +To release a package simply tag a commit with the package name and its version: +e.g. `ethereum-balancer-0.1.0`. This will create a release and automatically build +and push the spkg into our registry. -### Manifest -In this new folder add a manifest file `substreams.yaml`. You can use the template below to get started: +### Note +The CD pipeline will error if the Cargo version is not the same as the version in +the tag. -```yaml -specVersion: v0.1.0 -package: - name: 'substreams_[CHAIN]_[PROTOCOL_SYSTEM]' - version: v0.1.0 +Releases are immutable so do no try to delete tags or build the same release twice +since this will error. -protobuf: - files: - - vm.proto - - common.proto - # You can specify any internal proto files here - importPaths: - - ../../proto/tycho/evm/v1/ - # Any private message types only used in internal modules - # can remain local to the folder. - - ./proto +### Pre release -binaries: - default: - type: wasm/rust-v1 - # this points to the workspace target directory we use a special - # substreams build profile to optimise wasm binaries - file: ../../target/wasm32-unknown-unknown/substreams/substreams_[CHAIN]_[PROTOCOL_SYSTEM].wasm +To create a pre release for testing in dev you can start CD pipeline manually supplying +the package you'd like to pre release. This will create a +`[package]-[semver].pre-[commit-sha]` release in our spkg repository which you can use +to run the substream´. -modules: - - name: map_changes - kind: map - inputs: - - source: sf.ethereum.type.v2.Block - output: - type: proto:tycho.evm.state.v1.BlockContractChanges -``` - -Substreams packages are Rust crates so we also need a `cargo.toml`. -The example from the official docs will serve us just well: - -```toml -[package] -name = "substreams-[CHAIN]-[PROTOCOL_SYSTEM]" -version = "0.1.0" -edition = "2021" - -[lib] -name = "substreams_[CHAIN]_[PROTOCOL_SYSTEM]" -crate-type = ["cdylib"] - -[dependencies] -substreams = "0.5" -substreams-ethereum = "0.9" -prost = "0.11" - -``` - -There are already some generated rust files in the `src/pb` directory. These are generated -from the protobuf files in the `/proto/tycho/evm/v1` directory. They specify the output protobuf messages -we want to generate. The input Block is specified by the subtreams crate, specifically the [sf.ethereum.type.v2.Block](https://github.com/streamingfast/substreams-ethereum/blob/develop/core/src/pb/sf.ethereum.type.v2.rs) message. - -You can define your own protobuf messages, make a new directory `/substreams/[CHAIN]-[PROTOCOL]/proto` for them. - - -Now we can generate the Rust protobuf code: - -``` -substreams protogen substreams.yaml --exclude-paths="sf/substreams,google" -``` - -The command above should put the generate rust files under `/src/pb`. You -can start using these now in your module handlers: See -the [official substreams documentation](https://thegraph.com/docs/en/substreams/getting-started/quickstart/#create-substreams-module-handlers) -on -how to implement module handlers. - -You can also look into already existing substreams packages to see how it -is done. E.g. [ethereum-ambient](./ethereum-ambient/) provides a pretty good -example of how to get access to raw contract storage. - -# Tests - -To create a block test asset for ethereum do the following: - -- Follow [this tutorial](https://substreams.streamingfast.io/tutorials/overview/map_block_meta_module). Make sure you - set up the substreams-explorer repo in the same directory as this repo. - - Comment out `image: ./ethereum.png` in `ethereum-explorer/substreams.yaml` - - Add `prost-types = "0.11.0"` to `ethereum-explorer/Cargo.toml` -- Make sure you set up your key env vars. -- Run `sh scripts/download-ethereum-block-to-s3 BLOCK_NUMBER` - -Do not commit the block files (they are quite big). \ No newline at end of file