diff --git a/src/abi/angle-transmuter/MorphoVault.json b/src/abi/angle-transmuter/MorphoVault.json new file mode 100644 index 000000000..5a4db57fd --- /dev/null +++ b/src/abi/angle-transmuter/MorphoVault.json @@ -0,0 +1,2506 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "morpho", + "type": "address" + }, + { + "internalType": "uint256", + "name": "initialTimelock", + "type": "uint256" + }, + { + "internalType": "address", + "name": "_asset", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "AboveMaxTimelock", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "AllCapsReached", + "type": "error" + }, + { + "inputs": [], + "name": "AlreadyPending", + "type": "error" + }, + { + "inputs": [], + "name": "AlreadySet", + "type": "error" + }, + { + "inputs": [], + "name": "BelowMinTimelock", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "DuplicateMarket", + "type": "error" + }, + { + "inputs": [], + "name": "ECDSAInvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ECDSAInvalidSignatureLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "ECDSAInvalidSignatureS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "ERC2612ExpiredSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC2612InvalidSigner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxDeposit", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxMint", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxRedeem", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "ERC4626ExceededMaxWithdraw", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "InconsistentAsset", + "type": "error" + }, + { + "inputs": [], + "name": "InconsistentReallocation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "currentNonce", + "type": "uint256" + } + ], + "name": "InvalidAccountNonce", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "InvalidMarketRemovalNonZeroCap", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "InvalidMarketRemovalNonZeroSupply", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "InvalidMarketRemovalTimelockNotElapsed", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidShortString", + "type": "error" + }, + { + "inputs": [], + "name": "MarketNotCreated", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "MarketNotEnabled", + "type": "error" + }, + { + "inputs": [], + "name": "MathOverflowedMulDiv", + "type": "error" + }, + { + "inputs": [], + "name": "MaxFeeExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "MaxQueueLengthExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "NoPendingValue", + "type": "error" + }, + { + "inputs": [], + "name": "NonZeroCap", + "type": "error" + }, + { + "inputs": [], + "name": "NotAllocatorRole", + "type": "error" + }, + { + "inputs": [], + "name": "NotCuratorNorGuardianRole", + "type": "error" + }, + { + "inputs": [], + "name": "NotCuratorRole", + "type": "error" + }, + { + "inputs": [], + "name": "NotEnoughLiquidity", + "type": "error" + }, + { + "inputs": [], + "name": "NotGuardianRole", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "PendingCap", + "type": "error" + }, + { + "inputs": [], + "name": "PendingRemoval", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "bits", + "type": "uint8" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "SafeCastOverflowedUintDowncast", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "str", + "type": "string" + } + ], + "name": "StringTooLong", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "SupplyCapExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "TimelockNotElapsed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "UnauthorizedMarket", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroFeeRecipient", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTotalAssets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "feeShares", + "type": "uint256" + } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferStarted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "suppliedAssets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "suppliedShares", + "type": "uint256" + } + ], + "name": "ReallocateSupply", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "withdrawnAssets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "withdrawnShares", + "type": "uint256" + } + ], + "name": "ReallocateWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "RevokePendingCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RevokePendingGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "RevokePendingMarketRemoval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + } + ], + "name": "RevokePendingTimelock", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "SetCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newCurator", + "type": "address" + } + ], + "name": "SetCurator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newFee", + "type": "uint256" + } + ], + "name": "SetFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newFeeRecipient", + "type": "address" + } + ], + "name": "SetFeeRecipient", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "guardian", + "type": "address" + } + ], + "name": "SetGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "allocator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "isAllocator", + "type": "bool" + } + ], + "name": "SetIsAllocator", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newSkimRecipient", + "type": "address" + } + ], + "name": "SetSkimRecipient", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "Id[]", + "name": "newSupplyQueue", + "type": "bytes32[]" + } + ], + "name": "SetSupplyQueue", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "newTimelock", + "type": "uint256" + } + ], + "name": "SetTimelock", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": false, + "internalType": "Id[]", + "name": "newWithdrawQueue", + "type": "bytes32[]" + } + ], + "name": "SetWithdrawQueue", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Skim", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "cap", + "type": "uint256" + } + ], + "name": "SubmitCap", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "newGuardian", + "type": "address" + } + ], + "name": "SubmitGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "SubmitMarketRemoval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "newTimelock", + "type": "uint256" + } + ], + "name": "SubmitTimelock", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "updatedTotalAssets", + "type": "uint256" + } + ], + "name": "UpdateLastTotalAssets", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "DECIMALS_OFFSET", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MORPHO", + "outputs": [ + { + "internalType": "contract IMorpho", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "loanToken", + "type": "address" + }, + { + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "address", + "name": "irm", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lltv", + "type": "uint256" + } + ], + "internalType": "struct MarketParams", + "name": "marketParams", + "type": "tuple" + } + ], + "name": "acceptCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "acceptGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "acceptOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "acceptTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "asset", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "", + "type": "bytes32" + } + ], + "name": "config", + "outputs": [ + { + "internalType": "uint184", + "name": "cap", + "type": "uint184" + }, + { + "internalType": "bool", + "name": "enabled", + "type": "bool" + }, + { + "internalType": "uint64", + "name": "removableAt", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "convertToAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "convertToShares", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "curator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "deposit", + "outputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "fee", + "outputs": [ + { + "internalType": "uint96", + "name": "", + "type": "uint96" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "feeRecipient", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "guardian", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isAllocator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastTotalAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "maxMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "maxRedeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "maxWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "mint", + "outputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "", + "type": "bytes32" + } + ], + "name": "pendingCap", + "outputs": [ + { + "internalType": "uint192", + "name": "value", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "validAt", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingGuardian", + "outputs": [ + { + "internalType": "address", + "name": "value", + "type": "address" + }, + { + "internalType": "uint64", + "name": "validAt", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingOwner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pendingTimelock", + "outputs": [ + { + "internalType": "uint192", + "name": "value", + "type": "uint192" + }, + { + "internalType": "uint64", + "name": "validAt", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "previewDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "previewMint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "name": "previewRedeem", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "name": "previewWithdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "address", + "name": "loanToken", + "type": "address" + }, + { + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "address", + "name": "irm", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lltv", + "type": "uint256" + } + ], + "internalType": "struct MarketParams", + "name": "marketParams", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "internalType": "struct MarketAllocation[]", + "name": "allocations", + "type": "tuple[]" + } + ], + "name": "reallocate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "redeem", + "outputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "revokePendingCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revokePendingGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Id", + "name": "id", + "type": "bytes32" + } + ], + "name": "revokePendingMarketRemoval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "revokePendingTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newCurator", + "type": "address" + } + ], + "name": "setCurator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newFee", + "type": "uint256" + } + ], + "name": "setFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newFeeRecipient", + "type": "address" + } + ], + "name": "setFeeRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAllocator", + "type": "address" + }, + { + "internalType": "bool", + "name": "newIsAllocator", + "type": "bool" + } + ], + "name": "setIsAllocator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newSkimRecipient", + "type": "address" + } + ], + "name": "setSkimRecipient", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "Id[]", + "name": "newSupplyQueue", + "type": "bytes32[]" + } + ], + "name": "setSupplyQueue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "skim", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "skimRecipient", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "loanToken", + "type": "address" + }, + { + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "address", + "name": "irm", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lltv", + "type": "uint256" + } + ], + "internalType": "struct MarketParams", + "name": "marketParams", + "type": "tuple" + }, + { + "internalType": "uint256", + "name": "newSupplyCap", + "type": "uint256" + } + ], + "name": "submitCap", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newGuardian", + "type": "address" + } + ], + "name": "submitGuardian", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "loanToken", + "type": "address" + }, + { + "internalType": "address", + "name": "collateralToken", + "type": "address" + }, + { + "internalType": "address", + "name": "oracle", + "type": "address" + }, + { + "internalType": "address", + "name": "irm", + "type": "address" + }, + { + "internalType": "uint256", + "name": "lltv", + "type": "uint256" + } + ], + "internalType": "struct MarketParams", + "name": "marketParams", + "type": "tuple" + } + ], + "name": "submitMarketRemoval", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "newTimelock", + "type": "uint256" + } + ], + "name": "submitTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "supplyQueue", + "outputs": [ + { + "internalType": "Id", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "supplyQueueLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "timelock", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAssets", + "outputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "indexes", + "type": "uint256[]" + } + ], + "name": "updateWithdrawQueue", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "assets", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "withdraw", + "outputs": [ + { + "internalType": "uint256", + "name": "shares", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "withdrawQueue", + "outputs": [ + { + "internalType": "Id", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawQueueLength", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts b/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts index 0723b8c54..f84a4c9e4 100644 --- a/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts +++ b/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts @@ -11,6 +11,8 @@ import { import { Network, ContractMethod, SwapSide } from '../../constants'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; import { generateConfig } from '../../config'; +import { Collateral } from './angle-transmuter-integration.test'; +import { BI_POWS } from '../../bigint-constants'; function testForNetwork( network: Network, @@ -20,6 +22,7 @@ function testForNetwork( tokenAAmount: string, tokenBAmount: string, nativeTokenAmount: string, + isKYC: boolean, ) { const provider = new StaticJsonRpcProvider( generateConfig(network).privateHttpProvider, @@ -52,19 +55,21 @@ function testForNetwork( provider, ); }); - it(`${tokenBSymbol} -> ${tokenASymbol}`, async () => { - await testE2E( - tokens[tokenBSymbol], - tokens[tokenASymbol], - holders[tokenBSymbol], - side === SwapSide.SELL ? tokenBAmount : tokenAAmount, - side, - dexKey, - contractMethod, - network, - provider, - ); - }); + if (!isKYC) { + it(`${tokenBSymbol} -> ${tokenASymbol}`, async () => { + await testE2E( + tokens[tokenBSymbol], + tokens[tokenASymbol], + holders[tokenBSymbol], + side === SwapSide.SELL ? tokenBAmount : tokenAAmount, + side, + dexKey, + contractMethod, + network, + provider, + ); + }); + } }); }); }), @@ -78,59 +83,42 @@ describe('AngleTransmuter E2E', () => { describe('Mainnet', () => { const network = Network.MAINNET; - describe('EUROC', () => { - const tokenASymbol: string = 'EUROC'; - const tokenBSymbol: string = 'EURA'; + const tokens = Tokens[network]; + const stables = [tokens.EURA, tokens.USDA]; - const tokenAAmount: string = '1000000'; - const tokenBAmount: string = '1000000000000000000'; - const nativeTokenAmount = '1000000000000000000'; + const collaterals: Collateral = { + USDA: [tokens.USDC, tokens.steakUSDC, tokens.bIB01], + EURA: [tokens.EUROC, tokens.bC3M, tokens.bERNX], + }; - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - ); - }); - describe('BC3M', () => { - const tokenASymbol: string = 'bC3M'; - const tokenBSymbol: string = 'EURA'; + const isKYC: { [token: string]: boolean } = {}; + isKYC[tokens.bIB01.symbol!] = true; + isKYC[tokens.bC3M.symbol!] = true; + isKYC[tokens.bERNX.symbol!] = true; - const tokenAAmount: string = '100000000000000000'; - const tokenBAmount: string = '1000000000000000000'; - const nativeTokenAmount = '1000000000000000000'; + stables.forEach(stable => + collaterals[stable.symbol! as keyof Collateral].forEach(collateral => + describe(`${stable.symbol}/${collateral.symbol}`, () => { + const stableAmount: string = ( + 1n * BI_POWS[stable.decimals] + ).toString(); + const collateralAmount: string = ( + 1n * BI_POWS[collateral.decimals] + ).toString(); + const nativeTokenAmount = '1000000000000000000'; - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - ); - }); - describe('BERNX', () => { - const tokenASymbol: string = 'bERNX'; - const tokenBSymbol: string = 'EURA'; - - const tokenAAmount: string = '500000000000000000'; - const tokenBAmount: string = '1000000000000000000'; - const nativeTokenAmount = '1000000000000000000'; - - testForNetwork( - network, - dexKey, - tokenASymbol, - tokenBSymbol, - tokenAAmount, - tokenBAmount, - nativeTokenAmount, - ); - }); + testForNetwork( + network, + dexKey, + collateral.symbol!, + stable.symbol!, + collateralAmount, + stableAmount, + nativeTokenAmount, + isKYC[collateral.symbol!], + ); + }), + ), + ); }); }); diff --git a/src/dex/angle-transmuter/angle-transmuter-events.test.ts b/src/dex/angle-transmuter/angle-transmuter-events.test.ts index 9cc5518fc..cc18504d4 100644 --- a/src/dex/angle-transmuter/angle-transmuter-events.test.ts +++ b/src/dex/angle-transmuter/angle-transmuter-events.test.ts @@ -34,45 +34,41 @@ describe('AngleTransmuter EventPool Mainnet', () => { const eventsToTest: Record = { //Transmuter Events '0x00253582b2a3FE112feEC532221d9708c64cEFAb': { - // FeesSet: [19567142], + FeesSet: [], RedemptionCurveParamsSet: [], - // OracleSet: [19567142], - // Swap: [ - // 19582703, 19583592, 19584048, 19589408, 19602964, 19607526, 19611131, 19614332, 19616567, 19623965, 19625332, - // 19631246, 19631653, 19633515, 19638468, 19648373, 19653214, 19656178, 19657413, 19667310, 19667763, - // ], + OracleSet: [], + Swap: [ + 19582703, 19583592, 19584048, 19589408, 19602964, 19607526, 19611131, + 19614332, 19616567, 19623965, 19625332, 19631246, 19631653, 19633515, + 19638468, 19648373, 19653214, 19656178, 19657413, 19667310, 19667763, + ], Redeemed: [], ReservesAdjusted: [], - // CollateralAdded: [19567142], + CollateralAdded: [], CollateralRevoked: [], - // CollateralWhitelistStatusUpdated: [19567142], + CollateralWhitelistStatusUpdated: [], WhitelistStatusToggled: [], }, // Pyth Events - // "0x4305FB66699C3B2702D4d05CF36551390A4c69C6": { - // PriceFeedUpdate: [ - // 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, 19611413, - // 19611413, 19618548, 19618548, 19618548, 19618548, 19618548, 19618548, 19618548, 19618548, 19618548, 19618548, - // 19618548, 19618548, 19625698, 19625698, 19625698, 19625698, 19625698, 19625698, 19625698, 19625698, 19625698, - // 19625698, 19625698, 19625698, 19625698, 19625698, 19625698, 19632847, 19632847, 19632847, 19632847, 19632847, - // 19632847, 19632847, 19632847, 19632847, 19632847, 19632847, 19632847, 19632847, 19632847, 19632847, 19633586, - // 19633586, 19639991, 19639991, 19639991, 19639991, 19639991, 19639991, 19639991, 19639991, 19639991, 19639991, - // 19639991, 19639991, 19647112, 19647112, 19647112, 19647112, 19647112, 19647112, 19647112, 19647112, 19647112, - // 19647112, 19647112, 19647112, 19649850, 19649850, 19654237, 19654237, 19654237, 19654237, 19654237, 19654237, - // 19654237, 19654237, 19654237, 19654237, 19654237, 19654237, - // ], - // }, - //Backed Events - // "0x83Ec02059F686E747392A22ddfED7833bA0d7cE3": { - // AnswerUpdated: [ - // 19574099, 19574442, 19581598, 19588736, 19610148, 19617280, 19624427, 19638723, 19667243, 19674385, - // ], - // }, - // "0x475855DAe09af1e3f2d380d766b9E630926ad3CE": { - // AnswerUpdated: [ - // 19574095, 19574443, 19581596, 19588737, 19610145, 19617284, 19624426, 19631578, 19638720, 19667241, 19674386, - // ], - // }, + '0x4305FB66699C3B2702D4d05CF36551390A4c69C6': { + PriceFeedUpdate: [ + 19611413, 19618548, 19625698, 19632847, 19633586, 19639991, 19647112, + 19649850, 19649850, 19654237, + ], + }, + // Backed Events + '0x83Ec02059F686E747392A22ddfED7833bA0d7cE3': { + AnswerUpdated: [ + 19574099, 19574442, 19581598, 19588736, 19610148, 19617280, 19624427, + 19638723, 19667243, 19674385, + ], + }, + '0x475855DAe09af1e3f2d380d766b9E630926ad3CE': { + AnswerUpdated: [ + 19574095, 19574443, 19581596, 19588737, 19610145, 19617284, 19624426, + 19631578, 19638720, 19667241, 19674386, + ], + }, //Redstone Events '0x6E27A25999B3C665E44D903B2139F5a4Be2B6C26': { AnswerUpdated: [], diff --git a/src/dex/angle-transmuter/angle-transmuter-integration.test.ts b/src/dex/angle-transmuter/angle-transmuter-integration.test.ts index 72742ab61..f45fade04 100644 --- a/src/dex/angle-transmuter/angle-transmuter-integration.test.ts +++ b/src/dex/angle-transmuter/angle-transmuter-integration.test.ts @@ -15,6 +15,9 @@ import { import { Tokens } from '../../../tests/constants-e2e'; import { AngleTransmuterEventPool } from './angle-transmuter-pool'; import { Address } from '../../types'; +import { SmartTokenParams } from '../../../tests/smart-tokens'; + +export type Collateral = { [stablecoin: string]: SmartTokenParams[] }; /* README @@ -60,7 +63,20 @@ function decodeReaderResult( }); } +function getExchangeAddress( + network: Network, + srcAddress: Address, + dstAddress: Address, +): Address { + const tokens = Tokens[network]; + return srcAddress.toLowerCase() === tokens.EURA.address.toLowerCase() || + dstAddress.toLowerCase() === tokens.EURA.address.toLowerCase() + ? '0x00253582b2a3FE112feEC532221d9708c64cEFAb' + : '0x222222fD79264BBE280b4986F6FEfBC3524d0137'; +} + async function checkOnChainPricing( + network: Network, angleTransmuter: AngleTransmuter, funcName: string, blockNumber: number, @@ -69,7 +85,7 @@ async function checkOnChainPricing( tokenIn: Address, tokenOut: Address, ) { - const exchangeAddress = '0x00253582b2a3FE112feEC532221d9708c64cEFAb'; + const exchangeAddress = getExchangeAddress(network, tokenIn, tokenOut); const readerIface = AngleTransmuterEventPool.angleTransmuterIface; const readerCallData = getReaderCalldata( @@ -80,6 +96,7 @@ async function checkOnChainPricing( tokenIn, tokenOut, ); + const readerResult = ( await angleTransmuter.dexHelper.multiContract.methods .aggregate(readerCallData) @@ -149,6 +166,7 @@ async function testPricingOnNetwork( // Check if onchain pricing equals to calculated ones await checkOnChainPricing( + network, angleTransmuter, funcNameToCheck, blockNumber, @@ -170,37 +188,33 @@ describe('AngleTransmuter', () => { const tokens = Tokens[network]; - const eurocSymbol = 'EUROC'; - const bC3MSymbol = 'bC3M'; - const bERNXSymbol = 'bERNX'; - const euraSymbol = 'EURA'; - - const amountsEUROC = [ - 0n, - 1n * BI_POWS[tokens[eurocSymbol].decimals], - 2n * BI_POWS[tokens[eurocSymbol].decimals], - 3n * BI_POWS[tokens[eurocSymbol].decimals], - 4n * BI_POWS[tokens[eurocSymbol].decimals], - 5n * BI_POWS[tokens[eurocSymbol].decimals], - 6n * BI_POWS[tokens[eurocSymbol].decimals], - 7n * BI_POWS[tokens[eurocSymbol].decimals], - 8n * BI_POWS[tokens[eurocSymbol].decimals], - 9n * BI_POWS[tokens[eurocSymbol].decimals], - 10n * BI_POWS[tokens[eurocSymbol].decimals], + const stables = [ + // tokens.EURA, + tokens.USDA, ]; - const amountsEURA = [ + const collaterals: Collateral = { + USDA: [tokens.USDC, tokens.steakUSDC, tokens.bIB01], + EURA: [tokens.EUROC, tokens.bC3M, tokens.bERNX], + }; + + const isKYC: { [token: string]: boolean } = {}; + isKYC[tokens.bIB01.symbol!] = true; + isKYC[tokens.bC3M.symbol!] = true; + isKYC[tokens.bERNX.symbol!] = true; + + const amounts = [ 0n, - 1n * BI_POWS[tokens[euraSymbol].decimals], - 2n * BI_POWS[tokens[euraSymbol].decimals], - 3n * BI_POWS[tokens[euraSymbol].decimals], - 4n * BI_POWS[tokens[euraSymbol].decimals], - 5n * BI_POWS[tokens[euraSymbol].decimals], - 6n * BI_POWS[tokens[euraSymbol].decimals], - 7n * BI_POWS[tokens[euraSymbol].decimals], - 8n * BI_POWS[tokens[euraSymbol].decimals], - 9n * BI_POWS[tokens[euraSymbol].decimals], - 10n * BI_POWS[tokens[euraSymbol].decimals], + 1n * BI_POWS[tokens.USDA.decimals], + 2n * BI_POWS[tokens.USDA.decimals], + 3n * BI_POWS[tokens.USDA.decimals], + 4n * BI_POWS[tokens.USDA.decimals], + 5n * BI_POWS[tokens.USDA.decimals], + 6n * BI_POWS[tokens.USDA.decimals], + 7n * BI_POWS[tokens.USDA.decimals], + 8n * BI_POWS[tokens.USDA.decimals], + 9n * BI_POWS[tokens.USDA.decimals], + 10n * BI_POWS[tokens.USDA.decimals], ]; beforeAll(async () => { @@ -211,112 +225,126 @@ describe('AngleTransmuter', () => { } }); - it('getPoolIdentifiers and getPricesVolume SELL - EUROC', async () => { - await testPricingOnNetwork( - angleTransmuter, - network, - dexKey, - blockNumber, - eurocSymbol, - euraSymbol, - SwapSide.SELL, - amountsEUROC, - 'quoteIn', - ); - }); - - it('getPoolIdentifiers and getPricesVolume SELL - EURA', async () => { - await testPricingOnNetwork( - angleTransmuter, - network, - dexKey, - blockNumber, - euraSymbol, - eurocSymbol, - SwapSide.SELL, - amountsEURA, - 'quoteIn', - ); - }); - - it('getPoolIdentifiers and getPricesVolume BUY - EUROC', async () => { - await testPricingOnNetwork( - angleTransmuter, - network, - dexKey, - blockNumber, - eurocSymbol, - euraSymbol, - SwapSide.BUY, - amountsEURA, - 'quoteOut', - ); - }); - - it('getPoolIdentifiers and getPricesVolume BUY - EURA', async () => { - await testPricingOnNetwork( - angleTransmuter, - network, - dexKey, - blockNumber, - euraSymbol, - eurocSymbol, - SwapSide.BUY, - amountsEUROC, - 'quoteOut', - ); - }); - - it('getTopPoolsForToken - EUROC', async () => { - // We have to check without calling initializePricing, because - // pool-tracker is not calling that function - const newAngleTransmuter = new AngleTransmuter( - network, - dexKey, - dexHelper, - ); - if (newAngleTransmuter.updatePoolState) { - await newAngleTransmuter.updatePoolState(); - } - const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( - tokens[eurocSymbol].address, - 10, - ); - console.log(`${eurocSymbol} Top Pools:`, poolLiquidity); - - if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { - checkPoolsLiquidity( - poolLiquidity, - Tokens[network][eurocSymbol].address, - dexKey, - ); - } - }); - - it('getTopPoolsForToken - EURA', async () => { - // We have to check without calling initializePricing, because - // pool-tracker is not calling that function - const newAngleTransmuter = new AngleTransmuter( - network, - dexKey, - dexHelper, - ); - if (newAngleTransmuter.updatePoolState) { - await newAngleTransmuter.updatePoolState(); - } - const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( - tokens[euraSymbol].address, - 10, - ); - console.log(`${euraSymbol} Top Pools:`, poolLiquidity); - - if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { - checkPoolsLiquidity( - poolLiquidity, - Tokens[network][euraSymbol].address, - dexKey, - ); - } - }); + stables.forEach(stable => + collaterals[stable.symbol! as keyof Collateral].forEach(collateral => + describe(`${stable.symbol}/${collateral.symbol}`, () => { + const amountsCollateral = [ + 0n, + 1n * BI_POWS[collateral.decimals], + 2n * BI_POWS[collateral.decimals], + 3n * BI_POWS[collateral.decimals], + 4n * BI_POWS[collateral.decimals], + 5n * BI_POWS[collateral.decimals], + 6n * BI_POWS[collateral.decimals], + 7n * BI_POWS[collateral.decimals], + 8n * BI_POWS[collateral.decimals], + 9n * BI_POWS[collateral.decimals], + 10n * BI_POWS[collateral.decimals], + ]; + + it('getTopPoolsForToken - collateral', async () => { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newAngleTransmuter = new AngleTransmuter( + network, + dexKey, + dexHelper, + ); + if (newAngleTransmuter.updatePoolState) { + await newAngleTransmuter.updatePoolState(); + } + const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( + collateral.address, + 10, + ); + console.log(`${collateral.symbol} Top Pools:`, poolLiquidity); + + if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity(poolLiquidity, collateral.address, dexKey); + } + }); + + it('getTopPoolsForToken - stablecoin', async () => { + // We have to check without calling initializePricing, because + // pool-tracker is not calling that function + const newAngleTransmuter = new AngleTransmuter( + network, + dexKey, + dexHelper, + ); + if (newAngleTransmuter.updatePoolState) { + await newAngleTransmuter.updatePoolState(); + } + const poolLiquidity = await newAngleTransmuter.getTopPoolsForToken( + stable.address, + 10, + ); + console.log(`${stable.symbol} Top Pools:`, poolLiquidity); + + if (!newAngleTransmuter.hasConstantPriceLargeAmounts) { + checkPoolsLiquidity(poolLiquidity, stable.address, dexKey); + } + }); + + it('getPoolIdentifiers and getPricesVolume SELL - collateral', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + collateral.symbol!, + stable.symbol!, + SwapSide.SELL, + amountsCollateral, + 'quoteIn', + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY - stablecoin', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + stable.symbol!, + collateral.symbol!, + SwapSide.BUY, + amountsCollateral, + 'quoteOut', + ); + }); + + if (!isKYC[collateral.symbol!]) { + it('getPoolIdentifiers and getPricesVolume SELL - stablecoin', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + stable.symbol!, + collateral.symbol!, + SwapSide.SELL, + amounts, + 'quoteIn', + ); + }); + + it('getPoolIdentifiers and getPricesVolume BUY - collateral', async () => { + await testPricingOnNetwork( + angleTransmuter, + network, + dexKey, + blockNumber, + collateral.symbol!, + stable.symbol!, + SwapSide.BUY, + amounts, + 'quoteOut', + ); + }); + } + }), + ), + ); }); }); diff --git a/src/dex/angle-transmuter/angle-transmuter-pool.ts b/src/dex/angle-transmuter/angle-transmuter-pool.ts index 3acff260d..cdb9d8eb2 100644 --- a/src/dex/angle-transmuter/angle-transmuter-pool.ts +++ b/src/dex/angle-transmuter/angle-transmuter-pool.ts @@ -16,6 +16,7 @@ import { PoolConfig, PoolState, PythConfig, + TransmuterParams, TransmuterState, } from './types'; import TransmuterABI from '../../abi/angle-transmuter/Transmuter.json'; @@ -35,7 +36,6 @@ import { BackedSubscriber } from './backedOracle'; import { SwapSide } from '../../constants'; import { ethers } from 'ethers'; import { BLOCK_UPGRADE_ORACLE } from './constants'; -import { log } from 'console'; export class AngleTransmuterEventPool extends ComposedEventSubscriber { public transmuter: Contract; @@ -104,7 +104,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber ); const transmuterListener = new TransmuterSubscriber( - config.EURA.address, + config.stablecoin.address, config.transmuter, config.collaterals, lens>().transmuter, @@ -124,7 +124,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber pythListener, ], { - stablecoin: config.EURA, + stablecoin: config.stablecoin, transmuter: {} as TransmuterState, oracles: { chainlink: {}, pyth: {} }, }, @@ -419,7 +419,7 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber } static async getConfig( - dexParams: DexParams, + dexParams: TransmuterParams, blockNumber: number | 'latest', multiContract: Contract, ): Promise { @@ -432,14 +432,14 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber // get all oracles feed const oracles = await AngleTransmuterEventPool.getOraclesConfig( dexParams.transmuter, - dexParams.pyth, + dexParams.pyth!, collaterals, blockNumber, multiContract, ); return { - EURA: dexParams.EURA, + stablecoin: dexParams.stablecoin, transmuter: dexParams.transmuter, collaterals: collaterals, oracles: oracles, @@ -632,6 +632,23 @@ export class AngleTransmuterEventPool extends ComposedEventSubscriber price = 1; } else if (oracleType === OracleReadType.NO_ORACLE) { price = baseValue; + } else if (oracleType == OracleReadType.MAX) { + price = feed.maxValue!; + } else if (oracleType == OracleReadType.MORPHO_ORACLE) { + // const oracle = filterDictionaryOnly( + // ethers.utils.defaultAbiCoder.decode( + // ['address contractAddress', 'uint256 normalizationFactor'], + // configOracle.hyperparameters, + // ), + // ) as unknown as { contractAddress: string, normalizationFactor: BigNumber }; + // userDeviation = Number.parseFloat( + // formatEther(hyperparameters.userDeviation.toString()), + // ); + // burnRatioDeviation = Number.parseFloat( + // formatEther(hyperparameters.burnRatioDeviation.toString()), + // ); + // (address contractAddress, uint256 normalizationFactor) = abi.decode(data, (address, uint256)); + // return IMorphoOracle(contractAddress).price() / normalizationFactor; } return price; } diff --git a/src/dex/angle-transmuter/angle-transmuter.ts b/src/dex/angle-transmuter/angle-transmuter.ts index 818a42de8..e1c816c93 100644 --- a/src/dex/angle-transmuter/angle-transmuter.ts +++ b/src/dex/angle-transmuter/angle-transmuter.ts @@ -28,11 +28,13 @@ export class AngleTransmuter extends SimpleExchange implements IDex { - protected eventPools: AngleTransmuterEventPool | null = null; - protected supportedTokensMap: { [address: string]: boolean } = {}; - // supportedTokens is only used by the pooltracker - protected supportedTokens: Token[] = []; - transmuterUSDLiquidity = 0; + protected eventPools: { [key: string]: AngleTransmuterEventPool } = {}; + protected supportedTokensMap: { + [key: string]: { [address: string]: boolean }; + } = {}; + protected supportedTokens: { [key: string]: Token[] } = {}; + protected transmuterUSDLiquidity: { [key: string]: number } = {}; + stablecoinList: string[]; public static erc20Interface = new Interface(ERC20ABI); @@ -55,7 +57,17 @@ export class AngleTransmuter ) { super(dexHelper, dexKey); this.logger = dexHelper.getLogger(dexKey); - this.supportedTokensMap[params.EURA.address.toLowerCase()] = true; + this.stablecoinList = Object.keys(params); + this.stablecoinList.forEach(stablecoin => { + this.supportedTokensMap[stablecoin] = {}; + this.supportedTokens[stablecoin] = []; + this.transmuterUSDLiquidity[stablecoin] = 0; + }); + this.stablecoinList.forEach(stablecoin => { + this.supportedTokensMap[stablecoin][ + params[stablecoin as keyof DexParams].stablecoin.address.toLowerCase() + ] = true; + }); } // Initialize pricing is called once in the start of @@ -63,22 +75,25 @@ export class AngleTransmuter // for pricing requests. It is optional for a DEX to // implement this function async initializePricing(blockNumber: number) { - const config = await AngleTransmuterEventPool.getConfig( - this.params, - blockNumber, - this.dexHelper.multiContract, - ); - config.collaterals.forEach( - (token: Address) => (this.supportedTokensMap[token.toLowerCase()] = true), - ); - this.eventPools = new AngleTransmuterEventPool( - this.dexKey, - this.network, - this.dexHelper, - this.logger, - config, - ); - await this.eventPools.initialize(blockNumber); + for (const stablecoin of this.stablecoinList) { + const config = await AngleTransmuterEventPool.getConfig( + this.params[stablecoin as keyof DexParams], + blockNumber, + this.dexHelper.multiContract, + ); + config.collaterals.forEach( + (token: Address) => + (this.supportedTokensMap[stablecoin][token.toLowerCase()] = true), + ); + this.eventPools[stablecoin] = new AngleTransmuterEventPool( + this.dexKey, + this.network, + this.dexHelper, + this.logger, + config, + ); + await this.eventPools[stablecoin].initialize(blockNumber); + } } // Returns the list of contract adapters (name and index) @@ -97,9 +112,9 @@ export class AngleTransmuter side: SwapSide, blockNumber: number, ): Promise { - if (this._knownAddress(srcToken, destToken)) - return [`${this.dexKey}_${this.params.EURA.address.toLowerCase()}`]; - return []; + const knownInfo = this._knownAddress(srcToken, destToken); + if (!knownInfo.known) return []; + return [`${this.dexKey}_${knownInfo.agToken!.toLowerCase()}`]; } // Returns pool prices for amounts. @@ -114,15 +129,15 @@ export class AngleTransmuter blockNumber: number, limitPools?: string[], ): Promise> { - const uniquePool = `${ - this.dexKey - }_${this.params.EURA.address.toLowerCase()}`; + const knownInfo = this._knownAddress(srcToken, destToken); + const pool = `${this.dexKey}_${knownInfo.agToken!.toLowerCase()}`; if ( - !this._knownAddress(srcToken, destToken) || - (limitPools && limitPools.length > 0 && !limitPools.includes(uniquePool)) + !knownInfo.known || + (limitPools && limitPools.length > 0 && !limitPools.includes(pool)) ) return null; + const fiat = knownInfo.fiatName! as keyof DexParams; const preProcessDecimals = side === SwapSide.SELL ? srcToken.decimals : destToken.decimals; const postProcessDecimals = @@ -132,7 +147,7 @@ export class AngleTransmuter Number.parseFloat(formatUnits(amount.toString(), preProcessDecimals)), ); - const prices = await this.eventPools!.getAmountOut( + const prices = await this.eventPools[fiat]!.getAmountOut( srcToken.address, destToken.address, side, @@ -157,8 +172,8 @@ export class AngleTransmuter unit: pricesBigInt[0], gasCost: TransmuterGasCost, exchange: this.dexKey, - data: { exchange: this.params.transmuter }, - poolAddresses: [this.params.transmuter], + data: { exchange: this.params[fiat].transmuter }, + poolAddresses: [this.params[fiat].transmuter], }, ]; } @@ -236,71 +251,76 @@ export class AngleTransmuter // getTopPoolsForToken. It is optional for a DEX // to implement this async updatePoolState(): Promise { - if (!this.supportedTokens.length) { - let tokenAddresses = await AngleTransmuterEventPool.getCollateralsList( - this.params.transmuter, - 'latest', - this.dexHelper.multiContract, - ); - tokenAddresses = tokenAddresses.concat([this.params.EURA.address]); - - const decimalsCallData = - AngleTransmuter.erc20Interface.encodeFunctionData('decimals'); - const tokenBalanceMultiCall = tokenAddresses.map(t => ({ - target: t, - callData: decimalsCallData, + for (const stablecoin of this.stablecoinList) { + const fiat = stablecoin as keyof DexParams; + const paramFiat = this.params[fiat]; + + if (!this.supportedTokens.length) { + let tokenAddresses = await AngleTransmuterEventPool.getCollateralsList( + paramFiat.transmuter, + 'latest', + this.dexHelper.multiContract, + ); + tokenAddresses = tokenAddresses.concat([paramFiat.stablecoin.address]); + + const decimalsCallData = + AngleTransmuter.erc20Interface.encodeFunctionData('decimals'); + const tokenBalanceMultiCall = tokenAddresses.map(t => ({ + target: t, + callData: decimalsCallData, + })); + const res = ( + await this.dexHelper.multiContract.methods + .aggregate(tokenBalanceMultiCall) + .call() + ).returnData; + + const tokenDecimals = res.map((r: any) => + Number.parseInt( + AngleTransmuter.erc20Interface + .decodeFunctionResult('decimals', r)[0] + .toString(), + ), + ); + + this.supportedTokens[fiat] = tokenAddresses.map((t, i) => ({ + address: t, + decimals: tokenDecimals[i], + })); + } + + // Only work if there are no managers + const erc20BalanceCalldata = + AngleTransmuter.erc20Interface.encodeFunctionData('balanceOf', [ + paramFiat.transmuter, + ]); + const tokenBalanceMultiCall = this.supportedTokens[fiat].map(t => ({ + target: t.address, + callData: erc20BalanceCalldata, })); const res = ( await this.dexHelper.multiContract.methods .aggregate(tokenBalanceMultiCall) .call() ).returnData; - - const tokenDecimals = res.map((r: any) => - Number.parseInt( + const tokenBalances = res.map((r: any) => + BigInt( AngleTransmuter.erc20Interface - .decodeFunctionResult('decimals', r)[0] + .decodeFunctionResult('balanceOf', r)[0] .toString(), ), ); - this.supportedTokens = tokenAddresses.map((t, i) => ({ - address: t, - decimals: tokenDecimals[i], - })); + // TODO bC3M price not detected + const tokenBalancesUSD = await Promise.all( + this.supportedTokens[fiat].map((t, i) => + this.dexHelper.getTokenUSDPrice(t, tokenBalances[i]), + ), + ); + this.transmuterUSDLiquidity[fiat] = tokenBalancesUSD.reduce( + (sum: number, curr: number) => sum + curr, + ); } - - // Only work if there are no managers - const erc20BalanceCalldata = - AngleTransmuter.erc20Interface.encodeFunctionData('balanceOf', [ - this.params.transmuter, - ]); - const tokenBalanceMultiCall = this.supportedTokens.map(t => ({ - target: t.address, - callData: erc20BalanceCalldata, - })); - const res = ( - await this.dexHelper.multiContract.methods - .aggregate(tokenBalanceMultiCall) - .call() - ).returnData; - const tokenBalances = res.map((r: any) => - BigInt( - AngleTransmuter.erc20Interface - .decodeFunctionResult('balanceOf', r)[0] - .toString(), - ), - ); - - // TODO bC3M price not detected - const tokenBalancesUSD = await Promise.all( - this.supportedTokens.map((t, i) => - this.dexHelper.getTokenUSDPrice(t, tokenBalances[i]), - ), - ); - this.transmuterUSDLiquidity = tokenBalancesUSD.reduce( - (sum: number, curr: number) => sum + curr, - ); } // Returns list of top pools based on liquidity. Max @@ -309,49 +329,75 @@ export class AngleTransmuter tokenAddress: Address, limit: number, ): Promise { - if (!this.supportedTokens.some(t => t.address === tokenAddress)) return []; - - const connectorTokens = - tokenAddress === this.params.EURA.address - ? this.supportedTokens.filter( - token => token.address !== this.params.EURA.address, - ) - : [this.params.EURA]; - return [ - { - exchange: this.dexKey, - address: this.params.transmuter, - connectorTokens: connectorTokens.slice(0, limit), - // liquidity is potentially infinite if swapping for agXXX, otherwise at most reserves value - liquidityUSD: - tokenAddress === this.params.EURA.address - ? this.transmuterUSDLiquidity - : 1e9, - }, - ]; + for (const stablecoin of this.stablecoinList) { + const fiat = stablecoin as keyof DexParams; + const paramFiat = this.params[fiat]; + + // If not this stable let's check another one + if ( + !this.supportedTokens[fiat].some( + t => t.address.toLowerCase() === tokenAddress.toLowerCase(), + ) + ) + continue; + + const connectorTokens = + tokenAddress === paramFiat.stablecoin.address + ? this.supportedTokens[fiat].filter( + token => + token.address.toLowerCase() !== + paramFiat.stablecoin.address.toLowerCase(), + ) + : [paramFiat.stablecoin]; + + return [ + { + exchange: this.dexKey, + address: paramFiat.transmuter, + connectorTokens: connectorTokens.slice(0, limit), + // liquidity is potentially infinite if swapping for agXXX, otherwise at most reserves value + liquidityUSD: + tokenAddress === paramFiat.stablecoin.address + ? this.transmuterUSDLiquidity[fiat] + : 1e9, + }, + ]; + } + return []; } // This is optional function in case if your implementation has acquired any resources // you need to release for graceful shutdown. For example, it may be any interval timer releaseResources(): AsyncOrSync {} - _knownAddress(srcToken: Token, destToken: Token): boolean { + _knownAddress( + srcToken: Token, + destToken: Token, + ): { known: boolean; agToken: string | null; fiatName: string | null } { const srcAddress = this.dexHelper.config .wrapETH(srcToken) .address.toLowerCase(); const destAddress = this.dexHelper.config .wrapETH(destToken) .address.toLowerCase(); - if ( - srcAddress !== destAddress && - this.supportedTokensMap[srcAddress] && - this.supportedTokensMap[destAddress] && - // check that at least one of the tokens is EURA - (srcAddress === this.params.EURA.address.toLowerCase() || - destAddress === this.params.EURA.address.toLowerCase()) - ) { - return true; + + for (const stablecoin of this.stablecoinList) { + const fiat = stablecoin as keyof DexParams; + if ( + srcAddress !== destAddress && + this.supportedTokensMap[stablecoin][srcAddress] && + this.supportedTokensMap[stablecoin][destAddress] && + // check that at least one of the tokens is EURA + (srcAddress === this.params[fiat].stablecoin.address.toLowerCase() || + destAddress === this.params[fiat].stablecoin.address.toLowerCase()) + ) { + return { + known: true, + agToken: this.params[fiat].stablecoin.address.toLowerCase(), + fiatName: stablecoin, + }; + } } - return false; + return { known: false, agToken: null, fiatName: null }; } } diff --git a/src/dex/angle-transmuter/config.ts b/src/dex/angle-transmuter/config.ts index 4cac17261..f38312e2c 100644 --- a/src/dex/angle-transmuter/config.ts +++ b/src/dex/angle-transmuter/config.ts @@ -5,12 +5,22 @@ import { Network, SwapSide } from '../../constants'; export const AngleTransmuterConfig: DexConfigMap = { AngleTransmuter: { [Network.MAINNET]: { - EURA: { - address: '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8', - decimals: 18, + EUR: { + stablecoin: { + address: '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8', + decimals: 18, + }, + transmuter: '0x00253582b2a3FE112feEC532221d9708c64cEFAb', + pyth: '0x4305FB66699C3B2702D4d05CF36551390A4c69C6', + }, + USD: { + stablecoin: { + address: '0x0000206329b97DB379d5E1Bf586BbDB969C63274', + decimals: 18, + }, + transmuter: '0x222222fD79264BBE280b4986F6FEfBC3524d0137', + pyth: '0x4305FB66699C3B2702D4d05CF36551390A4c69C6', }, - transmuter: '0x00253582b2a3FE112feEC532221d9708c64cEFAb', - pyth: '0x4305FB66699C3B2702D4d05CF36551390A4c69C6', }, }, }; diff --git a/src/dex/angle-transmuter/morphoVault.ts b/src/dex/angle-transmuter/morphoVault.ts new file mode 100644 index 000000000..1f24b0444 --- /dev/null +++ b/src/dex/angle-transmuter/morphoVault.ts @@ -0,0 +1,113 @@ +// import { DeepReadonly } from 'ts-essentials'; +// import { PartialEventSubscriber } from '../../composed-event-subscriber'; +// import { +// Address, +// BlockHeader, +// Log, +// Logger, +// MultiCallInput, +// MultiCallOutput, +// } from '../../types'; +// import { Lens } from '../../lens'; +// import { Interface } from '@ethersproject/abi'; +// import MorphoVaultABI from '../../abi/angle-transmuter/MorphoVault.json'; + +// export type MorphoVaultState = { +// answer: bigint; +// timestamp: bigint; +// }; + +// export class MorphoVaultSubscriber extends PartialEventSubscriber< +// State, +// MorphoVaultState +// > { +// static readonly vaultInterface = new Interface(MorphoVaultABI); +// static readonly ANSWER_UPDATED_TOPIC = +// MorphoVaultSubscriber.vaultInterface.getEventTopic('AnswerUpdated'); + +// constructor( +// private proxy: Address, +// private aggregator: Address, +// lens: Lens, DeepReadonly>, +// logger: Logger, +// ) { +// super([aggregator], lens, logger); +// } + +// static getReadAggregatorMultiCallInput(proxy: Address): MultiCallInput { +// return { +// target: proxy, +// callData: +// ChainLinkSubscriber.proxyInterface.encodeFunctionData('aggregator'), +// }; +// } + +// static readAggregator(multicallOutput: MultiCallOutput): Address { +// return ChainLinkSubscriber.proxyInterface.decodeFunctionResult( +// 'aggregator', +// multicallOutput, +// )[0]; +// } + +// static getReadDecimal(proxy: Address): MultiCallInput { +// return { +// target: proxy, +// callData: +// ChainLinkSubscriber.proxyInterface.encodeFunctionData('decimals'), +// }; +// } + +// static readDecimals(multicallOutput: MultiCallOutput): Address { +// return ChainLinkSubscriber.proxyInterface.decodeFunctionResult( +// 'decimals', +// multicallOutput, +// )[0]; +// } + +// public processLog( +// state: DeepReadonly, +// log: Readonly, +// blockHeader: Readonly, +// ): DeepReadonly | null { +// if (log.topics[0] !== ChainLinkSubscriber.ANSWER_UPDATED_TOPIC) return null; // Ignore other events +// const decoded = ChainLinkSubscriber.proxyInterface.decodeEventLog( +// 'AnswerUpdated', +// log.data, +// log.topics, +// ); +// return { +// answer: BigInt(decoded.current.toString()), +// timestamp: BigInt(decoded.updatedAt.toString()), +// }; +// } + +// public getGenerateStateMultiCallInputs(): MultiCallInput[] { +// return [ +// { +// target: this.proxy, +// callData: +// ChainLinkSubscriber.proxyInterface.encodeFunctionData( +// 'latestRoundData', +// ), +// }, +// ]; +// } + +// public generateState( +// multicallOutputs: MultiCallOutput[], +// blockNumber?: number | 'latest', +// ): DeepReadonly { +// const decoded = ChainLinkSubscriber.proxyInterface.decodeFunctionResult( +// 'latestRoundData', +// multicallOutputs[0], +// ); +// return { +// answer: BigInt(decoded.answer.toString()), +// timestamp: BigInt(decoded.updatedAt.toString()), +// }; +// } + +// public getLatestRoundData(state: DeepReadonly): bigint { +// return this.lens.get()(state).answer; +// } +// } diff --git a/src/dex/angle-transmuter/transmuter.ts b/src/dex/angle-transmuter/transmuter.ts index 3da6dd37e..f8ee0090b 100644 --- a/src/dex/angle-transmuter/transmuter.ts +++ b/src/dex/angle-transmuter/transmuter.ts @@ -22,10 +22,12 @@ import { Fees, Oracle, CollateralState, + MaxOracle, + MorphoOracle, } from './types'; import _ from 'lodash'; import { BigNumber, ethers } from 'ethers'; -import { formatUnits } from 'ethers/lib/utils'; +import { formatEther, formatUnits } from 'ethers/lib/utils'; import { filterDictionaryOnly } from './utils'; export class TransmuterSubscriber extends PartialEventSubscriber< @@ -497,23 +499,59 @@ export class TransmuterSubscriber extends PartialEventSubscriber< return { isChainlink: true, isPyth: false, + isMorpho: false, chainlink: TransmuterSubscriber._decodeChainlinkOracle(oracleData), }; if (readType === OracleReadType.PYTH) return { isChainlink: false, isPyth: true, + isMorpho: false, pyth: TransmuterSubscriber._decodePythOracle(oracleData), }; + if (readType === OracleReadType.MAX) + return { + isChainlink: false, + isPyth: false, + isMorpho: false, + maxValue: TransmuterSubscriber._decodeMaxOracle(oracleData), + }; + if (readType === OracleReadType.MORPHO_ORACLE) + return { + isChainlink: false, + isPyth: false, + isMorpho: true, + morpho: TransmuterSubscriber._decodeMorphoOracle(oracleData), + }; if (readType === OracleReadType.WSTETH) - return { isChainlink: false, isPyth: false, otherContract: STETH }; + return { + isChainlink: false, + isPyth: false, + isMorpho: false, + otherContract: STETH, + }; if (readType === OracleReadType.CBETH) - return { isChainlink: false, isPyth: false, otherContract: CBETH }; + return { + isChainlink: false, + isPyth: false, + isMorpho: false, + otherContract: CBETH, + }; if (readType === OracleReadType.RETH) - return { isChainlink: false, isPyth: false, otherContract: RETH }; + return { + isChainlink: false, + isPyth: false, + isMorpho: false, + otherContract: RETH, + }; if (readType === OracleReadType.SFRXETH) - return { isChainlink: false, isPyth: false, otherContract: SFRXETH }; - return { isChainlink: false, isPyth: false }; + return { + isChainlink: false, + isPyth: false, + isMorpho: false, + otherContract: SFRXETH, + }; + return { isChainlink: false, isPyth: false, isMorpho: false }; } static _decodeChainlinkOracle(oracleData: string): Chainlink { @@ -549,4 +587,23 @@ export class TransmuterSubscriber extends PartialEventSubscriber< return pythOracleDecoded; } + + static _decodeMaxOracle(oracleData: string): number { + const maxOracleDecoded = filterDictionaryOnly( + ethers.utils.defaultAbiCoder.decode(['uint256 maxValue'], oracleData), + ) as unknown as MaxOracle; + + return Number.parseFloat(formatEther(maxOracleDecoded.maxValue)); + } + + static _decodeMorphoOracle(oracleData: string): MorphoOracle { + const morphoOracleDecoded = filterDictionaryOnly( + ethers.utils.defaultAbiCoder.decode( + ['address oracle', 'uint256 normalizationFactor'], + oracleData, + ), + ) as unknown as MorphoOracle; + + return morphoOracleDecoded; + } } diff --git a/src/dex/angle-transmuter/types.ts b/src/dex/angle-transmuter/types.ts index 3f1ca0b6b..44e4b4ec6 100644 --- a/src/dex/angle-transmuter/types.ts +++ b/src/dex/angle-transmuter/types.ts @@ -37,7 +37,7 @@ export type ChainlinkConfig = { export type PythConfig = { proxy: Address; ids: string[] }; export type PoolConfig = { - EURA: Token; + stablecoin: Token; transmuter: Address; collaterals: Address[]; oracles: { @@ -65,11 +65,15 @@ export type AngleTransmuterData = { exchange: Address; }; -export type DexParams = { - EURA: Token; +export type TransmuterParams = { + stablecoin: Token; transmuter: Address; pyth: Address; }; +export type DexParams = { + EUR: TransmuterParams; + USD: TransmuterParams; +}; export enum QuoteType { MintExactInput = 0, @@ -120,12 +124,24 @@ export type Chainlink = { quoteType: OracleQuoteType; }; +export type MorphoOracle = { + oracle: Address[]; + normalizationFactor: BigNumber[]; +}; + +export type MaxOracle = { + maxValue: number; +}; + export type OracleFeed = { isChainlink: boolean; isPyth: boolean; + isMorpho: boolean; chainlink?: Chainlink; pyth?: Pyth; + morpho?: MorphoOracle; otherContract?: Address; + maxValue?: number; }; export type Oracle = { diff --git a/tests/constants-e2e.ts b/tests/constants-e2e.ts index 1f3e050b2..f885fcaf7 100644 --- a/tests/constants-e2e.ts +++ b/tests/constants-e2e.ts @@ -36,8 +36,9 @@ export const Tokens: { decimals: 9, }, USDC: { - address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', decimals: 6, + symbol: 'USDC', addBalance: balancesFn, addAllowance: allowedFn, }, @@ -318,30 +319,37 @@ export const Tokens: { EURA: { address: '0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8', decimals: 18, + symbol: 'EURA', }, EUROC: { address: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c', decimals: 6, + symbol: 'EUROC', }, bERNX: { address: '0x3f95AA88dDbB7D9D484aa3D482bf0a80009c52c9', decimals: 18, + symbol: 'bERNX', }, bC3M: { address: '0x2F123cF3F37CE3328CC9B5b8415f9EC5109b45e7', decimals: 18, + symbol: 'bC3M', }, USDA: { address: '0x0000206329b97DB379d5E1Bf586BbDB969C63274', decimals: 18, + symbol: 'USDA', }, bIB01: { address: '0xCA30c93B02514f86d5C86a6e375E3A330B435Fb5', decimals: 18, + symbol: 'bIB01', }, steakUSDC: { address: '0xBEEF01735c132Ada46AA9aA4c54623cAA92A64CB', decimals: 18, + symbol: 'steakUSDC', }, GHO: { address: '0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f', @@ -1115,7 +1123,7 @@ export const Holders: { SDEX: '0xB0470cF15B22a6A32c49a7C20E3821B944A76058', frxETH: '0x9df2322bdAEC46627100C999E6dDdD27837fec6e', EURA: '0xa116f421ff82A9704428259fd8CC63347127B777', - USDA: '0xd9Da13DE745bfa50FFAAFD0a531B92f0511B72Cf', + USDA: '0x5a54aD9860B08AAee07174887f9ee5107b0A2e72', }, [Network.ROPSTEN]: { ETH: '0x43262A12d8610AA70C15DbaeAC321d51613c9071',