diff --git a/tycho_simulation_py/python/tycho_simulation_py/assets/ISwapAdapterV2.abi b/tycho_simulation_py/python/tycho_simulation_py/assets/ISwapAdapterV2.abi new file mode 100644 index 00000000..15c88763 --- /dev/null +++ b/tycho_simulation_py/python/tycho_simulation_py/assets/ISwapAdapterV2.abi @@ -0,0 +1 @@ +{"abi":[{"type":"function","name":"getCapabilities","inputs":[{"name":"poolId","type":"bytes","internalType":"bytes"},{"name":"sellToken","type":"address","internalType":"address"},{"name":"buyToken","type":"address","internalType":"address"}],"outputs":[{"name":"capabilities","type":"uint8[]","internalType":"enum ISwapAdapterTypes.Capability[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"getLimits","inputs":[{"name":"poolId","type":"bytes","internalType":"bytes"},{"name":"sellToken","type":"address","internalType":"address"},{"name":"buyToken","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"limits","type":"uint256[]","internalType":"uint256[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"getPoolIds","inputs":[{"name":"offset","type":"uint256","internalType":"uint256"},{"name":"limit","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"ids","type":"bytes32[]","internalType":"bytes32[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"getTokens","inputs":[{"name":"poolId","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"tokens","type":"address[]","internalType":"address[]"}],"stateMutability":"nonpayable"},{"type":"function","name":"price","inputs":[{"name":"poolId","type":"bytes","internalType":"bytes"},{"name":"sellToken","type":"address","internalType":"address"},{"name":"buyToken","type":"address","internalType":"address"},{"name":"specifiedAmounts","type":"uint256[]","internalType":"uint256[]"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"prices","type":"tuple[]","internalType":"struct ISwapAdapterTypes.Fraction[]","components":[{"name":"numerator","type":"uint256","internalType":"uint256"},{"name":"denominator","type":"uint256","internalType":"uint256"}]}],"stateMutability":"nonpayable"},{"type":"function","name":"swap","inputs":[{"name":"poolId","type":"bytes","internalType":"bytes"},{"name":"sellToken","type":"address","internalType":"address"},{"name":"buyToken","type":"address","internalType":"address"},{"name":"side","type":"uint8","internalType":"enum ISwapAdapterTypes.OrderSide"},{"name":"specifiedAmount","type":"uint256","internalType":"uint256"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"trade","type":"tuple","internalType":"struct ISwapAdapterTypes.Trade","components":[{"name":"calculatedAmount","type":"uint256","internalType":"uint256"},{"name":"gasUsed","type":"uint256","internalType":"uint256"},{"name":"price","type":"tuple","internalType":"struct ISwapAdapterTypes.Fraction","components":[{"name":"numerator","type":"uint256","internalType":"uint256"},{"name":"denominator","type":"uint256","internalType":"uint256"}]}]}],"stateMutability":"nonpayable"},{"type":"error","name":"LimitExceeded","inputs":[{"name":"limit","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"NotImplemented","inputs":[{"name":"reason","type":"string","internalType":"string"}]},{"type":"error","name":"Unavailable","inputs":[{"name":"reason","type":"string","internalType":"string"}]}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"getCapabilities(bytes,address,address)":"eb393a9c","getLimits(bytes,address,address,bytes)":"c8af3d53","getPoolIds(uint256,uint256)":"23eeca01","getTokens(bytes)":"2c959543","price(bytes,address,address,uint256[],bytes)":"c130f7a9","swap(bytes,address,address,uint8,uint256,bytes)":"18905bed"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.27+commit.40a35a09\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"}],\"name\":\"LimitExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"NotImplemented\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"reason\",\"type\":\"string\"}],\"name\":\"Unavailable\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"poolId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sellToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"buyToken\",\"type\":\"address\"}],\"name\":\"getCapabilities\",\"outputs\":[{\"internalType\":\"enum ISwapAdapterTypes.Capability[]\",\"name\":\"capabilities\",\"type\":\"uint8[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"poolId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sellToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"buyToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"getLimits\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"limits\",\"type\":\"uint256[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"limit\",\"type\":\"uint256\"}],\"name\":\"getPoolIds\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"ids\",\"type\":\"bytes32[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"poolId\",\"type\":\"bytes\"}],\"name\":\"getTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"poolId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sellToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"buyToken\",\"type\":\"address\"},{\"internalType\":\"uint256[]\",\"name\":\"specifiedAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"price\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"internalType\":\"struct ISwapAdapterTypes.Fraction[]\",\"name\":\"prices\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"poolId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sellToken\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"buyToken\",\"type\":\"address\"},{\"internalType\":\"enum ISwapAdapterTypes.OrderSide\",\"name\":\"side\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"specifiedAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"calculatedAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"gasUsed\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"internalType\":\"struct ISwapAdapterTypes.Fraction\",\"name\":\"price\",\"type\":\"tuple\"}],\"internalType\":\"struct ISwapAdapterTypes.Trade\",\"name\":\"trade\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Implement this interface to support Propeller routing through your pools. Before implementing the interface we need to introduce some function for a given pool. The main one, the swap(x) function, implements a sell order of a specified token. The gas function simply returns the estimated gas cost given a specified amount x. Last but not least, the price function is the derivative of the swap function. It represents the best possible price a user can get from a pool after swapping x of the specified token. During calls to swap and getLimits, the caller can be assumed to have the required sell or buy token balance as well as unlimited approvals to this contract.\",\"errors\":{\"LimitExceeded(uint256)\":[{\"details\":\"The LimitExceeded error is thrown when a limit has been exceeded. E.g. the specified amount can't be traded safely.\"}],\"NotImplemented(string)\":[{\"details\":\"The NotImplemented error is thrown when a function is not implemented.\"}],\"Unavailable(string)\":[{\"details\":\"The Unavailable error is thrown when a pool or swap is not available for unexpected reason. E.g. it was paused due to a bug.\"}]},\"kind\":\"dev\",\"methods\":{\"getCapabilities(bytes,address,address)\":{\"params\":{\"poolId\":\"The ID of the trading pool.\"},\"returns\":{\"capabilities\":\"An array of Capability.\"}},\"getLimits(bytes,address,address,bytes)\":{\"details\":\"Retrieve the maximum limits of a token that can be traded. The limit is reached when the change in the received amounts is zero or close to zero or when the swap fails because of the pools restrictions. Overestimate if in doubt rather than underestimate. The swap function should not error with `LimitExceeded` if called with amounts below the limit.\",\"params\":{\"buyToken\":\"The token being bought.\",\"data\":\"Any additional data required, that does not fit the interface\",\"poolId\":\"The ID of the trading pool.\",\"sellToken\":\"The token being sold.\"},\"returns\":{\"limits\":\"An array of size two indicating the limit amount for the sell token (maximum the pool is willing to buy in sell token) as well as the limit amount of the buy token (maximum the pool is willing to sell in buy token).\"}},\"getPoolIds(uint256,uint256)\":{\"details\":\"Mainly used for testing. It is alright to not return all available pools here. Nevertheless, this is useful to test against the substreams implementation. If implemented, it saves time writing custom tests.\",\"params\":{\"limit\":\"The maximum number of pool IDs to retrieve.\",\"offset\":\"The starting index from which to retrieve pool IDs.\"},\"returns\":{\"ids\":\"An array of pool IDs.\"}},\"getTokens(bytes)\":{\"details\":\"Mainly used for testing as this is redundant with the required substreams implementation.\",\"params\":{\"poolId\":\"The ID of the trading pool.\"},\"returns\":{\"tokens\":\"An array of address contracts.\"}},\"price(bytes,address,address,uint256[],bytes)\":{\"details\":\"The returned prices should include all dex fees. In case the fee is dynamic, the returned price is expected to include the minimum fee. Ideally this method should be implemented, although it is optional as the price function can be numerically estimated from the swap function. In case it is not available, it should be flagged via capabilities and calling it should revert using the `NotImplemented` error. The method needs to be implemented as view as this is usually more efficient and can be run in parallel.\",\"params\":{\"buyToken\":\"The token being bought.\",\"data\":\"Any additional data required, that does not fit the interface\",\"poolId\":\"The ID of the trading pool.\",\"sellToken\":\"The token being sold.\",\"specifiedAmounts\":\"The specified amounts used for price calculation.\"},\"returns\":{\"prices\":\"array of prices as fractions corresponding to the provided amounts.\"}},\"swap(bytes,address,address,uint8,uint256,bytes)\":{\"details\":\"This function should be state modifying, meaning it should actually execute the swap and change the state of the EVM accordingly. Please include a gas usage estimate for each amount. This can be achieved e.g. by using the `gasleft()` function. The return type `Trade` has an attribute called price which should contain the value of `price(specifiedAmount)`. As this is optional, defined via `Capability.PriceFunction`, it is valid to return a Fraction(0, 0) value for this price. In that case the price will be estimated numerically.\",\"params\":{\"buyToken\":\"The token being bought.\",\"data\":\"Any additional data required, that does not fit the interface\",\"poolId\":\"The ID of the trading pool.\",\"sellToken\":\"The token being sold.\",\"side\":\"The side of the trade (Sell or Buy).\",\"specifiedAmount\":\"The amount to be traded.\"},\"returns\":{\"trade\":\"Trade struct representing the executed trade.\"}}},\"title\":\"ISwapAdapter\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getCapabilities(bytes,address,address)\":{\"notice\":\"Retrieves the capabilities of the selected pool.\"},\"getLimits(bytes,address,address,bytes)\":{\"notice\":\"Retrieves the limits for each token.\"},\"getPoolIds(uint256,uint256)\":{\"notice\":\"Retrieves a range of pool IDs.\"},\"getTokens(bytes)\":{\"notice\":\"Retrieves the tokens in the selected pool.\"},\"price(bytes,address,address,uint256[],bytes)\":{\"notice\":\"Calculates pool prices for specified amounts (optional).\"},\"swap(bytes,address,address,uint8,uint256,bytes)\":{\"notice\":\"Simulates swapping tokens on a given pool.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/interfaces/ISwapAdapterV2.sol\":\"ISwapAdapterV2\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":balancer-v2/interfaces/=lib/balancer-v2-monorepo/pkg/interfaces/contracts/\",\":ds-test/=lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":src/=src/\"],\"viaIR\":true},\"sources\":{\"src/interfaces/ISwapAdapterTypes.sol\":{\"keccak256\":\"0xf5637c8fca78253bd88d94d8173d8de4487146f82e462df42f428142ee951778\",\"license\":\"AGPL-3.0-or-later\",\"urls\":[\"bzz-raw://f2c3ab44f87f9c945f52052196537e057292e45d4011830c73a9495e60cdbf4c\",\"dweb:/ipfs/QmePvUFDNHpH2b5Y4kRBXgSrA55RrZgjdUXwV5GLNX5o5h\"]},\"src/interfaces/ISwapAdapterV2.sol\":{\"keccak256\":\"0xaed77b8b06d05e2bc0b188907d48a1bc694a0a8b1786efb22c6938a039772368\",\"license\":\"AGPL-3.0-or-later\",\"urls\":[\"bzz-raw://bcab603f4939ffa0ca19fcf635d134d23f991ef7cc2ea91e9af2473b43c87af9\",\"dweb:/ipfs/QmbiM1nxDVPQfVQLzwAHEgyzbGCmn87YeXZWuASdcxZLVc\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.27+commit.40a35a09"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"type":"error","name":"LimitExceeded"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"type":"error","name":"NotImplemented"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"type":"error","name":"Unavailable"},{"inputs":[{"internalType":"bytes","name":"poolId","type":"bytes"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"getCapabilities","outputs":[{"internalType":"enum ISwapAdapterTypes.Capability[]","name":"capabilities","type":"uint8[]"}]},{"inputs":[{"internalType":"bytes","name":"poolId","type":"bytes"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"getLimits","outputs":[{"internalType":"uint256[]","name":"limits","type":"uint256[]"}]},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"getPoolIds","outputs":[{"internalType":"bytes32[]","name":"ids","type":"bytes32[]"}]},{"inputs":[{"internalType":"bytes","name":"poolId","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"getTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}]},{"inputs":[{"internalType":"bytes","name":"poolId","type":"bytes"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"uint256[]","name":"specifiedAmounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"price","outputs":[{"internalType":"struct ISwapAdapterTypes.Fraction[]","name":"prices","type":"tuple[]","components":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}]}]},{"inputs":[{"internalType":"bytes","name":"poolId","type":"bytes"},{"internalType":"address","name":"sellToken","type":"address"},{"internalType":"address","name":"buyToken","type":"address"},{"internalType":"enum ISwapAdapterTypes.OrderSide","name":"side","type":"uint8"},{"internalType":"uint256","name":"specifiedAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"swap","outputs":[{"internalType":"struct ISwapAdapterTypes.Trade","name":"trade","type":"tuple","components":[{"internalType":"uint256","name":"calculatedAmount","type":"uint256"},{"internalType":"uint256","name":"gasUsed","type":"uint256"},{"internalType":"struct ISwapAdapterTypes.Fraction","name":"price","type":"tuple","components":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}]}]}]}],"devdoc":{"kind":"dev","methods":{"getCapabilities(bytes,address,address)":{"params":{"poolId":"The ID of the trading pool."},"returns":{"capabilities":"An array of Capability."}},"getLimits(bytes,address,address,bytes)":{"details":"Retrieve the maximum limits of a token that can be traded. The limit is reached when the change in the received amounts is zero or close to zero or when the swap fails because of the pools restrictions. Overestimate if in doubt rather than underestimate. The swap function should not error with `LimitExceeded` if called with amounts below the limit.","params":{"buyToken":"The token being bought.","data":"Any additional data required, that does not fit the interface","poolId":"The ID of the trading pool.","sellToken":"The token being sold."},"returns":{"limits":"An array of size two indicating the limit amount for the sell token (maximum the pool is willing to buy in sell token) as well as the limit amount of the buy token (maximum the pool is willing to sell in buy token)."}},"getPoolIds(uint256,uint256)":{"details":"Mainly used for testing. It is alright to not return all available pools here. Nevertheless, this is useful to test against the substreams implementation. If implemented, it saves time writing custom tests.","params":{"limit":"The maximum number of pool IDs to retrieve.","offset":"The starting index from which to retrieve pool IDs."},"returns":{"ids":"An array of pool IDs."}},"getTokens(bytes)":{"details":"Mainly used for testing as this is redundant with the required substreams implementation.","params":{"poolId":"The ID of the trading pool."},"returns":{"tokens":"An array of address contracts."}},"price(bytes,address,address,uint256[],bytes)":{"details":"The returned prices should include all dex fees. In case the fee is dynamic, the returned price is expected to include the minimum fee. Ideally this method should be implemented, although it is optional as the price function can be numerically estimated from the swap function. In case it is not available, it should be flagged via capabilities and calling it should revert using the `NotImplemented` error. The method needs to be implemented as view as this is usually more efficient and can be run in parallel.","params":{"buyToken":"The token being bought.","data":"Any additional data required, that does not fit the interface","poolId":"The ID of the trading pool.","sellToken":"The token being sold.","specifiedAmounts":"The specified amounts used for price calculation."},"returns":{"prices":"array of prices as fractions corresponding to the provided amounts."}},"swap(bytes,address,address,uint8,uint256,bytes)":{"details":"This function should be state modifying, meaning it should actually execute the swap and change the state of the EVM accordingly. Please include a gas usage estimate for each amount. This can be achieved e.g. by using the `gasleft()` function. The return type `Trade` has an attribute called price which should contain the value of `price(specifiedAmount)`. As this is optional, defined via `Capability.PriceFunction`, it is valid to return a Fraction(0, 0) value for this price. In that case the price will be estimated numerically.","params":{"buyToken":"The token being bought.","data":"Any additional data required, that does not fit the interface","poolId":"The ID of the trading pool.","sellToken":"The token being sold.","side":"The side of the trade (Sell or Buy).","specifiedAmount":"The amount to be traded."},"returns":{"trade":"Trade struct representing the executed trade."}}},"version":1},"userdoc":{"kind":"user","methods":{"getCapabilities(bytes,address,address)":{"notice":"Retrieves the capabilities of the selected pool."},"getLimits(bytes,address,address,bytes)":{"notice":"Retrieves the limits for each token."},"getPoolIds(uint256,uint256)":{"notice":"Retrieves a range of pool IDs."},"getTokens(bytes)":{"notice":"Retrieves the tokens in the selected pool."},"price(bytes,address,address,uint256[],bytes)":{"notice":"Calculates pool prices for specified amounts (optional)."},"swap(bytes,address,address,uint8,uint256,bytes)":{"notice":"Simulates swapping tokens on a given pool."}},"version":1}},"settings":{"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","balancer-v2/interfaces/=lib/balancer-v2-monorepo/pkg/interfaces/contracts/","ds-test/=lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/","src/=src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/interfaces/ISwapAdapterV2.sol":"ISwapAdapterV2"},"evmVersion":"paris","libraries":{},"viaIR":true},"sources":{"src/interfaces/ISwapAdapterTypes.sol":{"keccak256":"0xf5637c8fca78253bd88d94d8173d8de4487146f82e462df42f428142ee951778","urls":["bzz-raw://f2c3ab44f87f9c945f52052196537e057292e45d4011830c73a9495e60cdbf4c","dweb:/ipfs/QmePvUFDNHpH2b5Y4kRBXgSrA55RrZgjdUXwV5GLNX5o5h"],"license":"AGPL-3.0-or-later"},"src/interfaces/ISwapAdapterV2.sol":{"keccak256":"0xaed77b8b06d05e2bc0b188907d48a1bc694a0a8b1786efb22c6938a039772368","urls":["bzz-raw://bcab603f4939ffa0ca19fcf635d134d23f991ef7cc2ea91e9af2473b43c87af9","dweb:/ipfs/QmbiM1nxDVPQfVQLzwAHEgyzbGCmn87YeXZWuASdcxZLVc"],"license":"AGPL-3.0-or-later"}},"version":1},"id":47} \ No newline at end of file diff --git a/tycho_simulation_py/python/tycho_simulation_py/evm/adapter_contract.py b/tycho_simulation_py/python/tycho_simulation_py/evm/adapter_contract.py index 96f01745..8f35bde4 100644 --- a/tycho_simulation_py/python/tycho_simulation_py/evm/adapter_contract.py +++ b/tycho_simulation_py/python/tycho_simulation_py/evm/adapter_contract.py @@ -138,6 +138,7 @@ def price( amounts: list[int], block: EVMBlock, overwrites: TStateOverwrites = None, + **kwargs, ) -> list[Fraction]: args = [HexBytes(pair_id), sell_token.address, buy_token.address, amounts] res = self.call( @@ -158,6 +159,7 @@ def swap( amount: Decimal, block: EVMBlock, overwrites: TStateOverwrites = None, + **kwargs, ) -> tuple[Trade, dict[str, StateUpdate]]: args = [ HexBytes(pair_id), @@ -183,6 +185,7 @@ def get_limits( buy_token: EthereumToken, block: EVMBlock, overwrites: TStateOverwrites = None, + **kwargs, ) -> tuple[int, int]: args = [HexBytes(pair_id), sell_token.address, buy_token.address] res = self.call( @@ -195,7 +198,7 @@ def get_limits( return res.return_value[0] def get_capabilities( - self, pair_id: HexStr, sell_token: EthereumToken, buy_token: EthereumToken + self, pair_id: HexStr, sell_token: EthereumToken, buy_token: EthereumToken, **kwargs, ) -> set[Capability]: args = [HexBytes(pair_id), sell_token.address, buy_token.address] res = self.call("getCapabilities", args, block_number=1) @@ -204,3 +207,92 @@ def get_capabilities( def min_gas_usage(self) -> int: res = self.call("minGasUsage", [], block_number=1) return res.return_value[0] + + +class AdapterContractV2(TychoSimulationContract): + """ + The AdapterContract provides an interface to interact with the protocols implemented + by third parties using the `propeller-protocol-lib`. + """ + + def __init__(self, address: Address, engine: SimulationEngine): + super().__init__(address, "ISwapAdapterV2", engine) + + def price( + self, + pair_id: HexStr, + sell_token: EthereumToken, + buy_token: EthereumToken, + amounts: list[int], + data: HexStr, + block: EVMBlock, + overwrites: TStateOverwrites = None, + ) -> list[Fraction]: + args = [HexBytes(pair_id), sell_token.address, buy_token.address, amounts, HexBytes(data)] + res = self.call( + "price", + args, + block_number=block.id, + timestamp=int(block.ts.timestamp()), + overrides=overwrites, + ) + return list(map(lambda x: Fraction(*x), res.return_value[0])) + + def swap( + self, + pair_id: HexStr, + sell_token: EthereumToken, + buy_token: EthereumToken, + is_buy: bool, + amount: Decimal, + data: HexStr, + block: EVMBlock, + overwrites: TStateOverwrites = None, + ) -> tuple[Trade, dict[str, StateUpdate]]: + args = [ + HexBytes(pair_id), + sell_token.address, + buy_token.address, + int(is_buy), + amount, + HexBytes(data), + ] + res = self.call( + "swap", + args, + block_number=block.id, + timestamp=int(block.ts.timestamp()), + overrides=overwrites, + ) + amount, gas, price = res.return_value[0] + return Trade(amount, gas, Fraction(*price)), res.simulation_result.state_updates + + def get_limits( + self, + pair_id: HexStr, + sell_token: EthereumToken, + buy_token: EthereumToken, + data: HexStr, + block: EVMBlock, + overwrites: TStateOverwrites = None, + ) -> tuple[int, int]: + args = [HexBytes(pair_id), sell_token.address, buy_token.address, HexBytes(data)] + res = self.call( + "getLimits", + args, + block_number=block.id, + timestamp=int(block.ts.timestamp()), + overrides=overwrites, + ) + return res.return_value[0] + + def get_capabilities( + self, pair_id: HexStr, sell_token: EthereumToken, buy_token: EthereumToken + ) -> set[Capability]: + args = [HexBytes(pair_id), sell_token.address, buy_token.address] + res = self.call("getCapabilities", args, block_number=1) + return set(map(Capability, res.return_value[0])) + + def min_gas_usage(self) -> int: + res = self.call("minGasUsage", [], block_number=1) + return res.return_value[0] \ No newline at end of file diff --git a/tycho_simulation_py/python/tycho_simulation_py/evm/decoders.py b/tycho_simulation_py/python/tycho_simulation_py/evm/decoders.py index 1660ef9f..dc0674c8 100644 --- a/tycho_simulation_py/python/tycho_simulation_py/evm/decoders.py +++ b/tycho_simulation_py/python/tycho_simulation_py/evm/decoders.py @@ -151,6 +151,8 @@ def decode_pool_state( manual_updates = static_attributes.get( "manual_updates", HexBytes("0x00") ) > HexBytes("0x00") + swap_adapter_version = static_attributes.get("swap_adapter_version", 1) + additional_swap_data = static_attributes.get("additional_swap_data", "") if not manual_updates: # trigger pool updates on contract changes for address in component.contract_ids: @@ -166,6 +168,8 @@ def decode_pool_state( trace=self.trace, manual_updates=manual_updates, involved_contracts=set(to_checksum_address(b.hex()) for b in component.contract_ids), + swap_adapter_version=swap_adapter_version, + additional_swap_data=additional_swap_data, **optional_attributes, ) diff --git a/tycho_simulation_py/python/tycho_simulation_py/evm/pool_state.py b/tycho_simulation_py/python/tycho_simulation_py/evm/pool_state.py index ebcb0ae4..34b4a721 100644 --- a/tycho_simulation_py/python/tycho_simulation_py/evm/pool_state.py +++ b/tycho_simulation_py/python/tycho_simulation_py/evm/pool_state.py @@ -14,7 +14,7 @@ from . import token from . import SimulationEngine, AccountInfo, SimulationParameters -from .adapter_contract import AdapterContract +from .adapter_contract import AdapterContract, AdapterContractV2 from .constants import MAX_BALANCE, EXTERNAL_ACCOUNT from ..exceptions import RecoverableSimulationException from ..models import EVMBlock, Capability, Address, EthereumToken @@ -51,6 +51,8 @@ def __init__( trace: bool = False, involved_contracts=None, token_storage_slots=None, + swap_adapter_version=1, + additional_swap_data: HexStr = "", ): self.id_ = id_ """The pools identifier.""" @@ -109,9 +111,14 @@ def __init__( This is later used to compute storage slot for maps. """ + self.additional_swap_data: HexStr = additional_swap_data + self._engine: Optional[SimulationEngine] = None self._set_engine() - self._adapter_contract = AdapterContract(ADAPTER_ADDRESS, self._engine) + if swap_adapter_version == 1: + self._adapter_contract = AdapterContract(ADAPTER_ADDRESS, self._engine) + elif swap_adapter_version == 2: + self._adapter_contract = AdapterContractV2(ADAPTER_ADDRESS, self._engine) self._set_capabilities() self._init_token_storage_slots() if len(self.marginal_prices) == 0: @@ -180,6 +187,7 @@ def _set_marginal_prices(self): t0, t1, [sell_amount], + self.additional_swap_data, block=self.block, overwrites=self._get_overwrites(t0,t1), )[0] @@ -252,6 +260,7 @@ def _get_amount_out( buy_token, False, sell_token.to_onchain_amount(sell_amount), + data=self.additional_swap_data, block=self.block, overwrites=overwrites, ) @@ -379,6 +388,7 @@ def get_sell_amount_limit( cast(HexStr, self.id_), sell_token, buy_token, + data=self.additional_swap_data, block=self.block, overwrites=self._get_overwrites( sell_token, buy_token, max_amount=MAX_BALANCE // 100