diff --git a/.env.example b/.env.example index 1eba3de..67d6f77 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,6 @@ ARBITRUM_NODE_URL='https://arb1.arbitrum.io/rpc' SCROLL_NODE_URL='https://rpc.scroll.io' MODE_NODE_URL='https://mainnet.mode.network' FRAXTAL_NODE_URL='https://rpc.frax.com' +LYRA_NODE_URL='https://rpc.derive.xyz' + +DERIVE_SUBGRAPH_API_KEY='' \ No newline at end of file diff --git a/abi/IHyperdriveMorpho.json b/abi/IHyperdriveMorpho.json new file mode 100644 index 0000000..2ef9254 --- /dev/null +++ b/abi/IHyperdriveMorpho.json @@ -0,0 +1,1737 @@ +[ + { + "type": "function", + "name": "PERMIT_TYPEHASH", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "addLiquidity", + "inputs": [ + { + "name": "_contribution", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_minLpSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "_minApr", "type": "uint256", "internalType": "uint256" }, + { "name": "_maxApr", "type": "uint256", "internalType": "uint256" }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "lpShares", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "adminController", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { "name": "tokenId", "type": "uint256", "internalType": "uint256" }, + { "name": "owner", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "baseToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "batchTransferFrom", + "inputs": [ + { "name": "from", "type": "address", "internalType": "address" }, + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "ids", "type": "uint256[]", "internalType": "uint256[]" }, + { "name": "values", "type": "uint256[]", "internalType": "uint256[]" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "checkpoint", + "inputs": [ + { + "name": "_checkpointTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_maxIterations", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "closeLong", + "inputs": [ + { + "name": "_maturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "_bondAmount", "type": "uint256", "internalType": "uint256" }, + { "name": "_minOutput", "type": "uint256", "internalType": "uint256" }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "proceeds", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "closeShort", + "inputs": [ + { + "name": "_maturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "_bondAmount", "type": "uint256", "internalType": "uint256" }, + { "name": "_minOutput", "type": "uint256", "internalType": "uint256" }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "proceeds", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "collateralToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "collectGovernanceFee", + "inputs": [ + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "proceeds", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "convertToBase", + "inputs": [ + { "name": "_shareAmount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "convertToShares", + "inputs": [ + { "name": "_baseAmount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [{ "name": "", "type": "uint8", "internalType": "uint8" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "domainSeparator", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getCheckpoint", + "inputs": [ + { + "name": "_checkpointTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IHyperdrive.Checkpoint", + "components": [ + { + "name": "weightedSpotPrice", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "lastWeightedSpotPriceUpdateTime", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "vaultSharePrice", + "type": "uint128", + "internalType": "uint128" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getCheckpointExposure", + "inputs": [ + { + "name": "_checkpointTime", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [{ "name": "", "type": "int256", "internalType": "int256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getMarketState", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IHyperdrive.MarketState", + "components": [ + { + "name": "shareReserves", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "bondReserves", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "longExposure", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "longsOutstanding", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "shareAdjustment", + "type": "int128", + "internalType": "int128" + }, + { + "name": "shortsOutstanding", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "longAverageMaturityTime", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "shortAverageMaturityTime", + "type": "uint128", + "internalType": "uint128" + }, + { "name": "isInitialized", "type": "bool", "internalType": "bool" }, + { "name": "isPaused", "type": "bool", "internalType": "bool" }, + { + "name": "zombieBaseProceeds", + "type": "uint112", + "internalType": "uint112" + }, + { + "name": "zombieShareReserves", + "type": "uint128", + "internalType": "uint128" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolConfig", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IHyperdrive.PoolConfig", + "components": [ + { + "name": "baseToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "vaultSharesToken", + "type": "address", + "internalType": "contract IERC20" + }, + { + "name": "linkerFactory", + "type": "address", + "internalType": "address" + }, + { + "name": "linkerCodeHash", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "initialVaultSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minimumShareReserves", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "minimumTransactionAmount", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "circuitBreakerDelta", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "positionDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "checkpointDuration", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "timeStretch", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "governance", + "type": "address", + "internalType": "address" + }, + { + "name": "feeCollector", + "type": "address", + "internalType": "address" + }, + { + "name": "sweepCollector", + "type": "address", + "internalType": "address" + }, + { + "name": "checkpointRewarder", + "type": "address", + "internalType": "address" + }, + { + "name": "fees", + "type": "tuple", + "internalType": "struct IHyperdrive.Fees", + "components": [ + { + "name": "curve", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "flat", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "governanceLP", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "governanceZombie", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getPoolInfo", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IHyperdrive.PoolInfo", + "components": [ + { + "name": "shareReserves", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "shareAdjustment", + "type": "int256", + "internalType": "int256" + }, + { + "name": "zombieBaseProceeds", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "zombieShareReserves", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "bondReserves", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "lpTotalSupply", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "longsOutstanding", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "longAverageMaturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "shortsOutstanding", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "shortAverageMaturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "withdrawalSharesReadyToWithdraw", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "withdrawalSharesProceeds", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "lpSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "longExposure", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUncollectedGovernanceFees", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getWithdrawPool", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct IHyperdrive.WithdrawPool", + "components": [ + { + "name": "readyToWithdraw", + "type": "uint128", + "internalType": "uint128" + }, + { "name": "proceeds", "type": "uint128", "internalType": "uint128" } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "id", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "Id" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { + "name": "_contribution", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "_apr", "type": "uint256", "internalType": "uint256" }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "lpShares", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "irm", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isApprovedForAll", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "spender", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isPauser", + "inputs": [ + { "name": "_account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "kind", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "pure" + }, + { + "type": "function", + "name": "lltv", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "load", + "inputs": [ + { "name": "_slots", "type": "uint256[]", "internalType": "uint256[]" } + ], + "outputs": [ + { "name": "", "type": "bytes32[]", "internalType": "bytes32[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [ + { "name": "tokenId", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonces", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "openLong", + "inputs": [ + { "name": "_amount", "type": "uint256", "internalType": "uint256" }, + { "name": "_minOutput", "type": "uint256", "internalType": "uint256" }, + { + "name": "_minVaultSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { + "name": "maturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "bondProceeds", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "openShort", + "inputs": [ + { "name": "_bondAmount", "type": "uint256", "internalType": "uint256" }, + { "name": "_maxDeposit", "type": "uint256", "internalType": "uint256" }, + { + "name": "_minVaultSharePrice", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { + "name": "maturityTime", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "deposit", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "oracle", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [{ "name": "_status", "type": "bool", "internalType": "bool" }], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "perTokenApprovals", + "inputs": [ + { "name": "tokenId", "type": "uint256", "internalType": "uint256" }, + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "spender", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "permitForAll", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "spender", "type": "address", "internalType": "address" }, + { "name": "_approved", "type": "bool", "internalType": "bool" }, + { "name": "deadline", "type": "uint256", "internalType": "uint256" }, + { "name": "v", "type": "uint8", "internalType": "uint8" }, + { "name": "r", "type": "bytes32", "internalType": "bytes32" }, + { "name": "s", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "redeemWithdrawalShares", + "inputs": [ + { + "name": "_withdrawalShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_minOutputPerShare", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "proceeds", "type": "uint256", "internalType": "uint256" }, + { + "name": "withdrawalSharesRedeemed", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeLiquidity", + "inputs": [ + { "name": "_lpShares", "type": "uint256", "internalType": "uint256" }, + { + "name": "_minOutputPerShare", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "_options", + "type": "tuple", + "internalType": "struct IHyperdrive.Options", + "components": [ + { + "name": "destination", + "type": "address", + "internalType": "address" + }, + { "name": "asBase", "type": "bool", "internalType": "bool" }, + { "name": "extraData", "type": "bytes", "internalType": "bytes" } + ] + } + ], + "outputs": [ + { "name": "proceeds", "type": "uint256", "internalType": "uint256" }, + { + "name": "withdrawalShares", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setApproval", + "inputs": [ + { "name": "tokenID", "type": "uint256", "internalType": "uint256" }, + { "name": "operator", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setApprovalBridge", + "inputs": [ + { "name": "tokenID", "type": "uint256", "internalType": "uint256" }, + { "name": "operator", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" }, + { "name": "caller", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setApprovalForAll", + "inputs": [ + { "name": "operator", "type": "address", "internalType": "address" }, + { "name": "approved", "type": "bool", "internalType": "bool" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setGovernance", + "inputs": [ + { "name": "_who", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setPauser", + "inputs": [ + { "name": "", "type": "address", "internalType": "address" }, + { "name": "", "type": "bool", "internalType": "bool" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "sweep", + "inputs": [ + { + "name": "_target", + "type": "address", + "internalType": "contract IERC20" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "symbol", + "inputs": [ + { "name": "tokenId", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "target0", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "target1", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "target2", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "target3", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "target4", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalShares", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [ + { "name": "tokenId", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { "name": "tokenID", "type": "uint256", "internalType": "uint256" }, + { "name": "from", "type": "address", "internalType": "address" }, + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFromBridge", + "inputs": [ + { "name": "tokenID", "type": "uint256", "internalType": "uint256" }, + { "name": "from", "type": "address", "internalType": "address" }, + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" }, + { "name": "caller", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "vault", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "vaultSharesToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "version", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "pure" + }, + { + "type": "event", + "name": "AddLiquidity", + "inputs": [ + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "lpAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "lpSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ApprovalForAll", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "approved", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CloseLong", + "inputs": [ + { + "name": "trader", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destination", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assetId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "maturityTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "bondAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CloseShort", + "inputs": [ + { + "name": "trader", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destination", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assetId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "maturityTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "basePayment", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "bondAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CollectGovernanceFee", + "inputs": [ + { + "name": "collector", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CreateCheckpoint", + "inputs": [ + { + "name": "checkpointTime", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "checkpointVaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "maturedShorts", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "maturedLongs", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "lpSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialize", + "inputs": [ + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "lpAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "apr", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OpenLong", + "inputs": [ + { + "name": "trader", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assetId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "maturityTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "bondAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OpenShort", + "inputs": [ + { + "name": "trader", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "assetId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "maturityTime", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "baseProceeds", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "bondAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "PauseStatusUpdated", + "inputs": [ + { + "name": "isPaused", + "type": "bool", + "indexed": false, + "internalType": "bool" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RedeemWithdrawalShares", + "inputs": [ + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destination", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "withdrawalShareAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RemoveLiquidity", + "inputs": [ + { + "name": "provider", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destination", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "lpAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "vaultSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "asBase", + "type": "bool", + "indexed": false, + "internalType": "bool" + }, + { + "name": "withdrawalShareAmount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "lpSharePrice", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "extraData", + "type": "bytes", + "indexed": false, + "internalType": "bytes" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Sweep", + "inputs": [ + { + "name": "collector", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "target", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TransferSingle", + "inputs": [ + { + "name": "operator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "id", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { "type": "error", "name": "BatchInputLengthMismatch", "inputs": [] }, + { "type": "error", "name": "BelowMinimumContribution", "inputs": [] }, + { "type": "error", "name": "CircuitBreakerTriggered", "inputs": [] }, + { + "type": "error", + "name": "DecreasedPresentValueWhenAddingLiquidity", + "inputs": [] + }, + { "type": "error", "name": "DistributeExcessIdleFailed", "inputs": [] }, + { "type": "error", "name": "ExpInvalidExponent", "inputs": [] }, + { "type": "error", "name": "ExpiredDeadline", "inputs": [] }, + { "type": "error", "name": "InsufficientBalance", "inputs": [] }, + { "type": "error", "name": "InsufficientLiquidity", "inputs": [] }, + { "type": "error", "name": "InvalidApr", "inputs": [] }, + { "type": "error", "name": "InvalidCheckpointTime", "inputs": [] }, + { "type": "error", "name": "InvalidERC20Bridge", "inputs": [] }, + { "type": "error", "name": "InvalidEffectiveShareReserves", "inputs": [] }, + { "type": "error", "name": "InvalidFeeDestination", "inputs": [] }, + { "type": "error", "name": "InvalidInitialVaultSharePrice", "inputs": [] }, + { "type": "error", "name": "InvalidLPSharePrice", "inputs": [] }, + { "type": "error", "name": "InvalidPresentValue", "inputs": [] }, + { "type": "error", "name": "InvalidSignature", "inputs": [] }, + { "type": "error", "name": "InvalidTimestamp", "inputs": [] }, + { "type": "error", "name": "LnInvalidInput", "inputs": [] }, + { "type": "error", "name": "MinimumSharePrice", "inputs": [] }, + { "type": "error", "name": "MinimumTransactionAmount", "inputs": [] }, + { "type": "error", "name": "NotPayable", "inputs": [] }, + { "type": "error", "name": "OutputLimit", "inputs": [] }, + { "type": "error", "name": "PoolAlreadyInitialized", "inputs": [] }, + { "type": "error", "name": "PoolIsPaused", "inputs": [] }, + { "type": "error", "name": "RestrictedZeroAddress", "inputs": [] }, + { + "type": "error", + "name": "ReturnData", + "inputs": [{ "name": "data", "type": "bytes", "internalType": "bytes" }] + }, + { "type": "error", "name": "SweepFailed", "inputs": [] }, + { "type": "error", "name": "TransferFailed", "inputs": [] }, + { "type": "error", "name": "Unauthorized", "inputs": [] }, + { "type": "error", "name": "UnexpectedSuccess", "inputs": [] }, + { "type": "error", "name": "UnsafeCastToInt128", "inputs": [] }, + { "type": "error", "name": "UnsafeCastToInt256", "inputs": [] }, + { "type": "error", "name": "UnsafeCastToUint112", "inputs": [] }, + { "type": "error", "name": "UnsafeCastToUint128", "inputs": [] }, + { "type": "error", "name": "UnsafeCastToUint256", "inputs": [] }, + { "type": "error", "name": "UnsupportedToken", "inputs": [] }, + { "type": "error", "name": "UpdateLiquidityFailed", "inputs": [] } +] \ No newline at end of file diff --git a/abi/IMorpho.json b/abi/IMorpho.json new file mode 100644 index 0000000..493beca --- /dev/null +++ b/abi/IMorpho.json @@ -0,0 +1,630 @@ +[ + { + "type": "function", + "name": "DOMAIN_SEPARATOR", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "accrueInterest", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "borrow", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "shares", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "receiver", "type": "address", "internalType": "address" } + ], + "outputs": [ + { + "name": "assetsBorrowed", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sharesBorrowed", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "createMarket", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableIrm", + "inputs": [ + { "name": "irm", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "enableLltv", + "inputs": [ + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "extSloads", + "inputs": [ + { "name": "slots", "type": "bytes32[]", "internalType": "bytes32[]" } + ], + "outputs": [ + { "name": "", "type": "bytes32[]", "internalType": "bytes32[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "feeRecipient", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "flashLoan", + "inputs": [ + { "name": "token", "type": "address", "internalType": "address" }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "idToMarketParams", + "inputs": [{ "name": "id", "type": "bytes32", "internalType": "Id" }], + "outputs": [ + { + "name": "", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isAuthorized", + "inputs": [ + { "name": "authorizer", "type": "address", "internalType": "address" }, + { "name": "authorized", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isIrmEnabled", + "inputs": [ + { "name": "irm", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "isLltvEnabled", + "inputs": [ + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "liquidate", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "borrower", "type": "address", "internalType": "address" }, + { + "name": "seizedAssets", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "repaidShares", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [ + { "name": "", "type": "uint256", "internalType": "uint256" }, + { "name": "", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "market", + "inputs": [{ "name": "id", "type": "bytes32", "internalType": "Id" }], + "outputs": [ + { + "name": "m", + "type": "tuple", + "internalType": "struct Market", + "components": [ + { + "name": "totalSupplyAssets", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalSupplyShares", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalBorrowAssets", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "totalBorrowShares", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "lastUpdate", + "type": "uint128", + "internalType": "uint128" + }, + { "name": "fee", "type": "uint128", "internalType": "uint128" } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "nonce", + "inputs": [ + { "name": "authorizer", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "position", + "inputs": [ + { "name": "id", "type": "bytes32", "internalType": "Id" }, + { "name": "user", "type": "address", "internalType": "address" } + ], + "outputs": [ + { + "name": "p", + "type": "tuple", + "internalType": "struct Position", + "components": [ + { + "name": "supplyShares", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "borrowShares", + "type": "uint128", + "internalType": "uint128" + }, + { + "name": "collateral", + "type": "uint128", + "internalType": "uint128" + } + ] + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "repay", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "shares", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [ + { + "name": "assetsRepaid", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "sharesRepaid", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAuthorization", + "inputs": [ + { "name": "authorized", "type": "address", "internalType": "address" }, + { "name": "newIsAuthorized", "type": "bool", "internalType": "bool" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setAuthorizationWithSig", + "inputs": [ + { + "name": "authorization", + "type": "tuple", + "internalType": "struct Authorization", + "components": [ + { + "name": "authorizer", + "type": "address", + "internalType": "address" + }, + { + "name": "authorized", + "type": "address", + "internalType": "address" + }, + { "name": "isAuthorized", "type": "bool", "internalType": "bool" }, + { "name": "nonce", "type": "uint256", "internalType": "uint256" }, + { "name": "deadline", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "name": "signature", + "type": "tuple", + "internalType": "struct Signature", + "components": [ + { "name": "v", "type": "uint8", "internalType": "uint8" }, + { "name": "r", "type": "bytes32", "internalType": "bytes32" }, + { "name": "s", "type": "bytes32", "internalType": "bytes32" } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFee", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "newFee", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFeeRecipient", + "inputs": [ + { + "name": "newFeeRecipient", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setOwner", + "inputs": [ + { "name": "newOwner", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supply", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "shares", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [ + { + "name": "assetsSupplied", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sharesSupplied", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supplyCollateral", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "shares", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "receiver", "type": "address", "internalType": "address" } + ], + "outputs": [ + { + "name": "assetsWithdrawn", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "sharesWithdrawn", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawCollateral", + "inputs": [ + { + "name": "marketParams", + "type": "tuple", + "internalType": "struct MarketParams", + "components": [ + { + "name": "loanToken", + "type": "address", + "internalType": "address" + }, + { + "name": "collateralToken", + "type": "address", + "internalType": "address" + }, + { "name": "oracle", "type": "address", "internalType": "address" }, + { "name": "irm", "type": "address", "internalType": "address" }, + { "name": "lltv", "type": "uint256", "internalType": "uint256" } + ] + }, + { "name": "assets", "type": "uint256", "internalType": "uint256" }, + { "name": "onBehalf", "type": "address", "internalType": "address" }, + { "name": "receiver", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +] \ No newline at end of file diff --git a/abi/hyperdrive_registry.json b/abi/hyperdrive_registry.json new file mode 100644 index 0000000..c1ea11b --- /dev/null +++ b/abi/hyperdrive_registry.json @@ -0,0 +1,555 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EndIndexTooLarge", + "type": "error" + }, + { + "inputs": [], + "name": "InputLengthMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidFactory", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidIndexes", + "type": "error" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "admin", + "type": "address" + }], + "name": "AdminUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "data", + "type": "uint256" + }], + "name": "FactoryInfoUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "instance", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + }], + "name": "InstanceInfoUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_startIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndex", + "type": "uint256" + }], + "name": "getFactoriesInRange", + "outputs": [ + { + "internalType": "address[]", + "name": "factories", + "type": "address[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + }], + "name": "getFactoryAtIndex", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }], + "name": "getFactoryInfo", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }], + "internalType": "struct IHyperdriveRegistry.FactoryInfo", + "name": "info", + "type": "tuple" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }], + "name": "getFactoryInfoWithMetadata", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "kind", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }], + "internalType": "struct IHyperdriveRegistry.FactoryInfoWithMetadata", + "name": "info", + "type": "tuple" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__factories", + "type": "address[]" + }], + "name": "getFactoryInfos", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }], + "internalType": "struct IHyperdriveRegistry.FactoryInfo[]", + "name": "info", + "type": "tuple[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__factories", + "type": "address[]" + }], + "name": "getFactoryInfosWithMetadata", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "kind", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }], + "internalType": "struct IHyperdriveRegistry.FactoryInfoWithMetadata[]", + "name": "info", + "type": "tuple[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_index", + "type": "uint256" + }], + "name": "getInstanceAtIndex", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_instance", + "type": "address" + }], + "name": "getInstanceInfo", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "address", + "name": "factory", + "type": "address" + }], + "internalType": "struct IHyperdriveRegistry.InstanceInfo", + "name": "info", + "type": "tuple" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_instance", + "type": "address" + }], + "name": "getInstanceInfoWithMetadata", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "kind", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }], + "internalType": "struct IHyperdriveRegistry.InstanceInfoWithMetadata", + "name": "info", + "type": "tuple" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__instances", + "type": "address[]" + }], + "name": "getInstanceInfos", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "address", + "name": "factory", + "type": "address" + }], + "internalType": "struct IHyperdriveRegistry.InstanceInfo[]", + "name": "info", + "type": "tuple[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__instances", + "type": "address[]" + }], + "name": "getInstanceInfosWithMetadata", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "data", + "type": "uint256" + }, + { + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "kind", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }], + "internalType": "struct IHyperdriveRegistry.InstanceInfoWithMetadata[]", + "name": "info", + "type": "tuple[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_startIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_endIndex", + "type": "uint256" + }], + "name": "getInstancesInRange", + "outputs": [ + { + "internalType": "address[]", + "name": "instances", + "type": "address[]" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNumberOfFactories", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNumberOfInstances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "kind", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__factories", + "type": "address[]" + }, + { + "internalType": "uint128[]", + "name": "_data", + "type": "uint128[]" + }], + "name": "setFactoryInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "__instances", + "type": "address[]" + }, + { + "internalType": "uint128[]", + "name": "_data", + "type": "uint128[]" + }, + { + "internalType": "address[]", + "name": "__factories", + "type": "address[]" + }], + "name": "setInstanceInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_admin", + "type": "address" + }], + "name": "updateAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + }], + "stateMutability": "view", + "type": "function" + }] \ No newline at end of file diff --git a/constants/chains.py b/constants/chains.py index f07b4bb..7b0c8d3 100644 --- a/constants/chains.py +++ b/constants/chains.py @@ -9,5 +9,5 @@ class Chain(Enum): BLAST = "Blast" SCROLL = "Scroll" MODE = "Mode" - FRAXTAL = "Fraxtal" OPTIMISM = "Optimism" + Lyra = "Lyra" diff --git a/constants/hyperdrive.py b/constants/hyperdrive.py new file mode 100644 index 0000000..efa1f4e --- /dev/null +++ b/constants/hyperdrive.py @@ -0,0 +1,21 @@ +import json +from enum import IntEnum + +HYPERDRIVE_SUSDE_POOL_ADDRESS = "0x05b65FA90AD702e6Fd0C3Bd7c4c9C47BAB2BEa6b" +HYPERDRIVE_SUSDE_POOL_DEPLOYMENT_BLOCK = 20931644 + +HYPERDRIVE_MORPHO_ABI = None +with open("abi/IHyperdriveMorpho.json") as f: + HYPERDRIVE_MORPHO_ABI = json.load(f) + +ERC20_ABI = None +with open("abi/ERC20_abi.json") as f: + ERC20_ABI = json.load(f) + +class HyperdrivePrefix(IntEnum): + r"""The asset ID is used to encode the trade type in a transaction receipt""" + + LP = 0 + LONG = 1 + SHORT = 2 + WITHDRAWAL_SHARE = 3 diff --git a/constants/integration_ids.py b/constants/integration_ids.py index f4e91ab..c1e2e97 100644 --- a/constants/integration_ids.py +++ b/constants/integration_ids.py @@ -75,6 +75,7 @@ class IntegrationID(Enum): # Lyra LYRA_SUSDE_BULL_MAINNET = ("lyra_susde_bull_mainnet", "Lyra sUSDe Bull Vault Mainnet", Token.SUSDE) LYRA_SUSDE_BULL_ARBITRUM = ("lyra_susde_bull_arbitrum", "Lyra sUSDe Bull Vault Arbitrum", Token.SUSDE) + LYRA_SUSDE_EXCHANGE_DEPOSIT= ("lyra_susde_exchange_deposit", "Lyra sUSDe Exchange Deposits", Token.SUSDE) # Velodrome VELODROME_MODE_USDE = ('velodrome_mode_usde', 'Velodrome Mode USDe', Token.USDE) VELODROME_MODE_SUSDE = ('velodrome_mode_susde', 'Velodrome Mode sUSDe', Token.SUSDE) @@ -136,6 +137,9 @@ class IntegrationID(Enum): # Inverse Finance FiRM FIRM_SUSDE = ('firm_susde', 'Inverse Finance FiRM sUSDe', Token.SUSDE) + # Hyperdrive + HYPERDRIVE_SUSDE = ('hyperdrive_susde', 'ElementDAO 182 Day sUSDe Hyperdrive', Token.SUSDE) + def __init__(self, column_name: str, description: str, token: Token = Token.USDE): self.column_name = column_name self.description = description diff --git a/constants/lyra.py b/constants/lyra.py index a06e70a..8d298e7 100644 --- a/constants/lyra.py +++ b/constants/lyra.py @@ -5,48 +5,62 @@ from web3 import Web3 from constants.chains import Chain from constants.integration_ids import IntegrationID +from enum import Enum with open("abi/ERC20_abi.json") as f: erc20_abi = json.load(f) +class DetailType(Enum): + Vault = "Vault" + Exchange = "Exchange" + class LyraVaultDetails(TypedDict): + detail_type: DetailType start: int chain: str - integration_token: Contract - bridge: Contract - vault_token: Contract page_size: int + integration_token: Contract | None + bridge: Contract| None + vault_token: Contract| None # NOTE: does not handle cross-chain transfers of vault tokens LYRA_CONTRACTS_AND_START_BY_TOKEN: Dict[IntegrationID, LyraVaultDetails] = { IntegrationID.LYRA_SUSDE_BULL_MAINNET: LyraVaultDetails( + detail_type=DetailType.Vault, start=20211445, chain=Chain.ETHEREUM, - integration_token=W3_BY_CHAIN[Chain.ETHEREUM].eth.contract( + integration_token=W3_BY_CHAIN[Chain.ETHEREUM]["w3"].eth.contract( address=Web3.to_checksum_address("0x9d39a5de30e57443bff2a8307a4256c8797a3497"), abi=erc20_abi ), # sUSDe - bridge=W3_BY_CHAIN[Chain.ETHEREUM].eth.contract( + bridge=W3_BY_CHAIN[Chain.ETHEREUM]["w3"].eth.contract( address=Web3.to_checksum_address("0xE3E96892D30E0ee1a8131BAf87c891201F7137bf"), abi=erc20_abi ), - vault_token=W3_BY_CHAIN[Chain.ETHEREUM].eth.contract( + vault_token=W3_BY_CHAIN[Chain.ETHEREUM]["w3"].eth.contract( address=Web3.to_checksum_address("0x1d080C689B930f9dEa69CB3B4Bc6b8c213DFC2ad"), abi=erc20_abi ), page_size=5000, ), IntegrationID.LYRA_SUSDE_BULL_ARBITRUM: LyraVaultDetails( + detail_type=DetailType.Vault, start=227626020, chain=Chain.ARBITRUM, - integration_token=W3_BY_CHAIN[Chain.ARBITRUM].eth.contract( + integration_token=W3_BY_CHAIN[Chain.ARBITRUM]["w3"].eth.contract( address=Web3.to_checksum_address("0x211cc4dd073734da055fbf44a2b4667d5e5fe5d2"), abi=erc20_abi ), # sUSDe - bridge=W3_BY_CHAIN[Chain.ARBITRUM].eth.contract( + bridge=W3_BY_CHAIN[Chain.ARBITRUM]["w3"].eth.contract( address=Web3.to_checksum_address("0x3c143EA5eBaB50ad6D2B2d14FA719234d1d38F1b"), abi=erc20_abi ), - vault_token=W3_BY_CHAIN[Chain.ARBITRUM].eth.contract( + vault_token=W3_BY_CHAIN[Chain.ARBITRUM]["w3"].eth.contract( address=Web3.to_checksum_address("0x81494d722DDceDbA31ac40F28daFa66b207f232B"), abi=erc20_abi ), page_size=20000, ), + IntegrationID.LYRA_SUSDE_EXCHANGE_DEPOSIT: LyraVaultDetails( + detail_type=DetailType.Exchange, + start=11481048, + chain=Chain.Lyra, + page_size=20000, + ) } diff --git a/integrations/hyperdrive.py b/integrations/hyperdrive.py new file mode 100644 index 0000000..268ac26 --- /dev/null +++ b/integrations/hyperdrive.py @@ -0,0 +1,85 @@ +from decimal import Decimal +from constants.chains import Chain +from models.integration import Integration +from constants.integration_ids import IntegrationID +from constants.hyperdrive import HYPERDRIVE_SUSDE_POOL_ADDRESS, HYPERDRIVE_SUSDE_POOL_DEPLOYMENT_BLOCK, HYPERDRIVE_MORPHO_ABI +from utils.hyperdrive import get_hyperdrive_participants, get_pool_details, get_pool_positions +from utils.web3_utils import w3 + +class Hyperdrive(Integration): + def __init__(self): + super().__init__( + IntegrationID.HYPERDRIVE_SUSDE, + HYPERDRIVE_SUSDE_POOL_DEPLOYMENT_BLOCK, + Chain.ETHEREUM, + None, + 20, + 1, + None, + None, + ) + self.pool_ids = None + self.pool_users = None + self.pool_positions = None + + def update_participants(self): + self.pool_users, self.pool_ids = get_hyperdrive_participants( + pool=HYPERDRIVE_SUSDE_POOL_ADDRESS, + start_block=HYPERDRIVE_SUSDE_POOL_DEPLOYMENT_BLOCK, + ) + + def get_participants(self): + self.update_participants() + return self.pool_users + + def get_balance(self, user: str, block: int) -> float: + # update hyperdrive participants + if self.pool_positions is None: + if self.pool_users is None: + self.update_participants() + # get pool positions + pool_contract = w3.eth.contract(address=w3.to_checksum_address(HYPERDRIVE_SUSDE_POOL_ADDRESS), abi=HYPERDRIVE_MORPHO_ABI) + _, lp_rewardable_tvl, short_rewardable_tvl = get_pool_details(pool_contract) + self.pool_positions = get_pool_positions( + pool_contract=pool_contract, + pool_users=self.pool_users, + pool_ids=self.pool_ids, + lp_rewardable_tvl=lp_rewardable_tvl, + short_rewardable_tvl=short_rewardable_tvl, + block=block, + ) + # get the user's balance + rewardable_tvl = sum(position[5] for position in self.pool_positions if position[0] == user) + return rewardable_tvl / 1e18 + + def test_hyperdrive(self): + self.update_participants() + pool_contract = w3.eth.contract(address=w3.to_checksum_address(HYPERDRIVE_SUSDE_POOL_ADDRESS), abi=HYPERDRIVE_MORPHO_ABI) + vault_shares_balance, lp_rewardable_tvl, short_rewardable_tvl = get_pool_details(pool_contract) + pool_positions = get_pool_positions( + pool_contract=pool_contract, + pool_users=self.pool_users, + pool_ids=self.pool_ids, + lp_rewardable_tvl=lp_rewardable_tvl, + short_rewardable_tvl=short_rewardable_tvl, + ) + + # Make sure rewards add up to rewardable TVL + combined_prefixes = [(0, 3), (2,)] # Treat prefixes 0 and 3 together, 2 separately + for prefixes in combined_prefixes: + combined_shares = sum(position[5] for position in pool_positions if position[2] in prefixes) + combined_rewardable = lp_rewardable_tvl if prefixes[0] == 0 else short_rewardable_tvl + if combined_shares == combined_rewardable: + print(f"for prefixes={prefixes}, check combined_shares == combined_rewardable ({combined_shares} == {combined_rewardable}) ✅") + else: + print(f"for prefixes={prefixes}, check combined_shares == combined_rewardable ({combined_shares} != {combined_rewardable}) ❌") + + total_rewardable = Decimal(sum(position[5] for position in pool_positions)) + if vault_shares_balance == total_rewardable: + print(f"vault_shares_balance == total_rewardable ({vault_shares_balance} == {total_rewardable}) ✅") + else: + print(f"vault_shares_balance != total_rewardable ({vault_shares_balance} != {total_rewardable}) ❌") + +if __name__ == "__main__": + hyperdrive = Hyperdrive() + hyperdrive.test_hyperdrive() diff --git a/integrations/lyra_susde_bull.py b/integrations/lyra_susde_bull.py index 1fc3cc3..1b994aa 100644 --- a/integrations/lyra_susde_bull.py +++ b/integrations/lyra_susde_bull.py @@ -3,8 +3,8 @@ from constants.integration_ids import IntegrationID from models.integration import Integration -from utils.lyra import get_vault_users, get_effective_balance -from constants.lyra import LYRA_CONTRACTS_AND_START_BY_TOKEN, LyraVaultDetails +from utils.lyra import get_vault_users, get_effective_balance, get_exchange_users, get_exchange_balance +from constants.lyra import LYRA_CONTRACTS_AND_START_BY_TOKEN, LyraVaultDetails, DetailType class LyraIntegration(Integration): @@ -25,29 +25,37 @@ def __init__(self, integration_id: IntegrationID): ) def get_balance(self, user: str, block: int) -> float: - return get_effective_balance( - user, - block, - self.vault_data["integration_token"], - self.vault_data["bridge"], - self.vault_data["vault_token"], - ) + if self.vault_data["detail_type"] == DetailType.Vault: + return get_effective_balance( + user, + block, + self.vault_data["integration_token"], + self.vault_data["bridge"], + self.vault_data["vault_token"], + W3_BY_CHAIN[example_integration.chain]["w3"].eth.get_block(block)['timestamp'] + ) + + else: + return get_exchange_balance(user, block) def get_participants(self) -> list: logging.info(f"[{self.integration_id.get_description()}] Getting participants...") - self.participants = get_vault_users( - self.start_block, - self.vault_data["page_size"], - self.vault_data["vault_token"], - self.chain, - ) + if self.vault_data["detail_type"] == DetailType.Vault: + self.participants = get_vault_users( + self.start_block, + self.vault_data["page_size"], + self.vault_data["vault_token"], + self.chain, + ) + else: + self.participants = get_exchange_users() return self.participants if __name__ == "__main__": example_integration = LyraIntegration(IntegrationID.LYRA_SUSDE_BULL_MAINNET) - current_block = W3_BY_CHAIN[example_integration.chain].eth.get_block_number() + current_block = W3_BY_CHAIN[example_integration.chain]["w3"].eth.get_block_number() print("Found Lyra Participants:") print(example_integration.get_participants()) diff --git a/utils/hyperdrive.py b/utils/hyperdrive.py new file mode 100644 index 0000000..314296d --- /dev/null +++ b/utils/hyperdrive.py @@ -0,0 +1,151 @@ +import itertools +from decimal import Decimal, getcontext + +from dotenv import load_dotenv + +from constants.hyperdrive import ERC20_ABI,HYPERDRIVE_MORPHO_ABI,HyperdrivePrefix +from utils.web3_utils import fetch_events_logs_with_retry,w3 + +load_dotenv() + +PAGE_SIZE = 1900 +getcontext().prec = 100 # Set precision for Decimal calculations + +def get_first_contract_block(contract_address): + # do binary search up to latest block + latest_block = w3.eth.get_block_number() + earliest_block = 0 + while earliest_block < latest_block: + mid_block = (earliest_block + latest_block) // 2 + attempt_to_get_code = w3.eth.get_code(account=contract_address,block_identifier=mid_block) + if attempt_to_get_code == b'': + # Contract not yet deployed, continue searching in the later blocks + earliest_block = mid_block + 1 + else: + # Contract deployed, continue searching in the earlier blocks + latest_block = mid_block - 1 + # At this point, earliest_block and latest_block should be the same, + # and it represents the block where we can first retrieve the contract code. + assert earliest_block >= latest_block, f"something fucked up since {earliest_block=} isn't greater than or equal to {latest_block=}" + return earliest_block + +def get_hyperdrive_participants(pool, start_block = None): + target_block = w3.eth.get_block_number() + all_users = set() + all_ids = set() + start_block = start_block or get_first_contract_block(pool) + assert all_users is not None, "error: all_users is None" + assert all_ids is not None, "error: all_ids is None" + assert start_block is not None, "error: start_block is None" + contract = w3.eth.contract(address=pool, abi=HYPERDRIVE_MORPHO_ABI) + + current_block = start_block + while current_block < target_block: + to_block = min(current_block + PAGE_SIZE, target_block) + transfers = fetch_events_logs_with_retry( + label=f"Hyperdrive users {pool}", + contract_event=contract.events.TransferSingle(), + from_block=current_block, + to_block=to_block, + delay=0, + ) + for transfer in transfers: + all_users.add(transfer["args"]["to"]) + all_ids.add(transfer["args"]["id"]) + current_block = to_block + + return all_users, all_ids + +def decode_asset_id(asset_id: int) -> tuple[int, int]: + r"""Decodes a transaction asset ID into its constituent parts of an identifier, data, and a timestamp. + + First calculate the prefix mask by left-shifting 1 by 248 bits and subtracting 1 from the result. + This gives us a bit-mask with 248 bits set to 1 and the rest set to 0. + Then apply this mask to the input ID using the bitwise-and operator `&` to extract + the lower 248 bits as the timestamp. + + The prefix is a unique asset ID which denotes the following trade types: + LP = 0 + LONG = 1 + SHORT = 2 + WITHDRAWAL_SHARE = 3 + + Arguments + --------- + asset_id: int + Encoded ID from a transaction. It is a concatenation, [identifier: 8 bits][timestamp: 248 bits] + + Returns + ------- + tuple[int, int] + identifier, timestamp + """ + prefix_mask = (1 << 248) - 1 + prefix = asset_id >> 248 # shr 248 bits + timestamp = asset_id & prefix_mask # apply the prefix mask + return prefix, timestamp + +def get_pool_details(pool_contract): + config_values = pool_contract.functions.getPoolConfig().call() + config_outputs = pool_contract.functions.getPoolConfig().abi['outputs'][0]['components'] + config_keys = [i['name'] for i in config_outputs if 'name' in i] + config = dict(zip(config_keys, config_values)) + for k,v in config.items(): + print(f"{k}: {v}") + info_values = pool_contract.functions.getPoolInfo().call() + info_outputs = pool_contract.functions.getPoolInfo().abi['outputs'][0]['components'] + info_keys = [i['name'] for i in info_outputs if 'name' in i] + info = dict(zip(info_keys, info_values)) + + # query pool holdings + vault_shares_balance = None + if config["vaultSharesToken"] != "0x0000000000000000000000000000000000000000": + vault_shares_contract = w3.eth.contract(address=config["vaultSharesToken"], abi=ERC20_ABI) + vault_shares_balance = vault_shares_contract.functions.balanceOf(pool_contract.address).call() + short_rewardable_tvl = info['shortsOutstanding'] + lp_rewardable_tvl = vault_shares_balance - short_rewardable_tvl + + return vault_shares_balance, lp_rewardable_tvl, short_rewardable_tvl + +def get_pool_positions(pool_contract, pool_users, pool_ids, lp_rewardable_tvl, short_rewardable_tvl, block = None): + pool_positions = [] + combined_prefixes = [(0, 3), (2,)] # Treat prefixes 0 and 3 together, 2 separately + bal_by_prefix = {0: Decimal(0), 1: Decimal(0), 2: Decimal(0), 3: Decimal(0)} + + # First pass: collect balances + for user, id in itertools.product(pool_users, pool_ids): + trade_type, prefix, timestamp = get_trade_details(int(id)) + bal = pool_contract.functions.balanceOf(int(id), user).call(block_identifier=block or "latest") + if bal > Decimal(1): + pool_positions.append([user, trade_type, prefix, timestamp, bal, Decimal(0)]) + bal_by_prefix[prefix] += bal + + # Second pass: calculate shares (prefix 1 (longs) get nothing, so we skip it) + for position in pool_positions: + prefix = position[2] + if prefix in [0, 3]: # assign rewards for LPs and withdrawal shares + combined_lp_balance = bal_by_prefix[0] + bal_by_prefix[3] # combine LP and withdrawal share balance + if combined_lp_balance != Decimal(0): + share_of_rewardable = position[4] / combined_lp_balance + position[5] = (lp_rewardable_tvl * share_of_rewardable).quantize(Decimal('0')) + elif prefix == 2: # assign rewards for shorts + if bal_by_prefix[2] != Decimal(0): + share_of_rewardable = position[4] / bal_by_prefix[2] + position[5] = (short_rewardable_tvl * share_of_rewardable).quantize(Decimal('0')) + + # Correction step to fix rounding errors + for prefixes in combined_prefixes: + combined_shares = sum(position[5] for position in pool_positions if position[2] in prefixes) + combined_rewardable = lp_rewardable_tvl if prefixes[0] == 0 else short_rewardable_tvl + if combined_shares != combined_rewardable: + diff = combined_rewardable - combined_shares + # Find the position with the largest share among the combined prefixes + max_position = max((p for p in pool_positions if p[2] in prefixes), key=lambda x: x[5]) + max_position[5] += diff + + return pool_positions + +def get_trade_details(asset_id: int) -> tuple[str, int, int]: + prefix, timestamp = decode_asset_id(asset_id) + trade_type = HyperdrivePrefix(prefix).name + return trade_type, prefix, timestamp diff --git a/utils/lyra.py b/utils/lyra.py index 70e0884..851a915 100644 --- a/utils/lyra.py +++ b/utils/lyra.py @@ -2,24 +2,143 @@ W3_BY_CHAIN, fetch_events_logs_with_retry, ) +import os +import requests from web3.contract import Contract from utils.web3_utils import call_with_retry from constants.chains import Chain +from web3 import Web3 +url = 'https://app.sentio.xyz/api/v1/graphql/derive/v2_subgraph' +SUSDE_VAULT_ADDRESS = "0x0b4eD379da8eF4FCF06F697c5782CA7b4c3E505E" -def get_effective_balance(user: str, block: int, integration_token: Contract, bridge: Contract, vault_token: Contract): +user_balance_query = ''' +{ + accounts(where: {or: [{id: "{user}"}, {owner: "{user}"}]}, block: {number: {block}}) { + id + owner + subaccounts{ + subaccountId + balances(where:{asset: "0x375804cdcf0d534fdd2657584a7c4ff5ab14a2bb000000000000000000000000"}){ + balance + } + } + depositedSubaccounts{ + subaccountId + balances(where:{asset: "0x375804cdcf0d534fdd2657584a7c4ff5ab14a2bb000000000000000000000000"}){ + balance + } + } + } +} +''' + + +def get_exchange_balance(user: str, block: int) -> int: + user = user.lower() + # Replace the user and block placeholders in the query + user_balance_query_filled = user_balance_query.replace("{user}", user).replace("{block}", str(block)) + + headers = { + 'Content-Type': 'application/json', + 'api-key': os.getenv("DERIVE_SUBGRAPH_API_KEY") + } + print(user_balance_query_filled) + + # Send the POST request + response = requests.post(url, json={'query': user_balance_query_filled}, headers=headers) + + total_balance = 0 + if response.status_code == 200: + response_json = response.json() + accounts = response_json['data']['accounts'] + for account in accounts: + for subaccount in account['subaccounts']: + for balance in subaccount['balances']: + total_balance += float(balance['balance']) + for subaccount in account['depositedSubaccounts']: + for balance in subaccount['balances']: + total_balance += float(balance['balance']) + else: + print(f"Query failed with status code {response.status_code}: {response.text}") + return total_balance + +def get_effective_balance(user: str, block: int, integration_token: Contract, bridge: Contract, vault_token: Contract, timestamp): """ Since vault tokens can be transferred, calculates the portion of totalSupply() of the vault held by user. User's effective ethena integration token balance = (vault.balanceOf(user) / vault.totalSupply()) * total bridge balance """ - total_bridge_balance = call_with_retry(integration_token.functions.balanceOf(bridge.address), block) - total_vault_token_balance = call_with_retry(vault_token.functions.totalSupply(), block) user_vault_token_balance = call_with_retry(vault_token.functions.balanceOf(user), block) - return (user_vault_token_balance / total_vault_token_balance) * total_bridge_balance + headers = { + 'Content-Type': 'application/json' + } + + # Send the POST request + response = requests.post("https://api.lyra.finance/public/get_vault_share", json={'from_timestamp_sec': 0, 'to_timestamp_sec': timestamp, 'vault_name': 'sUSDePrincipal Protected Bull Call Spread', 'page_size': 1}, headers=headers) + try: + response_json = response.json() + vault_price = float(response_json['result']['vault_shares'][0]["base_value"]) + except: + print("Failed to get vault price, using default") + vault_price = float(1) + + return user_vault_token_balance * vault_price /1e18 + + +all_users_query = ''' +{ + subAccountBalances(where: {asset: "0x375804cdcf0d534fdd2657584a7c4ff5ab14a2bb000000000000000000000000"}) { + subaccount { + id + owner { + id + owner + } + matchingOwner { + id + owner + } + } + } +} +''' + +def get_exchange_users() -> set: + headers = { + 'Content-Type': 'application/json', + 'api-key': os.getenv("DERIVE_SUBGRAPH_API_KEY") + } + + response = requests.post(url, json={'query': all_users_query}, headers=headers) + + users = set() + if response.status_code == 200: + response_json = response.json() + balances = response_json['data']['subAccountBalances'] + for balance in balances: + if balance['subaccount']['matchingOwner'] is not None: + if balance['subaccount']['matchingOwner']['owner'] is not None: + users.add(Web3.to_checksum_address(balance['subaccount']['matchingOwner']['owner'])) + else: + users.add(Web3.to_checksum_address(balance['subaccount']['matchingOwner']['id'])) + else: + if balance['subaccount']['owner']['owner'] is not None: + users.add(Web3.to_checksum_address(balance['subaccount']['owner']['owner'])) + else: + users.add(Web3.to_checksum_address(balance['subaccount']['owner']['id'])) + else: + print(f"Query failed with status code {response.status_code}: {response.text}") + + try: + users.remove(SUSDE_VAULT_ADDRESS) # Ignore the sUSDe vault which is accounted for separately + except: + pass + + return users def get_vault_users(start_block: int, page_size: int, vault_token: Contract, chain: Chain): """ @@ -29,7 +148,7 @@ def get_vault_users(start_block: int, page_size: int, vault_token: Contract, cha """ all_users = set() - target_block = W3_BY_CHAIN[chain].eth.get_block_number() + target_block = W3_BY_CHAIN[chain]["w3"].eth.get_block_number() while start_block < target_block: to_block = min(start_block + page_size, target_block) diff --git a/utils/web3_utils.py b/utils/web3_utils.py index 019049a..f7cc40f 100644 --- a/utils/web3_utils.py +++ b/utils/web3_utils.py @@ -27,6 +27,8 @@ w3_mode = Web3(Web3.HTTPProvider(MODE_NODE_URL)) FRAXTAL_NODE_URL = os.getenv("FRAXTAL_NODE_URL") w3_fraxtal = Web3(Web3.HTTPProvider(FRAXTAL_NODE_URL)) +LYRA_NODE_URL = os.getenv("LYRA_NODE_URL") +w3_lyra = Web3(Web3.HTTPProvider(LYRA_NODE_URL)) W3_BY_CHAIN = { Chain.ETHEREUM: { @@ -50,6 +52,9 @@ Chain.FRAXTAL: { "w3": w3_fraxtal, }, + Chain.Lyra: { + "w3": w3_lyra, + }, }