diff --git a/.env.example b/.env.example index 04a695e86..59830e7ce 100644 --- a/.env.example +++ b/.env.example @@ -9,12 +9,14 @@ RESEARCH_ORIGIN=https://research.lido.fi EL_RPC_URLS_1= EL_RPC_URLS_17000= EL_RPC_URLS_11155111= +EL_RPC_URLS_10= EL_RPC_URLS_11155420= # IPFS prefill RPC URLs - list of URLs delimited by commas PREFILL_UNSAFE_EL_RPC_URLS_1= PREFILL_UNSAFE_EL_RPC_URLS_17000= PREFILL_UNSAFE_EL_RPC_URLS_11155111= +PREFILL_UNSAFE_EL_RPC_URLS_10= PREFILL_UNSAFE_EL_RPC_URLS_11155420= # supported networks for connecting wallet diff --git a/IPFS.json b/IPFS.json index 3e967c8b0..7c62eb623 100644 --- a/IPFS.json +++ b/IPFS.json @@ -31,14 +31,5 @@ "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"], "multiChainBanner": [] } - }, - "11155420": { - "__warning__": "For testing purposes only", - "cid": "", - "leastSafeVersion": "0.36.1", - "config": { - "enabledWithdrawalDexes": ["one-inch", "paraswap", "bebop"], - "multiChainBanner": [] - } } } diff --git a/abi/l2-steth.abi.json b/abi/l2-steth.abi.json new file mode 100644 index 000000000..247cdc8f4 --- /dev/null +++ b/abi/l2-steth.abi.json @@ -0,0 +1,438 @@ +[ + { + "inputs": [ + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "string", "name": "version_", "type": "string" }, + { "internalType": "uint8", "name": "decimals_", "type": "uint8" }, + { + "internalType": "address", + "name": "tokenToWrapFrom_", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenRateOracle_", + "type": "address" + }, + { "internalType": "address", "name": "bridge_", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "ErrorAccountIsZeroAddress", "type": "error" }, + { "inputs": [], "name": "ErrorDeadlineExpired", "type": "error" }, + { "inputs": [], "name": "ErrorInvalidSignature", "type": "error" }, + { "inputs": [], "name": "ErrorNameIsEmpty", "type": "error" }, + { "inputs": [], "name": "ErrorNotBridge", "type": "error" }, + { "inputs": [], "name": "ErrorNotEnoughAllowance", "type": "error" }, + { "inputs": [], "name": "ErrorNotEnoughBalance", "type": "error" }, + { "inputs": [], "name": "ErrorSymbolIsEmpty", "type": "error" }, + { "inputs": [], "name": "ErrorTransferToRebasableContract", "type": "error" }, + { + "inputs": [], + "name": "ErrorZeroAddressL2ERC20TokenBridge", + "type": "error" + }, + { "inputs": [], "name": "ErrorZeroAddressTokenRateOracle", "type": "error" }, + { "inputs": [], "name": "ErrorZeroAddressTokenToWrapFrom", "type": "error" }, + { "inputs": [], "name": "ErrorZeroDecimals", "type": "error" }, + { "inputs": [], "name": "ErrorZeroSharesUnwrap", "type": "error" }, + { "inputs": [], "name": "ErrorZeroSharesWrap", "type": "error" }, + { "inputs": [], "name": "ErrorZeroTokensUnwrap", "type": "error" }, + { "inputs": [], "name": "InvalidContractVersionIncrement", "type": "error" }, + { "inputs": [], "name": "NonZeroContractVersionOnInit", "type": "error" }, + { + "inputs": [ + { "internalType": "uint256", "name": "expected", "type": "uint256" }, + { "internalType": "uint256", "name": "received", "type": "uint256" } + ], + "name": "UnexpectedContractVersion", + "type": "error" + }, + { + "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": false, + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "ContractVersionSet", + "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": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "sharesValue", + "type": "uint256" + } + ], + "name": "TransferShares", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "L2_ERC20_TOKEN_BRIDGE", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_RATE_ORACLE", + "outputs": [ + { + "internalType": "contract ITokenRateOracle", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_RATE_ORACLE_DECIMALS", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "TOKEN_TO_WRAP_FROM", + "outputs": [ + { "internalType": "contract IERC20", "name": "", "type": "address" } + ], + "stateMutability": "view", + "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": "amount_", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account_", "type": "address" } + ], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account_", "type": "address" }, + { "internalType": "uint256", "name": "tokenAmount_", "type": "uint256" } + ], + "name": "bridgeUnwrap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account_", "type": "address" }, + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "bridgeWrap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "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": "getContractVersion", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenAmount_", "type": "uint256" } + ], + "name": "getSharesByTokens", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "getTokensByShares", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTotalShares", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "string", "name": "version_", "type": "string" } + ], + "name": "initialize", + "outputs": [], + "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": [ + { "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": "bytes", "name": "signature_", "type": "bytes" } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "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": "address", "name": "account_", "type": "address" } + ], + "name": "sharesOf", + "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": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "to_", "type": "address" }, + { "internalType": "uint256", "name": "amount_", "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": "amount_", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient_", "type": "address" }, + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "transferShares", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender_", "type": "address" }, + { "internalType": "address", "name": "recipient_", "type": "address" }, + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "transferSharesFrom", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "tokenAmount_", "type": "uint256" } + ], + "name": "unwrap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "unwrapShares", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "sharesAmount_", "type": "uint256" } + ], + "name": "wrap", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/abi/l2-wstesth.abi.json b/abi/l2-wstesth.abi.json new file mode 100644 index 000000000..518cc00c8 --- /dev/null +++ b/abi/l2-wstesth.abi.json @@ -0,0 +1,296 @@ +[ + { + "inputs": [ + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "string", "name": "version_", "type": "string" }, + { "internalType": "uint8", "name": "decimals_", "type": "uint8" }, + { "internalType": "address", "name": "bridge_", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { "inputs": [], "name": "ErrorAccountIsZeroAddress", "type": "error" }, + { "inputs": [], "name": "ErrorDeadlineExpired", "type": "error" }, + { "inputs": [], "name": "ErrorInvalidSignature", "type": "error" }, + { + "inputs": [], + "name": "ErrorMetadataIsAlreadyInitialized", + "type": "error" + }, + { "inputs": [], "name": "ErrorMetadataIsNotInitialized", "type": "error" }, + { "inputs": [], "name": "ErrorNameIsEmpty", "type": "error" }, + { "inputs": [], "name": "ErrorNotBridge", "type": "error" }, + { "inputs": [], "name": "ErrorNotEnoughAllowance", "type": "error" }, + { "inputs": [], "name": "ErrorNotEnoughBalance", "type": "error" }, + { "inputs": [], "name": "ErrorSymbolIsEmpty", "type": "error" }, + { "inputs": [], "name": "ErrorZeroAddressBridge", "type": "error" }, + { "inputs": [], "name": "ErrorZeroDecimals", "type": "error" }, + { "inputs": [], "name": "InvalidContractVersionIncrement", "type": "error" }, + { "inputs": [], "name": "NonZeroContractVersionOnInit", "type": "error" }, + { + "inputs": [ + { "internalType": "uint256", "name": "expected", "type": "uint256" }, + { "internalType": "uint256", "name": "received", "type": "uint256" } + ], + "name": "UnexpectedContractVersion", + "type": "error" + }, + { + "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": false, + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "ContractVersionSet", + "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" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender_", "type": "address" }, + { "internalType": "uint256", "name": "amount_", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bridge", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account_", "type": "address" }, + { "internalType": "uint256", "name": "amount_", "type": "uint256" } + ], + "name": "bridgeBurn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account_", "type": "address" }, + { "internalType": "uint256", "name": "amount_", "type": "uint256" } + ], + "name": "bridgeMint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "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": [ + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "version_", "type": "string" } + ], + "name": "finalizeUpgrade_v2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getContractVersion", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "string", "name": "version_", "type": "string" } + ], + "name": "initialize", + "outputs": [], + "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": [ + { "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": "bytes", "name": "signature_", "type": "bytes" } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "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": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "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": "amount_", "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": "amount_", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/assets/icons/chain-toggler/mainnet.svg b/assets/icons/chain-toggler/mainnet.svg new file mode 100644 index 000000000..892644b07 --- /dev/null +++ b/assets/icons/chain-toggler/mainnet.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/icons/chain-toggler/optimism.svg b/assets/icons/chain-toggler/optimism.svg new file mode 100644 index 000000000..7bb1b5676 --- /dev/null +++ b/assets/icons/chain-toggler/optimism.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/config/get-secret-config.ts b/config/get-secret-config.ts index d992aacc9..4c67c6103 100644 --- a/config/get-secret-config.ts +++ b/config/get-secret-config.ts @@ -11,6 +11,8 @@ export type SecretConfigType = Modify< rpcUrls_1: [string, ...string[]]; rpcUrls_17000: [string, ...string[]]; rpcUrls_11155111: [string, ...string[]]; + + rpcUrls_10: [string, ...string[]]; rpcUrls_11155420: [string, ...string[]]; // Dynamic keys like rpcUrls_ [key: `rpcUrls_${number}`]: string[]; @@ -45,6 +47,11 @@ export const getSecretConfig = (): SecretConfigType => { ], rpcUrls_11155111: (serverRuntimeConfig.rpcUrls_11155111?.split(',') ?? []) as [string, ...string[]], + + rpcUrls_10: (serverRuntimeConfig.rpcUrls_10?.split(',') ?? []) as [ + string, + ...string[], + ], rpcUrls_11155420: (serverRuntimeConfig.rpcUrls_11155420?.split(',') ?? []) as [string, ...string[]], diff --git a/config/groups/web3.ts b/config/groups/web3.ts index 85f00a9c3..57f3bdf32 100644 --- a/config/groups/web3.ts +++ b/config/groups/web3.ts @@ -8,8 +8,17 @@ export const PROVIDER_BATCH_TIME = 150; export const PROVIDER_MAX_BATCH = 20; // account for gas estimation -// will always have >=0.001 ether, >=0.001 stETH, >=0.001 wstETH -// on Mainnet, Holesky +// will always have: +// Balances: +// >=0.001 ether(or native token), >=0.001 stETH, >=0.001 wstETH, +// Contract States: +// >=0.001 stETH allowance to wstETH (L1) +// >=0.001 wsTETH allowance to WQ (L1) +// >=0.001 wsTETH allowance to WQ (L1) +// >=0.001 wsTETH allowance to stETH (L2) +// >=0.001 wsTETH allowance to stETH (L2) + +// on Mainnet, Holesky, Sepolia, Optimism, Optimism Sepolia export const ESTIMATE_ACCOUNT = '0x87c0e047F4e4D3e289A56a36570D4CB957A37Ef1'; export const ESTIMATE_AMOUNT = parseEther('0.001'); diff --git a/config/user-config/types.ts b/config/user-config/types.ts index c16008fb9..e03070156 100644 --- a/config/user-config/types.ts +++ b/config/user-config/types.ts @@ -8,6 +8,7 @@ export type UserConfigDefaultType = { [CHAINS.Holesky]: string[]; [CHAINS.Sepolia]: string[]; [CHAINS.OptimismSepolia]: string[]; + [CHAINS.Optimism]: string[]; }; walletconnectProjectId: string | undefined; }; diff --git a/config/user-config/utils.ts b/config/user-config/utils.ts index 8e1acdd46..937466246 100644 --- a/config/user-config/utils.ts +++ b/config/user-config/utils.ts @@ -16,6 +16,7 @@ export const getUserConfigDefault = (): UserConfigDefaultType => { [CHAINS.Mainnet]: config.prefillUnsafeElRpcUrls1, [CHAINS.Holesky]: config.prefillUnsafeElRpcUrls17000, [CHAINS.Sepolia]: config.prefillUnsafeElRpcUrls11155111, + [CHAINS.Optimism]: config.prefillUnsafeElRpcUrls10, [CHAINS.OptimismSepolia]: config.prefillUnsafeElRpcUrls11155420, }, walletconnectProjectId: config.walletconnectProjectId, diff --git a/consts/chains.ts b/consts/chains.ts index 223641982..1ed6c7c5e 100644 --- a/consts/chains.ts +++ b/consts/chains.ts @@ -1,7 +1,10 @@ +import { LIDO_L2_CONTRACT_ADDRESSES } from '@lidofinance/lido-ethereum-sdk/common'; + export enum CHAINS { Mainnet = 1, Holesky = 17000, Sepolia = 11155111, + Optimism = 10, OptimismSepolia = 11155420, } @@ -25,10 +28,7 @@ export const SDK_LEGACY_SUPPORTED_CHAINS = [ CHAINS.Sepolia, ]; -// TODO: move to @lidofinance/lido-ethereum-sdk package -export const SDK_SUPPORTED_MULTICHAIN_CHAINS = [CHAINS.OptimismSepolia]; - // TODO: move to @lidofinance/lido-ethereum-sdk package export const isSDKSupportedL2Chain = (chainId: CHAINS) => { - return SDK_SUPPORTED_MULTICHAIN_CHAINS.indexOf(chainId) > -1; + return !!LIDO_L2_CONTRACT_ADDRESSES[chainId]; }; diff --git a/consts/matomo-click-events.ts b/consts/matomo-click-events.ts index 91f34032c..d8042113c 100644 --- a/consts/matomo-click-events.ts +++ b/consts/matomo-click-events.ts @@ -35,10 +35,17 @@ export const enum MATOMO_CLICK_EVENTS_TYPES { faqHowCanIUnstakeStEthIntegrations = 'faqHowCanIUnstakeStEthIntegrations', faqHowCanIGetWstethWrapLink = 'faqHowCanIGetWstethWrapLink', faqHowCanIGetWstethIntegrationsLink = 'faqHowCanIGetWstethIntegrationsLink', + faqHowCanIGetWstethOnOptimismWrapLink = 'faqHowCanIGetWstethOnOptimismWrapLink', + faqHowCanIGetWstethOnOptimismBridgeYourWstETHFromEthereumToOptimism = 'faqHowCanIGetWstethOnOptimismBridgeYourWstETHFromEthereumToOptimism', + faqHowCanIGetWstethOnOptimismIntegrations = 'faqHowCanIGetWstethOnOptimismIntegrations', faqHowDoIUnwrapWstethUnwrapLink = 'faqHowDoIUnwrapWstethUnwrapLink', faqHowCanIUseWstethLidoMultichain = 'faqHowCanIUseWstethLidoMultichain', faqHowCanIUseWstethDefiProtocols = 'faqHowCanIUseWstethDefiProtocols', + faqHowCanIUseWstethOnOptimismDefiProtocols = 'faqHowCanIUseWstethOnOptimismDefiProtocols', faqDoINeedToUnwrapMyWstethWithdrawalsTabs = 'faqDoINeedToUnwrapMyWstethWithdrawalsTabs', + faqHowCouldIUnwrapWstETHBackToStETHOnOptimismUnwrapLink = 'faqHowCouldIUnwrapWstETHBackToStETHOnOptimismUnwrapLink', + faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismBridgeYourWstETHOrStETHBack = 'faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismBridgeYourWstETHOrStETHBack', + faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismWithdrawalsRequestAndClaim = 'faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismWithdrawalsRequestAndClaim', // /wrap page wrapTokenSelectSTETH = 'wrapTokenSelectSteth', wrapTokenSelectETH = 'wrapTokenSelectEth', @@ -237,6 +244,22 @@ export const MATOMO_CLICK_EVENTS: Record< 'Push «DEX Lido integrations» in FAQ How can I get wstETH', 'eth_widget_faq_howgetwsteth_dexLidoIntegrations', ], + [MATOMO_CLICK_EVENTS_TYPES.faqHowCanIGetWstethOnOptimismWrapLink]: [ + 'Ethereum_Staking_Widget', + 'Push «Wrap & Unwrap staking widget» in FAQ How can I get wstETH (Optimism)', + 'eth_widget_faq_howgetwsteth_wrap_optimism', + ], + [MATOMO_CLICK_EVENTS_TYPES.faqHowCanIGetWstethOnOptimismBridgeYourWstETHFromEthereumToOptimism]: + [ + 'Ethereum_Staking_Widget', + 'Push «bridge your wstETH from Ethereum to Optimism» in How can I get wstETH on Optimism?', + 'eth_widget_faq_howCanIGetWstethOnOptimism_bridgeYourWstETHFromEthereumToOptimism', + ], + [MATOMO_CLICK_EVENTS_TYPES.faqHowCanIGetWstethOnOptimismIntegrations]: [ + 'Ethereum_Staking_Widget', + 'Push «DEX Lido integrations» in FAQ How can I get wstETH (Optimism)', + 'eth_widget_faq_howgetwsteth_dexLidoIntegrations_optimism', + ], [MATOMO_CLICK_EVENTS_TYPES.faqHowDoIUnwrapWstethUnwrapLink]: [ 'Ethereum_Staking_Widget', 'Push «stake.lido.fi/wrap/unwrap» How do I unwrap wstETH back to stETH?', @@ -247,6 +270,11 @@ export const MATOMO_CLICK_EVENTS: Record< 'Push «L2» How can I use wstETH?', // L2 naiming for analytics history consistency 'eth_widget_faq_howCanIUseWstETH_l2', // L2 naiming for analytics history consistency ], + [MATOMO_CLICK_EVENTS_TYPES.faqHowCanIUseWstethOnOptimismDefiProtocols]: [ + 'Ethereum_Staking_Widget', + 'Push «L2» How can I use wstETH? (Optimism)', + 'eth_widget_faq_howCanIUseWstETH_l2_optimism', + ], [MATOMO_CLICK_EVENTS_TYPES.faqHowCanIUseWstethDefiProtocols]: [ 'Ethereum_Staking_Widget', 'Push «DeFi protocols» How can I use wstETH?', @@ -257,6 +285,24 @@ export const MATOMO_CLICK_EVENTS: Record< 'Push «Withdrawals Request and Claim tabs» Do I need to unwrap my wstETH before requesting withdrawals?', 'eth_widget_faq_doINeedToUnwrapMyWsteth_withdrawalsRequestAndClaimTabs', ], + [MATOMO_CLICK_EVENTS_TYPES.faqHowCouldIUnwrapWstETHBackToStETHOnOptimismUnwrapLink]: + [ + 'Ethereum_Staking_Widget', + 'Push «Wrap & Unwrap staking widget» How could I unwrap wstETH back to stETH on Optimism?', + 'eth_widget_faq_howCouldIUnwrapWstETHBackToStETHOnOptimismUnwrapLink', + ], + [MATOMO_CLICK_EVENTS_TYPES.faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismBridgeYourWstETHOrStETHBack]: + [ + 'Ethereum_Staking_Widget', + 'Push «bridge your wstETH or stETH back» What happens if I want to unstake ETH on Ethereum? Can I do that from Optimism?', + 'eth_widget_faq_WhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismBridgeYourWstETHOrStETHBack', + ], + [MATOMO_CLICK_EVENTS_TYPES.faqWhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismWithdrawalsRequestAndClaim]: + [ + 'Ethereum_Staking_Widget', + 'Push «Withdrawals Request and Claim» What happens if I want to unstake ETH on Ethereum? Can I do that from Optimism?', + 'eth_widget_faq_WhatHappensIfIWantToUnstakeETHOnEthereumCanIDoThatFromOptimismWithdrawalsRequestAndClaim', + ], // /wrap page [MATOMO_CLICK_EVENTS_TYPES.wrapTokenSelectETH]: [ 'Ethereum_Staking_Widget', diff --git a/consts/tx.ts b/consts/tx.ts index a2dd7c3dc..d011e0e6f 100644 --- a/consts/tx.ts +++ b/consts/tx.ts @@ -1,7 +1,11 @@ import { BigNumber } from 'ethers'; export const WSTETH_APPROVE_GAS_LIMIT = BigNumber.from(78000); +export const STETH_L2_APPROVE_GAS_LIMIT = BigNumber.from(52500); export const WRAP_FROM_ETH_GAS_LIMIT = BigNumber.from(100000); export const WRAP_GAS_LIMIT = BigNumber.from(140000); +export const WRAP_L2_GAS_LIMIT = BigNumber.from(95500); + export const UNWRAP_GAS_LIMIT = BigNumber.from(115000); +export const UNWRAP_L2_GAS_LIMIT = BigNumber.from(77500); diff --git a/env-dynamics.mjs b/env-dynamics.mjs index 3c273329d..bb05b97a6 100644 --- a/env-dynamics.mjs +++ b/env-dynamics.mjs @@ -53,6 +53,8 @@ export const prefillUnsafeElRpcUrls17000 = process.env.PREFILL_UNSAFE_EL_RPC_URL /** @type string[] */ export const prefillUnsafeElRpcUrls11155111 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_11155111?.split(',') ?? []; /** @type string[] */ +export const prefillUnsafeElRpcUrls10 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_10?.split(',') ?? []; +/** @type string[] */ export const prefillUnsafeElRpcUrls11155420 = process.env.PREFILL_UNSAFE_EL_RPC_URLS_11155420?.split(',') ?? []; /** @type boolean */ diff --git a/features/rewards/components/IndexerLink.tsx b/features/rewards/components/IndexerLink.tsx index 2f05fd919..b2a064ab7 100644 --- a/features/rewards/components/IndexerLink.tsx +++ b/features/rewards/components/IndexerLink.tsx @@ -1,5 +1,5 @@ import { Box, External as ExternalLinkIcon } from '@lidofinance/lido-ui'; -import { getEtherscanTxLink } from '@lido-sdk/helpers'; +import { getEtherscanTxLink } from 'utils/get-etherscan-tx-link'; import { config } from 'config'; diff --git a/features/rewards/components/rewardsListContent/RewardsListContent.tsx b/features/rewards/components/rewardsListContent/RewardsListContent.tsx index b7c8ad636..db6be73b6 100644 --- a/features/rewards/components/rewardsListContent/RewardsListContent.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListContent.tsx @@ -20,7 +20,8 @@ import { import type { Address } from 'viem'; export const RewardsListContent: FC = () => { - const { isWalletConnected, isSupportedChain } = useDappStatus(); + const { isWalletConnected, isSupportedChain, isAccountActiveOnL2 } = + useDappStatus(); const { address, error, @@ -38,7 +39,7 @@ export const RewardsListContent: FC = () => { }); const hasSteth = stethBalance?.gt(Zero); - if (isWalletConnected && !isSupportedChain) + if ((isWalletConnected && !isSupportedChain) || isAccountActiveOnL2) return ; if (!data && !initialLoading && !error) return ; diff --git a/features/rewards/components/rewardsListContent/RewardsListsUnsupportedChain.tsx b/features/rewards/components/rewardsListContent/RewardsListsUnsupportedChain.tsx index 9f5aaa755..f184685eb 100644 --- a/features/rewards/components/rewardsListContent/RewardsListsUnsupportedChain.tsx +++ b/features/rewards/components/rewardsListContent/RewardsListsUnsupportedChain.tsx @@ -1,4 +1,4 @@ -import { FC, useMemo } from 'react'; +import { FC } from 'react'; import { Divider } from '@lidofinance/lido-ui'; import { useConfig } from 'config'; @@ -7,23 +7,15 @@ import { RewardsListEmptyWrapper } from './RewardsListsEmptyStyles'; export const RewardsListsUnsupportedChain: FC = () => { const { - config: { supportedChains }, + config: { defaultChain }, } = useConfig(); - const supportedChainsNames = useMemo(() => { - // 'Chain ID' array to 'Chain name' array exclude unknown chain id - const chains = supportedChains.map((id) => CHAINS[id]).filter(Boolean); - const lastChain = chains.pop(); - // to str - return [chains.join(', '), lastChain].filter((chain) => chain).join(' or '); - }, [supportedChains]); - return ( <>

- Please switch to {supportedChainsNames} in your wallet to see the + Please switch to {CHAINS[defaultChain]} in your wallet to see the stats.

diff --git a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx index a1d4a1587..9eb952940 100644 --- a/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx +++ b/features/rewards/components/rewardsListHeader/RewardsListHeader.tsx @@ -8,7 +8,8 @@ import { RewardsListHeaderStyle } from './styles'; import { TitleStyle } from './styles'; export const RewardsListHeader: FC = () => { - const { isWalletConnected, isSupportedChain } = useDappStatus(); + const { isWalletConnected, isSupportedChain, isAccountActiveOnL2 } = + useDappStatus(); const { error, data } = useRewardsHistory(); return ( @@ -17,7 +18,9 @@ export const RewardsListHeader: FC = () => { {!error && data && data?.events.length > 0 && - (!isWalletConnected || (isWalletConnected && isSupportedChain)) && ( + (!isWalletConnected || + (isWalletConnected && isSupportedChain) || + !isAccountActiveOnL2) && ( <> diff --git a/features/rewards/features/top-card/top-card.tsx b/features/rewards/features/top-card/top-card.tsx index 2e44058a5..46ffd394c 100644 --- a/features/rewards/features/top-card/top-card.tsx +++ b/features/rewards/features/top-card/top-card.tsx @@ -1,5 +1,7 @@ import { FC, useEffect, useState } from 'react'; +import { CHAINS } from '@lido-sdk/constants'; +import { getConfig } from 'config'; import { StatsWrapper } from 'features/rewards/components/statsWrapper'; import { Stats } from 'features/rewards/components/stats'; import { useDappStatus } from 'shared/hooks/use-dapp-status'; @@ -8,8 +10,10 @@ import { Fallback } from 'shared/wallet'; import { Wallet } from './wallet'; export const TopCard: FC = () => { + const { defaultChain } = getConfig(); const [visible, setVisible] = useState(false); - const { isWalletConnected, isSupportedChain } = useDappStatus(); + const { isWalletConnected, isSupportedChain, isAccountActiveOnL2 } = + useDappStatus(); // fix flash after reload page useEffect(() => { @@ -20,7 +24,17 @@ export const TopCard: FC = () => { return ( <> - {isWalletConnected && !isSupportedChain ? : } + {isWalletConnected && !isSupportedChain ? ( + + ) : isAccountActiveOnL2 ? ( + + ) : ( + + )} diff --git a/features/stake/stake-form/controls/stake-amount-input.tsx b/features/stake/stake-form/controls/stake-amount-input.tsx index 00579d707..58a307a9c 100644 --- a/features/stake/stake-form/controls/stake-amount-input.tsx +++ b/features/stake/stake-form/controls/stake-amount-input.tsx @@ -5,7 +5,8 @@ import { useStakingLimitWarning } from 'shared/hooks/use-staking-limit-warning'; import { useDappStatus } from 'shared/hooks/use-dapp-status'; export const StakeAmountInput = () => { - const { isWalletConnected, isDappActive, isDappActiveOnL2 } = useDappStatus(); + const { isWalletConnected, isDappActive, isAccountActiveOnL2 } = + useDappStatus(); const { maxAmount, stakingLimitInfo } = useStakeFormData(); const { limitWarning, limitError } = useStakingLimitWarning( stakingLimitInfo?.stakeLimitLevel, @@ -13,7 +14,7 @@ export const StakeAmountInput = () => { return ( { - const { isDappActive, isDappActiveOnL2 } = useDappStatus(); + const { isDappActive, isAccountActiveOnL2 } = useDappStatus(); const { stakingLimitInfo } = useStakeFormData(); return ( { const { address } = useAccount(); @@ -98,13 +100,30 @@ const WalletComponent: WalletComponentType = (props) => { }; export const Wallet: WalletComponentType = memo((props) => { - const { isDappActive } = useDappStatus(); + const { defaultChain } = getConfig(); + const { isWalletConnected, isDappActive, isAccountActiveOnL2 } = + useDappStatus(); const { showLidoMultichainFallback } = useLidoMultichainFallbackCondition(); if (showLidoMultichainFallback) { return ; } + if (isAccountActiveOnL2) { + return ( + + ); + } + + if (isWalletConnected && !isDappActive) { + return ( + + ); + } + if (!isDappActive) { return ; } diff --git a/features/withdrawals/claim/form/requests-list/requests-list.tsx b/features/withdrawals/claim/form/requests-list/requests-list.tsx index 1e7ed79e8..8bb23403c 100644 --- a/features/withdrawals/claim/form/requests-list/requests-list.tsx +++ b/features/withdrawals/claim/form/requests-list/requests-list.tsx @@ -8,7 +8,7 @@ import { Wrapper } from './styles'; import { RequestsLoader } from './requests-loader'; export const RequestsList: React.FC = () => { - const { isWalletConnected, isDappActive } = useDappStatus(); + const { isWalletConnected, isDappActiveOnL1 } = useDappStatus(); const { isLoading } = useFormState(); const { register } = useFormContext(); const { fields } = useFieldArray({ @@ -19,11 +19,11 @@ export const RequestsList: React.FC = () => { return ; } - if (!isDappActive || fields.length === 0) { + if (!isDappActiveOnL1 || fields.length === 0) { return ( ); } diff --git a/features/withdrawals/claim/form/submit-button.tsx b/features/withdrawals/claim/form/submit-button.tsx index f294a5c1d..2d74e0a6a 100644 --- a/features/withdrawals/claim/form/submit-button.tsx +++ b/features/withdrawals/claim/form/submit-button.tsx @@ -3,14 +3,16 @@ import { useAccount } from 'wagmi'; import { Button } from '@lidofinance/lido-ui'; import { Zero } from '@ethersproject/constants'; -import { Connect, UnsupportedChainButton } from 'shared/wallet'; +import { Connect, DisabledButton } from 'shared/wallet'; import { FormatToken } from 'shared/formatters/format-token'; +import { useDappStatus } from 'shared/hooks/use-dapp-status'; import { useIsSupportedChain } from 'shared/hooks/use-is-supported-chain'; import { isValidationErrorTypeUnhandled } from 'shared/hook-form/validation/validation-error'; import { ClaimFormInputType, useClaimFormData } from '../claim-form-context'; export const SubmitButton = () => { + const { isAccountActiveOnL2 } = useDappStatus(); const { isConnected } = useAccount(); const isSupportedChain = useIsSupportedChain(); @@ -21,19 +23,19 @@ export const SubmitButton = () => { if (!isConnected) return ; - if (!isSupportedChain) { - return ; + if (!isSupportedChain || isAccountActiveOnL2) { + return Claim; } - const claimButtonAmount = ethToClaim.lte(Zero) ? null : ( - - ); - const disabled = (!!errors.requests && !isValidationErrorTypeUnhandled(errors.requests.type)) || selectedRequests.length === 0; + const claimButtonAmount = ethToClaim.lte(Zero) ? null : ( + + ); + return (