diff --git a/.gitignore b/.gitignore index 3151b1ec..e2689d2a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,8 @@ dist-ssr *.njsproj *.sln *.sw? +.zed/* +yarn.lock .env .env.local diff --git a/package.json b/package.json index 4eacb7c3..86149fb6 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "preview": "vite preview" }, "dependencies": { - "@lifi/widget": "^3.0.0", + "@ethersproject/bignumber": "^5.7.0", "@radix-ui/react-accordion": "^1.2.0", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-popover": "^1.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8aa078a8..5664848c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,9 @@ importers: .: dependencies: - '@lifi/widget': - specifier: ^3.0.0 - version: 3.0.0(jjnkyh6cyrxgxf254wfk2drkny) + '@ethersproject/bignumber': + specifier: ^5.7.0 + version: 5.7.0 '@radix-ui/react-accordion': specifier: ^1.2.0 version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -968,75 +968,15 @@ packages: '@coinbase/wallet-sdk@4.0.4': resolution: {integrity: sha512-74c040CRnGhfRjr3ArnkAgud86erIqdkPHNt5HR1k9u97uTIZCJww9eGYT67Qf7gHPpGS/xW8Be1D4dvRm63FA==} - '@emotion/babel-plugin@11.12.0': - resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} - - '@emotion/cache@11.11.0': - resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==} - - '@emotion/cache@11.13.1': - resolution: {integrity: sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==} - '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} '@emotion/is-prop-valid@1.3.0': resolution: {integrity: sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==} - '@emotion/memoize@0.8.1': - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} - '@emotion/memoize@0.9.0': resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - '@emotion/react@11.11.4': - resolution: {integrity: sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==} - peerDependencies: - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@types/react': - optional: true - - '@emotion/serialize@1.3.0': - resolution: {integrity: sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==} - - '@emotion/sheet@1.2.2': - resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==} - - '@emotion/sheet@1.4.0': - resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} - - '@emotion/styled@11.11.5': - resolution: {integrity: sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==} - peerDependencies: - '@emotion/react': ^11.0.0-rc.0 - '@types/react': '*' - react: '>=16.8.0' - peerDependenciesMeta: - '@types/react': - optional: true - - '@emotion/unitless@0.9.0': - resolution: {integrity: sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==} - - '@emotion/use-insertion-effect-with-fallbacks@1.1.0': - resolution: {integrity: sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==} - peerDependencies: - react: '>=16.8.0' - - '@emotion/utils@1.2.1': - resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} - - '@emotion/utils@1.4.0': - resolution: {integrity: sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==} - - '@emotion/weak-memoize@0.3.1': - resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==} - - '@emotion/weak-memoize@0.4.0': - resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild/aix-ppc64@0.21.5': resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -1209,6 +1149,15 @@ packages: resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} engines: {node: '>=14'} + '@ethersproject/bignumber@5.7.0': + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + + '@ethersproject/bytes@5.7.0': + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + + '@ethersproject/logger@5.7.0': + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + '@floating-ui/core@1.6.4': resolution: {integrity: sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==} @@ -1301,50 +1250,6 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@lifi/sdk@3.0.0': - resolution: {integrity: sha512-Xinus12HOlQqJm/tdl3uNt0/Mp2+x3lK5cFPo2OsfLHmWirtc+tax1ExlUcDq5+ODURwKUrbo9WisHqa8DB1uA==} - peerDependencies: - '@solana/wallet-adapter-base': ^0.9.0 - '@solana/web3.js': ^1.93.0 - viem: ^2.16.0 - - '@lifi/types@13.18.2': - resolution: {integrity: sha512-LbAzsW9wWLwpgSWyf+WpJCKBfa3DwP9G40alKYx7AWn/EW90ulDahloxRiR5xID/JS7deP6IeR7ZQnU1IF/8TA==} - - '@lifi/wallet-management@3.0.0': - resolution: {integrity: sha512-LRvfUFN4y8NhgAfyTHVyYL3lUeAwsG1ojIFZy1IlSO1xec8aTFlt7JHE8bYe6cM97WfTRnmBfTexxwLG6lwOWw==} - peerDependencies: - '@lifi/sdk': ^3.0.0 - '@tanstack/react-query': ^5.0.0 - viem: ^2.16.0 - wagmi: ^2.10.0 - - '@lifi/widget@3.0.0': - resolution: {integrity: sha512-TzWXmoNbk0fbQNsMDSw7Rn8kJQnfO2BNrhMIWNY/0fTN69TmjAiM76j2+Qhz2JYNi89b8xYUboXd324zsY1K2A==} - peerDependencies: - '@emotion/react': ^11.11.0 - '@emotion/styled': ^11.11.0 - '@lifi/sdk': ^3.0.0 - '@lifi/wallet-management': ^3.0.0 - '@mui/icons-material': ^5.15.0 - '@mui/material': ^5.15.0 - '@solana/wallet-adapter-base': ^0.9.0 - '@solana/wallet-adapter-react': ^0.15.0 - '@solana/web3.js': ^1.93.0 - '@tanstack/react-query': ^5.17.0 - '@types/react': ^18.2.0 - i18next: ^23.11.0 - react: ^18.2.0 - react-dom: ^18.2.0 - react-i18next: ^14.1.0 - react-router-dom: ^6.22.0 - viem: ^2.16.0 - wagmi: ^2.10.0 - zustand: ^4.5.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@lit-labs/ssr-dom-shim@1.2.1': resolution: {integrity: sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ==} @@ -1471,189 +1376,12 @@ packages: resolution: {integrity: sha512-z10PF9JV6SbjFq+/rYabM+8CVlMokgl8RFGvieSGNTmrkQanfHn+15XBrhG3BgUfvmTeSeyShfOHpG0i9zEdcg==} deprecated: Motion One for Vue is deprecated. Use Oku Motion instead https://oku-ui.com/motion - '@mui/base@5.0.0-beta.40': - resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/core-downloads-tracker@5.16.7': - resolution: {integrity: sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==} - - '@mui/icons-material@5.15.21': - resolution: {integrity: sha512-yqkq1MbdkmX5ZHyvZTBuAaA6RkvoqkoAgwBSx9Oh0L0jAfj9T/Ih/NhMNjkl8PWVSonjfDUkKroBnjRyo/1M9Q==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@mui/material': ^5.0.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/lab@5.0.0-alpha.170': - resolution: {integrity: sha512-0bDVECGmrNjd3+bLdcLiwYZ0O4HP5j5WSQm5DV6iA/Z9kr8O6AnvZ1bv9ImQbbX7Gj3pX4o43EKwCutj3EQxQg==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@mui/material': '>=5.15.0' - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/material@5.15.21': - resolution: {integrity: sha512-nTyCcgduKwHqiuQ/B03EQUa+utSMzn2sQp0QAibsnYe4tvc3zkMbO0amKpl48vhABIY3IvT6w9615BFIgMt0YA==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/private-theming@5.15.20': - resolution: {integrity: sha512-BK8F94AIqSrnaPYXf2KAOjGZJgWfvqAVQ2gVR3EryvQFtuBnG6RwodxrCvd3B48VuMy6Wsk897+lQMUxJyk+6g==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/private-theming@5.16.6': - resolution: {integrity: sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/styled-engine@5.15.14': - resolution: {integrity: sha512-RILkuVD8gY6PvjZjqnWhz8fu68dVkqhM5+jYWfB5yhlSQKg+2rHkmEwm75XIeAqI3qwOndK6zELK5H6Zxn4NHw==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.4.1 - '@emotion/styled': ^11.3.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - - '@mui/styled-engine@5.16.6': - resolution: {integrity: sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.4.1 - '@emotion/styled': ^11.3.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - - '@mui/system@5.15.20': - resolution: {integrity: sha512-LoMq4IlAAhxzL2VNUDBTQxAb4chnBe8JvRINVNDiMtHE2PiPOoHlhOPutSxEbaL5mkECPVWSv6p8JEV+uykwIA==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/system@5.16.7': - resolution: {integrity: sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@emotion/react': ^11.5.0 - '@emotion/styled': ^11.3.0 - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@emotion/react': - optional: true - '@emotion/styled': - optional: true - '@types/react': - optional: true - - '@mui/types@7.2.14': - resolution: {integrity: sha512-MZsBZ4q4HfzBsywtXgM1Ksj6HDThtiwmOKUXH1pKYISI9gAVXCNHNpo7TlGoGrBaYWZTdNoirIN7JsQcQUjmQQ==} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/types@7.2.15': - resolution: {integrity: sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/utils@5.15.20': - resolution: {integrity: sha512-mAbYx0sovrnpAu1zHc3MDIhPqL8RPVC5W5xcO1b7PiSCJPtckIZmBkp8hefamAvUiAV8gpfMOM6Zb+eSisbI2A==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - '@mui/utils@5.16.6': - resolution: {integrity: sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==} - engines: {node: '>=12.0.0'} - peerDependencies: - '@types/react': ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@noble/curves@1.4.0': resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} '@noble/curves@1.4.2': resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - '@noble/curves@1.5.0': - resolution: {integrity: sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==} - '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} @@ -1756,9 +1484,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@radix-ui/number@1.1.0': resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} @@ -2258,10 +1983,6 @@ packages: '@types/react': optional: true - '@remix-run/router@1.17.1': - resolution: {integrity: sha512-mCOMec4BKd6BRGBZeSnGiIgwsbLGp3yhVqAD8H+PxiRNEHgDpZb8J1TnrSDlg97t0ySKMQJTHCWBCmBpSmkF6Q==} - engines: {node: '>=14.0.0'} - '@rnx-kit/chromium-edge-launcher@1.0.0': resolution: {integrity: sha512-lzD84av1ZQhYUS+jsGqJiCMaJO2dn9u+RTT9n9q6D3SaKVwWqv+7AoRKqBu19bkwyE+iFRl1ymr40QS90jVFYg==} engines: {node: '>=14.15'} @@ -2395,80 +2116,6 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@solana-mobile/mobile-wallet-adapter-protocol-web3js@2.1.3': - resolution: {integrity: sha512-IEvPzp4m39sWTS3gybbVfk1WQ5Bx9TrGlthtRlVw1BJPvjbmT6lTcnndgXp7HmMkz5e6cc8fwJWp3EKx5upAug==} - peerDependencies: - '@solana/web3.js': ^1.58.0 - - '@solana-mobile/mobile-wallet-adapter-protocol@2.1.3': - resolution: {integrity: sha512-rj1/cSQVjPYdQjHsJDxmlpgRjI9jly/0Md3bEeqCan2sLXPf5F6+TiVlAg9+Hxg+uVWd1peUrepFUdOykbklSw==} - peerDependencies: - '@solana/web3.js': ^1.58.0 - react-native: '>0.69' - - '@solana-mobile/wallet-adapter-mobile@2.1.3': - resolution: {integrity: sha512-V9gxV7/F1BLode6I+j134kFvQv1mnF0OlN+tYPHEmJOcH4caDfH6rlJy7t9Pktkl9ZEVTO9kT8K19Y4MRl6nxg==} - peerDependencies: - '@solana/web3.js': ^1.58.0 - - '@solana/buffer-layout@4.0.1': - resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} - engines: {node: '>=5.10'} - - '@solana/wallet-adapter-base@0.9.23': - resolution: {integrity: sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.77.3 - - '@solana/wallet-adapter-react@0.15.35': - resolution: {integrity: sha512-i4hc/gNLTYNLMEt2LS+4lrrc0QAwa5SU2PtYMnZ2A3rsoKF5m1bv1h6cjLj2KBry4/zRGEBoqkiMOC5zHkLnRQ==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.77.3 - react: '*' - - '@solana/wallet-standard-chains@1.1.0': - resolution: {integrity: sha512-IRJHf94UZM8AaRRmY18d34xCJiVPJej1XVwXiTjihHnmwD0cxdQbc/CKjrawyqFyQAKJx7raE5g9mnJsAdspTg==} - engines: {node: '>=16'} - - '@solana/wallet-standard-core@1.1.1': - resolution: {integrity: sha512-DoQ5Ryly4GAZtxRUmW2rIWrgNvTYVCWrFCFFjZI5s4zu2QNsP7sHZUax3kc1GbmFLXNL1FWRZlPOXRs6e0ZEng==} - engines: {node: '>=16'} - - '@solana/wallet-standard-features@1.2.0': - resolution: {integrity: sha512-tUd9srDLkRpe1BYg7we+c4UhRQkq+XQWswsr/L1xfGmoRDF47BPSXf4zE7ZU2GRBGvxtGt7lwJVAufQyQYhxTQ==} - engines: {node: '>=16'} - - '@solana/wallet-standard-util@1.1.1': - resolution: {integrity: sha512-dPObl4ntmfOc0VAGGyyFvrqhL8UkHXmVsgbj0K9RcznKV4KB3MgjGwzo8CTSX5El5lkb0rDeEzFqvToJXRz3dw==} - engines: {node: '>=16'} - - '@solana/wallet-standard-wallet-adapter-base@1.1.2': - resolution: {integrity: sha512-DqhzYbgh3disHMgcz6Du7fmpG29BYVapNEEiL+JoVMa+bU9d4P1wfwXUNyJyRpGGNXtwhyZjIk2umWbe5ZBNaQ==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.58.0 - bs58: ^4.0.1 - - '@solana/wallet-standard-wallet-adapter-react@1.1.2': - resolution: {integrity: sha512-bN6W4QkzenyjUoUz3sC5PAed+z29icGtPh9VSmLl1ZrRO7NbFB49a8uwUUVXNxhL/ZbMsyVKhb9bNj47/p8uhQ==} - engines: {node: '>=16'} - peerDependencies: - '@solana/wallet-adapter-base': '*' - react: '*' - - '@solana/wallet-standard-wallet-adapter@1.1.2': - resolution: {integrity: sha512-lCwoA+vhPfmvjcmJOhSRV94wouVWTfJv1Z7eeULAe+GodCeKA/0T9/uBYgXHUxQjLHd7o8LpLYIkfm+xjA5sMA==} - engines: {node: '>=16'} - - '@solana/wallet-standard@1.1.2': - resolution: {integrity: sha512-o7wk+zr5/QgyE393cGRC04K1hacR4EkBu3MB925ddaLvCVaXjwr2asgdviGzN9PEm3FiEJp3sMmMKYHFnwOITQ==} - engines: {node: '>=16'} - - '@solana/web3.js@1.94.0': - resolution: {integrity: sha512-wMiBebzu5I2fTSz623uj6VXpWFhl0d7qJKqPFK2I4IBLTNUdv+bOeA4H7OBM7Gworv7sOvB3xibRql6l61MeqA==} - '@stablelib/aead@1.0.1': resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} @@ -2591,9 +2238,6 @@ packages: peerDependencies: '@svgr/core': '*' - '@swc/helpers@0.5.12': - resolution: {integrity: sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==} - '@tanstack/eslint-plugin-query@5.51.12': resolution: {integrity: sha512-vzUXXIVzDP2c6wVSJ+1imPGaKQ2ILuWnta64FJc/JnQ5WunfO17bQJSk6uKDbzTQG/YKgPYBMG3C9qFA4b7Ayg==} peerDependencies: @@ -2633,12 +2277,6 @@ packages: react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 - '@tanstack/react-virtual@3.8.1': - resolution: {integrity: sha512-dP5a7giEM4BQWLJ7K07ToZv8rF51mzbrBMkf0scg1QNYuFx3utnPUBPUHdzaowZhIez1K2XS78amuzD+YGRA5Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@tanstack/router-devtools@1.43.10': resolution: {integrity: sha512-v6fi0U2r/VCN8vwukSjVRaM3anYI8QLqhfK++DuaABZBX2e9cTkmBCzMhA9e5J1bbuh7Zv1efh3GLuKdURqK7g==} engines: {node: '>=12'} @@ -2669,9 +2307,6 @@ packages: '@tanstack/store@0.5.5': resolution: {integrity: sha512-EOSrgdDAJExbvRZEQ/Xhh9iZchXpMN+ga1Bnk8Nmygzs8TfiE6hbzThF+Pr2G19uHL6+DTDTHhJ8VQiOd7l4tA==} - '@tanstack/virtual-core@3.8.1': - resolution: {integrity: sha512-uNtAwenT276M9QYCjTBoHZ8X3MUeCRoGK59zPi92hMIxdfS9AyHjkDWJ94WroDxnv48UE+hIeo21BU84jKc8aQ==} - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2684,9 +2319,6 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -2714,27 +2346,18 @@ packages: '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@18.19.44': resolution: {integrity: sha512-ZsbGerYg72WMXUIE9fYxtvfzLEuq6q8mKERdWFnqTmOvudMxnz+CBNRoOwJ2kNpFOncrKjT1hZwxjlFgQ9qvQA==} '@types/node@22.2.0': resolution: {integrity: sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==} - '@types/parse-json@4.0.2': - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} - '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} '@types/react-dom@18.3.0': resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - '@types/react-transition-group@4.4.11': - resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} - '@types/react@18.3.3': resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} @@ -2747,15 +2370,6 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@types/uuid@8.3.4': - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - - '@types/ws@7.4.7': - resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} - - '@types/ws@8.5.12': - resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} - '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -2934,26 +2548,6 @@ packages: typescript: optional: true - '@wallet-standard/app@1.0.1': - resolution: {integrity: sha512-LnLYq2Vy2guTZ8GQKKSXQK3+FRGPil75XEdkZqE6fiLixJhZJoJa5hT7lXxwe0ykVTt9LEThdTbOpT7KadS26Q==} - engines: {node: '>=16'} - - '@wallet-standard/base@1.0.1': - resolution: {integrity: sha512-1To3ekMfzhYxe0Yhkpri+Fedq0SYcfrOfJi3vbLjMwF2qiKPjTGLwZkf2C9ftdQmxES+hmxhBzTwF4KgcOwf8w==} - engines: {node: '>=16'} - - '@wallet-standard/core@1.0.3': - resolution: {integrity: sha512-Jb33IIjC1wM1HoKkYD7xQ6d6PZ8EmMZvyc8R7dFgX66n/xkvksVTW04g9yLvQXrLFbcIjHrCxW6TXMhvpsAAzg==} - engines: {node: '>=16'} - - '@wallet-standard/features@1.0.3': - resolution: {integrity: sha512-m8475I6W5LTatTZuUz5JJNK42wFRgkJTB0I9tkruMwfqBF2UN2eomkYNVf9RbrsROelCRzSFmugqjKZBFaubsA==} - engines: {node: '>=16'} - - '@wallet-standard/wallet@1.0.1': - resolution: {integrity: sha512-qkhJeuQU2afQTZ02yMZE5SFc91Fo3hyFjFkpQglHudENNyiSG0oUKcIjky8X32xVSaumgTZSQUAzpXnCTWHzKQ==} - engines: {node: '>=16'} - '@walletconnect/core@2.14.0': resolution: {integrity: sha512-E/dgBM9q3judXnTfZQ5ILvDpeSdDpabBLsXtYXa3Nyc26cfNplfLJ2nXm9FgtTdhM1nZ7yx4+zDPiXawBRZl2g==} @@ -3034,10 +2628,6 @@ packages: '@walletconnect/window-metadata@1.0.1': resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} - JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true - abitype@1.0.5: resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} peerDependencies: @@ -3067,10 +2657,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - agentkeepalive@4.5.0: - resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} - engines: {node: '>= 8.0.0'} - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -3213,10 +2799,6 @@ packages: babel-dead-code-elimination@1.0.6: resolution: {integrity: sha512-JxFi9qyRJpN0LjEbbjbN8g0ux71Qppn9R8Qe3k6QzHg2CaKsbUQtbn307LQGiDLGjV6JCtEFqfxzVig9MyDCHQ==} - babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} - babel-plugin-polyfill-corejs2@0.4.11: resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: @@ -3238,26 +2820,13 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base-x@3.0.10: - resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} - - base-x@4.0.0: - resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} - base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} - binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -3267,9 +2836,6 @@ packages: bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - borsh@0.7.0: - resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} - bowser@2.11.0: resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} @@ -3296,12 +2862,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - - bs58@5.0.0: - resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} - bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -3504,9 +3064,6 @@ packages: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} - convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -3523,10 +3080,6 @@ packages: resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} engines: {node: '>=4'} - cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - cosmiconfig@8.3.6: resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} engines: {node: '>=14'} @@ -3656,10 +3209,6 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - delay@5.0.0: - resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} - engines: {node: '>=10'} - denodeify@1.2.1: resolution: {integrity: sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg==} @@ -3709,9 +3258,6 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} - dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} - dompurify@3.1.6: resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==} @@ -3812,12 +3358,6 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - - es6-promisify@5.0.0: - resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -3931,9 +3471,6 @@ packages: eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -3956,10 +3493,6 @@ packages: resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} engines: {node: '>=12.0.0'} - eyes@0.1.8: - resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} - engines: {node: '> 0.1.90'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -3980,9 +3513,6 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-stable-stringify@1.0.0: - resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} - fast-xml-parser@4.4.1: resolution: {integrity: sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==} hasBin: true @@ -3997,9 +3527,6 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -4016,9 +3543,6 @@ packages: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} - find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} engines: {node: '>=6'} @@ -4261,12 +3785,6 @@ packages: hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - - html-parse-stringify@3.0.1: - resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} - http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -4283,9 +3801,6 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - i18next-browser-languagedetector@7.1.0: resolution: {integrity: sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==} @@ -4531,11 +4046,6 @@ packages: isomorphic-unfetch@3.1.0: resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} - isomorphic-ws@4.0.1: - resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} - peerDependencies: - ws: '*' - isows@1.0.4: resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} peerDependencies: @@ -4548,11 +4058,6 @@ packages: resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} - jayson@4.1.1: - resolution: {integrity: sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w==} - engines: {node: '>=8'} - hasBin: true - jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4588,9 +4093,6 @@ packages: joi@17.13.3: resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} - js-base64@3.7.7: - resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4645,9 +4147,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -4656,10 +4155,6 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonparse@1.3.1: - resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} - engines: {'0': node >= 0.2.0} - jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -4870,9 +4365,6 @@ packages: micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - microdiff@1.4.0: - resolution: {integrity: sha512-OBKBOa1VBznvLPb/3ljeJaENVe0fO0lnWl77lR4vhPlQD71UpjEoRV5P0KdQkcjbFlBu1Oy2mEUBMU3wxcBAGg==} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} @@ -4940,9 +4432,6 @@ packages: typescript: optional: true - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -5491,28 +4980,6 @@ packages: peerDependencies: react: ^18.3.1 - react-i18next@14.1.2: - resolution: {integrity: sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==} - peerDependencies: - i18next: '>= 23.2.3' - react: '>= 16.8.0' - react-dom: '*' - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - - react-intersection-observer@9.10.3: - resolution: {integrity: sha512-9NYfKwPZRovB6QJee7fDg0zz/SyYrqXtn5xTZU0vwLtLVBtfu9aZt1pVmr825REE49VPDZ7Lm5SNHjJBOTZHpA==} - peerDependencies: - react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - react-dom: - optional: true - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5563,19 +5030,6 @@ packages: '@types/react': optional: true - react-router-dom@6.24.1: - resolution: {integrity: sha512-U19KtXqooqw967Vw0Qcn5cOvrX5Ejo9ORmOtJMzYWtCT4/WOfFLIZGGsVLxcd9UkBO0mSTZtXqhZBsWlHr7+Sg==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' - - react-router@6.24.1: - resolution: {integrity: sha512-PTXFXGK2pyXpHzVo3rR9H7ip4lSPZZc0bHG5CARmj65fTT6qG7sTngmb6lcYu1gf3y/8KxORoy9yn59pGpCnpg==} - engines: {node: '>=14.0.0'} - peerDependencies: - react: '>=16.8' - react-shallow-renderer@16.15.0: resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} peerDependencies: @@ -5591,17 +5045,6 @@ packages: '@types/react': optional: true - react-timer-hook@3.0.7: - resolution: {integrity: sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==} - peerDependencies: - react: '>=16.8.0' - - react-transition-group@4.4.5: - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -5726,9 +5169,6 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rpc-websockets@9.0.2: - resolution: {integrity: sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==} - run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -5997,9 +5437,6 @@ packages: strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} - stylis@4.2.0: - resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -6061,9 +5498,6 @@ packages: engines: {node: '>=10'} hasBin: true - text-encoding-utf-8@1.0.2: - resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} - text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -6083,9 +5517,6 @@ packages: through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -6343,10 +5774,6 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} - hasBin: true - uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true @@ -6445,10 +5872,6 @@ packages: vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - void-elements@3.1.0: - resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} - engines: {node: '>=0.10.0'} - wagmi@2.12.5: resolution: {integrity: sha512-+fpSUsVKyGOumguQirtpyMb7dmDP4/ZdwrTqrBc+WZVTwR9S8WdFPParw/BKXVZjF9euJxu1zKsWQSLBeCROfQ==} peerDependencies: @@ -6573,18 +5996,6 @@ packages: utf-8-validate: optional: true - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - xmlhttprequest-ssl@2.0.0: resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} engines: {node: '>=0.4.0'} @@ -6603,10 +6014,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} - yaml@2.5.0: resolution: {integrity: sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==} engines: {node: '>= 14'} @@ -7692,104 +7099,15 @@ snapshots: preact: 10.23.1 sha.js: 2.4.11 - '@emotion/babel-plugin@11.12.0': - dependencies: - '@babel/helper-module-imports': 7.24.7 - '@babel/runtime': 7.25.0 - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/serialize': 1.3.0 - babel-plugin-macros: 3.1.0 - convert-source-map: 1.9.0 - escape-string-regexp: 4.0.0 - find-root: 1.1.0 - source-map: 0.5.7 - stylis: 4.2.0 - transitivePeerDependencies: - - supports-color - - '@emotion/cache@11.11.0': - dependencies: - '@emotion/memoize': 0.8.1 - '@emotion/sheet': 1.2.2 - '@emotion/utils': 1.2.1 - '@emotion/weak-memoize': 0.3.1 - stylis: 4.2.0 - - '@emotion/cache@11.13.1': - dependencies: - '@emotion/memoize': 0.9.0 - '@emotion/sheet': 1.4.0 - '@emotion/utils': 1.4.0 - '@emotion/weak-memoize': 0.4.0 - stylis: 4.2.0 - '@emotion/hash@0.9.2': {} '@emotion/is-prop-valid@1.3.0': dependencies: '@emotion/memoize': 0.9.0 + optional: true - '@emotion/memoize@0.8.1': {} - - '@emotion/memoize@0.9.0': {} - - '@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@emotion/babel-plugin': 11.12.0 - '@emotion/cache': 11.13.1 - '@emotion/serialize': 1.3.0 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) - '@emotion/utils': 1.4.0 - '@emotion/weak-memoize': 0.3.1 - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 - transitivePeerDependencies: - - supports-color - - '@emotion/serialize@1.3.0': - dependencies: - '@emotion/hash': 0.9.2 - '@emotion/memoize': 0.9.0 - '@emotion/unitless': 0.9.0 - '@emotion/utils': 1.4.0 - csstype: 3.1.3 - - '@emotion/sheet@1.2.2': {} - - '@emotion/sheet@1.4.0': {} - - '@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@emotion/babel-plugin': 11.12.0 - '@emotion/is-prop-valid': 1.3.0 - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/serialize': 1.3.0 - '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) - '@emotion/utils': 1.4.0 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 - transitivePeerDependencies: - - supports-color - - '@emotion/unitless@0.9.0': {} - - '@emotion/use-insertion-effect-with-fallbacks@1.1.0(react@18.3.1)': - dependencies: - react: 18.3.1 - - '@emotion/utils@1.2.1': {} - - '@emotion/utils@1.4.0': {} - - '@emotion/weak-memoize@0.3.1': {} - - '@emotion/weak-memoize@0.4.0': {} + '@emotion/memoize@0.9.0': + optional: true '@esbuild/aix-ppc64@0.21.5': optional: true @@ -7903,6 +7221,18 @@ snapshots: ethereum-cryptography: 2.2.1 micro-ftch: 0.3.1 + '@ethersproject/bignumber@5.7.0': + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + bn.js: 5.2.1 + + '@ethersproject/bytes@5.7.0': + dependencies: + '@ethersproject/logger': 5.7.0 + + '@ethersproject/logger@5.7.0': {} + '@floating-ui/core@1.6.4': dependencies: '@floating-ui/utils': 0.2.4 @@ -8016,57 +7346,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@lifi/sdk@3.0.0(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8))': - dependencies: - '@lifi/types': 13.18.2 - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - eth-rpc-errors: 4.0.3 - viem: 2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) - - '@lifi/types@13.18.2': {} - - '@lifi/wallet-management@3.0.0(jp76vp23zirnrrtfsbj7azde2q)': - dependencies: - '@lifi/sdk': 3.0.0(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8)) - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@tanstack/react-query': 5.51.21(react@18.3.1) - react: 18.3.1 - viem: 2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) - wagmi: 2.12.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.51.21)(@tanstack/react-query@5.51.21(react@18.3.1))(@types/react@18.3.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(rollup@4.18.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) - transitivePeerDependencies: - - '@solana/web3.js' - - '@lifi/widget@3.0.0(jjnkyh6cyrxgxf254wfk2drkny)': - dependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@lifi/sdk': 3.0.0(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8)) - '@lifi/wallet-management': 3.0.0(jp76vp23zirnrrtfsbj7azde2q) - '@mui/icons-material': 5.15.21(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@mui/lab': 5.0.0-alpha.170(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/material': 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-react': 0.15.35(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@tanstack/react-query': 5.51.21(react@18.3.1) - '@tanstack/react-virtual': 3.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - i18next: 23.11.5 - microdiff: 1.4.0 - mitt: 3.0.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-i18next: 14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) - react-intersection-observer: 9.10.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-router-dom: 6.24.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-timer-hook: 3.0.7(react@18.3.1) - uuid: 10.0.0 - viem: 2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8) - wagmi: 2.12.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.51.21)(@tanstack/react-query@5.51.21(react@18.3.1))(@types/react@18.3.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(rollup@4.18.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8) - zustand: 4.4.1(@types/react@18.3.3)(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.3 - '@lit-labs/ssr-dom-shim@1.2.1': {} '@lit/reactive-element@1.6.3': @@ -8278,196 +7557,32 @@ snapshots: '@motionone/easing@10.18.0': dependencies: - '@motionone/utils': 10.18.0 - tslib: 2.6.3 - - '@motionone/generators@10.18.0': - dependencies: - '@motionone/types': 10.17.1 - '@motionone/utils': 10.18.0 - tslib: 2.6.3 - - '@motionone/svelte@10.16.4': - dependencies: - '@motionone/dom': 10.18.0 - tslib: 2.6.3 - - '@motionone/types@10.17.1': {} - - '@motionone/utils@10.18.0': - dependencies: - '@motionone/types': 10.17.1 - hey-listen: 1.0.8 - tslib: 2.6.3 - - '@motionone/vue@10.16.4': - dependencies: - '@motionone/dom': 10.18.0 - tslib: 2.6.3 - - '@mui/base@5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.24.7 - '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) - '@popperjs/core': 2.11.8 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.3 - - '@mui/core-downloads-tracker@5.16.7': {} - - '@mui/icons-material@5.15.21(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@mui/material': 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 - - '@mui/lab@5.0.0-alpha.170(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.24.7 - '@mui/base': 5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/material': 5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/system': 5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - - '@mui/material@5.15.21(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@mui/base': 5.0.0-beta.40(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mui/core-downloads-tracker': 5.16.7 - '@mui/system': 5.16.7(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@mui/types': 7.2.15(@types/react@18.3.3) - '@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) - '@types/react-transition-group': 4.4.11 - clsx: 2.1.1 - csstype: 3.1.3 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 18.3.1 - react-transition-group: 4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 - - '@mui/private-theming@5.15.20(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.24.7 - '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 - - '@mui/private-theming@5.16.6(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 - - '@mui/styled-engine@5.15.14(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.24.7 - '@emotion/cache': 11.11.0 - csstype: 3.1.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - - '@mui/styled-engine@5.16.6(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1)': - dependencies: - '@babel/runtime': 7.25.0 - '@emotion/cache': 11.13.1 - csstype: 3.1.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - - '@mui/system@5.15.20(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': - dependencies: - '@babel/runtime': 7.24.7 - '@mui/private-theming': 5.15.20(@types/react@18.3.3)(react@18.3.1) - '@mui/styled-engine': 5.15.14(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.14(@types/react@18.3.3) - '@mui/utils': 5.15.20(@types/react@18.3.3)(react@18.3.1) - clsx: 2.1.1 - csstype: 3.1.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 + '@motionone/utils': 10.18.0 + tslib: 2.6.3 - '@mui/system@5.16.7(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': + '@motionone/generators@10.18.0': dependencies: - '@babel/runtime': 7.25.0 - '@mui/private-theming': 5.16.6(@types/react@18.3.3)(react@18.3.1) - '@mui/styled-engine': 5.16.6(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@emotion/styled@11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1))(react@18.3.1) - '@mui/types': 7.2.15(@types/react@18.3.3) - '@mui/utils': 5.16.6(@types/react@18.3.3)(react@18.3.1) - clsx: 2.1.1 - csstype: 3.1.3 - prop-types: 15.8.1 - react: 18.3.1 - optionalDependencies: - '@emotion/react': 11.11.4(@types/react@18.3.3)(react@18.3.1) - '@emotion/styled': 11.11.5(@emotion/react@11.11.4(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) - '@types/react': 18.3.3 + '@motionone/types': 10.17.1 + '@motionone/utils': 10.18.0 + tslib: 2.6.3 - '@mui/types@7.2.14(@types/react@18.3.3)': - optionalDependencies: - '@types/react': 18.3.3 + '@motionone/svelte@10.16.4': + dependencies: + '@motionone/dom': 10.18.0 + tslib: 2.6.3 - '@mui/types@7.2.15(@types/react@18.3.3)': - optionalDependencies: - '@types/react': 18.3.3 + '@motionone/types@10.17.1': {} - '@mui/utils@5.15.20(@types/react@18.3.3)(react@18.3.1)': + '@motionone/utils@10.18.0': dependencies: - '@babel/runtime': 7.24.7 - '@types/prop-types': 15.7.12 - prop-types: 15.8.1 - react: 18.3.1 - react-is: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 + '@motionone/types': 10.17.1 + hey-listen: 1.0.8 + tslib: 2.6.3 - '@mui/utils@5.16.6(@types/react@18.3.3)(react@18.3.1)': + '@motionone/vue@10.16.4': dependencies: - '@babel/runtime': 7.25.0 - '@mui/types': 7.2.15(@types/react@18.3.3) - '@types/prop-types': 15.7.12 - clsx: 2.1.1 - prop-types: 15.8.1 - react: 18.3.1 - react-is: 18.3.1 - optionalDependencies: - '@types/react': 18.3.3 + '@motionone/dom': 10.18.0 + tslib: 2.6.3 '@noble/curves@1.4.0': dependencies: @@ -8477,10 +7592,6 @@ snapshots: dependencies: '@noble/hashes': 1.4.0 - '@noble/curves@1.5.0': - dependencies: - '@noble/hashes': 1.4.0 - '@noble/hashes@1.4.0': {} '@nodelib/fs.scandir@2.1.5': @@ -8559,8 +7670,6 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@popperjs/core@2.11.8': {} - '@radix-ui/number@1.1.0': {} '@radix-ui/primitive@1.1.0': {} @@ -9254,8 +8363,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - '@remix-run/router@1.17.1': {} - '@rnx-kit/chromium-edge-launcher@1.0.0': dependencies: '@types/node': 18.19.44 @@ -9378,153 +8485,6 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@solana-mobile/mobile-wallet-adapter-protocol-web3js@2.1.3(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': - dependencies: - '@solana-mobile/mobile-wallet-adapter-protocol': 2.1.3(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - bs58: 5.0.0 - js-base64: 3.7.7 - transitivePeerDependencies: - - '@solana/wallet-adapter-base' - - react - - react-native - - '@solana-mobile/mobile-wallet-adapter-protocol@2.1.3(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': - dependencies: - '@solana/wallet-standard': 1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1) - '@solana/wallet-standard-util': 1.1.1 - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@wallet-standard/core': 1.0.3 - js-base64: 3.7.7 - react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - '@solana/wallet-adapter-base' - - bs58 - - react - - '@solana-mobile/wallet-adapter-mobile@2.1.3(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': - dependencies: - '@solana-mobile/mobile-wallet-adapter-protocol-web3js': 2.1.3(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-features': 1.2.0 - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - js-base64: 3.7.7 - optionalDependencies: - '@react-native-async-storage/async-storage': 1.24.0(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10)) - transitivePeerDependencies: - - react - - react-native - - '@solana/buffer-layout@4.0.1': - dependencies: - buffer: 6.0.3 - - '@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))': - dependencies: - '@solana/wallet-standard-features': 1.2.0 - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@wallet-standard/base': 1.0.1 - '@wallet-standard/features': 1.0.3 - eventemitter3: 4.0.7 - - '@solana/wallet-adapter-react@0.15.35(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)': - dependencies: - '@solana-mobile/wallet-adapter-mobile': 2.1.3(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1) - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-wallet-adapter-react': 1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1) - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - react: 18.3.1 - transitivePeerDependencies: - - bs58 - - react-native - - '@solana/wallet-standard-chains@1.1.0': - dependencies: - '@wallet-standard/base': 1.0.1 - - '@solana/wallet-standard-core@1.1.1': - dependencies: - '@solana/wallet-standard-chains': 1.1.0 - '@solana/wallet-standard-features': 1.2.0 - '@solana/wallet-standard-util': 1.1.1 - - '@solana/wallet-standard-features@1.2.0': - dependencies: - '@wallet-standard/base': 1.0.1 - '@wallet-standard/features': 1.0.3 - - '@solana/wallet-standard-util@1.1.1': - dependencies: - '@noble/curves': 1.5.0 - '@solana/wallet-standard-chains': 1.1.0 - '@solana/wallet-standard-features': 1.2.0 - - '@solana/wallet-standard-wallet-adapter-base@1.1.2(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)': - dependencies: - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-chains': 1.1.0 - '@solana/wallet-standard-features': 1.2.0 - '@solana/wallet-standard-util': 1.1.1 - '@solana/web3.js': 1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - '@wallet-standard/app': 1.0.1 - '@wallet-standard/base': 1.0.1 - '@wallet-standard/features': 1.0.3 - '@wallet-standard/wallet': 1.0.1 - bs58: 5.0.0 - - '@solana/wallet-standard-wallet-adapter-react@1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1)': - dependencies: - '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-wallet-adapter-base': 1.1.2(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0) - '@wallet-standard/app': 1.0.1 - '@wallet-standard/base': 1.0.1 - react: 18.3.1 - transitivePeerDependencies: - - '@solana/web3.js' - - bs58 - - '@solana/wallet-standard-wallet-adapter@1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1)': - dependencies: - '@solana/wallet-standard-wallet-adapter-base': 1.1.2(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0) - '@solana/wallet-standard-wallet-adapter-react': 1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1) - transitivePeerDependencies: - - '@solana/wallet-adapter-base' - - '@solana/web3.js' - - bs58 - - react - - '@solana/wallet-standard@1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1)': - dependencies: - '@solana/wallet-standard-core': 1.1.1 - '@solana/wallet-standard-wallet-adapter': 1.1.2(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)))(@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10))(bs58@5.0.0)(react@18.3.1) - transitivePeerDependencies: - - '@solana/wallet-adapter-base' - - '@solana/web3.js' - - bs58 - - react - - '@solana/web3.js@1.94.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': - dependencies: - '@babel/runtime': 7.25.0 - '@noble/curves': 1.5.0 - '@noble/hashes': 1.4.0 - '@solana/buffer-layout': 4.0.1 - agentkeepalive: 4.5.0 - bigint-buffer: 1.1.5 - bn.js: 5.2.1 - borsh: 0.7.0 - bs58: 4.0.1 - buffer: 6.0.3 - fast-stable-stringify: 1.0.0 - jayson: 4.1.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) - node-fetch: 2.7.0 - rpc-websockets: 9.0.2 - superstruct: 1.0.4 - transitivePeerDependencies: - - bufferutil - - encoding - - utf-8-validate - '@stablelib/aead@1.0.1': {} '@stablelib/binary@1.0.1': @@ -9675,10 +8635,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@swc/helpers@0.5.12': - dependencies: - tslib: 2.6.3 - '@tanstack/eslint-plugin-query@5.51.12(eslint@8.57.0)(typescript@5.5.4)': dependencies: '@typescript-eslint/utils': 8.0.0-alpha.30(eslint@8.57.0)(typescript@5.5.4) @@ -9720,12 +8676,6 @@ snapshots: react-dom: 18.3.1(react@18.3.1) use-sync-external-store: 1.2.2(react@18.3.1) - '@tanstack/react-virtual@3.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@tanstack/virtual-core': 3.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@tanstack/router-devtools@1.43.10(@tanstack/react-router@1.45.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/react-router': 1.45.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -9768,8 +8718,6 @@ snapshots: '@tanstack/store@0.5.5': {} - '@tanstack/virtual-core@3.8.1': {} - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.24.7 @@ -9791,10 +8739,6 @@ snapshots: dependencies: '@babel/types': 7.24.7 - '@types/connect@3.4.38': - dependencies: - '@types/node': 22.2.0 - '@types/debug@4.1.12': dependencies: '@types/ms': 0.7.34 @@ -9823,8 +8767,6 @@ snapshots: dependencies: '@types/node': 22.2.0 - '@types/node@12.20.55': {} - '@types/node@18.19.44': dependencies: undici-types: 5.26.5 @@ -9833,18 +8775,12 @@ snapshots: dependencies: undici-types: 6.13.0 - '@types/parse-json@4.0.2': {} - '@types/prop-types@15.7.12': {} '@types/react-dom@18.3.0': dependencies: '@types/react': 18.3.3 - '@types/react-transition-group@4.4.11': - dependencies: - '@types/react': 18.3.3 - '@types/react@18.3.3': dependencies: '@types/prop-types': 15.7.12 @@ -9858,16 +8794,6 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@types/uuid@8.3.4': {} - - '@types/ws@7.4.7': - dependencies: - '@types/node': 22.2.0 - - '@types/ws@8.5.12': - dependencies: - '@types/node': 22.2.0 - '@types/yargs-parser@21.0.3': {} '@types/yargs@15.0.19': @@ -10147,27 +9073,6 @@ snapshots: - immer - react - '@wallet-standard/app@1.0.1': - dependencies: - '@wallet-standard/base': 1.0.1 - - '@wallet-standard/base@1.0.1': {} - - '@wallet-standard/core@1.0.3': - dependencies: - '@wallet-standard/app': 1.0.1 - '@wallet-standard/base': 1.0.1 - '@wallet-standard/features': 1.0.3 - '@wallet-standard/wallet': 1.0.1 - - '@wallet-standard/features@1.0.3': - dependencies: - '@wallet-standard/base': 1.0.1 - - '@wallet-standard/wallet@1.0.1': - dependencies: - '@wallet-standard/base': 1.0.1 - '@walletconnect/core@2.14.0(@react-native-async-storage/async-storage@1.24.0(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10)))(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -10488,11 +9393,6 @@ snapshots: '@walletconnect/window-getters': 1.0.1 tslib: 1.14.1 - JSONStream@1.3.5: - dependencies: - jsonparse: 1.3.1 - through: 2.3.8 - abitype@1.0.5(typescript@5.5.4)(zod@3.23.8): optionalDependencies: typescript: 5.5.4 @@ -10513,10 +9413,6 @@ snapshots: acorn@8.12.1: {} - agentkeepalive@4.5.0: - dependencies: - humanize-ms: 1.2.1 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -10688,12 +9584,6 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-macros@3.1.0: - dependencies: - '@babel/runtime': 7.25.0 - cosmiconfig: 7.1.0 - resolve: 1.22.8 - babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7): dependencies: '@babel/compat-data': 7.25.2 @@ -10726,24 +9616,10 @@ snapshots: balanced-match@1.0.2: {} - base-x@3.0.10: - dependencies: - safe-buffer: 5.2.1 - - base-x@4.0.0: {} - base64-js@1.5.1: {} - bigint-buffer@1.1.5: - dependencies: - bindings: 1.5.0 - binary-extensions@2.3.0: {} - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -10754,12 +9630,6 @@ snapshots: bn.js@5.2.1: {} - borsh@0.7.0: - dependencies: - bn.js: 5.2.1 - bs58: 4.0.1 - text-encoding-utf-8: 1.0.2 - bowser@2.11.0: {} brace-expansion@1.1.11: @@ -10791,14 +9661,6 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.0(browserslist@4.23.3) - bs58@4.0.1: - dependencies: - base-x: 3.0.10 - - bs58@5.0.0: - dependencies: - base-x: 4.0.0 - bser@2.1.1: dependencies: node-int64: 0.4.0 @@ -11004,8 +9866,6 @@ snapshots: consola@3.2.3: {} - convert-source-map@1.9.0: {} - convert-source-map@2.0.0: {} cookie-es@1.2.2: {} @@ -11023,14 +9883,6 @@ snapshots: js-yaml: 3.14.1 parse-json: 4.0.0 - cosmiconfig@7.1.0: - dependencies: - '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.2 - cosmiconfig@8.3.6(typescript@5.5.4): dependencies: import-fresh: 3.3.0 @@ -11136,8 +9988,6 @@ snapshots: defu@6.1.4: {} - delay@5.0.0: {} - denodeify@1.2.1: {} depd@2.0.0: {} @@ -11174,11 +10024,6 @@ snapshots: dependencies: esutils: 2.0.3 - dom-helpers@5.2.1: - dependencies: - '@babel/runtime': 7.25.0 - csstype: 3.1.3 - dompurify@3.1.6: {} dot-case@3.0.4: @@ -11352,12 +10197,6 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 - es6-promise@4.2.8: {} - - es6-promisify@5.0.0: - dependencies: - es6-promise: 4.2.8 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -11541,8 +10380,6 @@ snapshots: eventemitter2@6.4.9: {} - eventemitter3@4.0.7: {} - eventemitter3@5.0.1: {} events@3.3.0: {} @@ -11578,8 +10415,6 @@ snapshots: readable-stream: 3.6.2 webextension-polyfill: 0.10.0 - eyes@0.1.8: {} - fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -11598,8 +10433,6 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-stable-stringify@1.0.0: {} - fast-xml-parser@4.4.1: dependencies: strnum: 1.0.5 @@ -11616,8 +10449,6 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-uri-to-path@1.0.0: {} - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -11642,8 +10473,6 @@ snapshots: make-dir: 2.1.0 pkg-dir: 3.0.0 - find-root@1.1.0: {} - find-up@3.0.0: dependencies: locate-path: 3.0.0 @@ -11878,14 +10707,6 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - - html-parse-stringify@3.0.1: - dependencies: - void-elements: 3.1.0 - http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -11900,10 +10721,6 @@ snapshots: human-signals@5.0.0: {} - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - i18next-browser-languagedetector@7.1.0: dependencies: '@babel/runtime': 7.25.0 @@ -12114,10 +10931,6 @@ snapshots: transitivePeerDependencies: - encoding - isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)): - dependencies: - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) - isows@1.0.4(ws@8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)): dependencies: ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -12136,24 +10949,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jayson@4.1.1(bufferutil@4.0.8)(utf-8-validate@5.0.10): - dependencies: - '@types/connect': 3.4.38 - '@types/node': 12.20.55 - '@types/ws': 7.4.7 - JSONStream: 1.3.5 - commander: 2.20.3 - delay: 5.0.0 - es6-promisify: 5.0.0 - eyes: 0.1.8 - isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - json-stringify-safe: 5.0.1 - uuid: 8.3.2 - ws: 7.5.10(bufferutil@4.0.8)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 @@ -12218,8 +11013,6 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - js-base64@3.7.7: {} - js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -12281,16 +11074,12 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json-stringify-safe@5.0.1: {} - json5@2.2.3: {} jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 - jsonparse@1.3.1: {} - jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -12647,8 +11436,6 @@ snapshots: micro-ftch@0.3.1: {} - microdiff@1.4.0: {} - micromatch@4.0.7: dependencies: braces: 3.0.3 @@ -12692,8 +11479,6 @@ snapshots: optionalDependencies: typescript: 5.5.4 - mitt@3.0.1: {} - mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -13161,22 +11946,6 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-i18next@14.1.2(i18next@23.11.5)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1): - dependencies: - '@babel/runtime': 7.25.0 - html-parse-stringify: 3.0.1 - i18next: 23.11.5 - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - react-native: 0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10) - - react-intersection-observer@9.10.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - react-is@16.13.1: {} react-is@17.0.2: {} @@ -13261,18 +12030,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - react-router-dom@6.24.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@remix-run/router': 1.17.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-router: 6.24.1(react@18.3.1) - - react-router@6.24.1(react@18.3.1): - dependencies: - '@remix-run/router': 1.17.1 - react: 18.3.1 - react-shallow-renderer@16.15.0(react@18.3.1): dependencies: object-assign: 4.1.1 @@ -13288,19 +12045,6 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 - react-timer-hook@3.0.7(react@18.3.1): - dependencies: - react: 18.3.1 - - react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@babel/runtime': 7.25.0 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -13454,19 +12198,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 - rpc-websockets@9.0.2: - dependencies: - '@swc/helpers': 0.5.12 - '@types/uuid': 8.3.4 - '@types/ws': 8.5.12 - buffer: 6.0.3 - eventemitter3: 5.0.1 - uuid: 8.3.2 - ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 5.0.10 - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -13762,8 +12493,6 @@ snapshots: strnum@1.0.5: {} - stylis@4.2.0: {} - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -13842,8 +12571,6 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - text-encoding-utf-8@1.0.2: {} - text-table@0.2.0: {} thenify-all@1.6.0: @@ -13865,8 +12592,6 @@ snapshots: readable-stream: 2.3.8 xtend: 4.0.2 - through@2.3.8: {} - tiny-invariant@1.3.3: {} tiny-warning@1.0.3: {} @@ -14082,8 +12807,6 @@ snapshots: utils-merge@1.0.1: {} - uuid@10.0.0: {} - uuid@8.3.2: {} uuid@9.0.1: {} @@ -14188,8 +12911,6 @@ snapshots: vlq@1.0.1: {} - void-elements@3.1.0: {} - wagmi@2.12.5(@react-native-async-storage/async-storage@1.24.0(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10)))(@tanstack/query-core@5.51.21)(@tanstack/react-query@5.51.21(react@18.3.1))(@types/react@18.3.3)(bufferutil@4.0.8)(react-dom@18.3.1(react@18.3.1))(react-native@0.74.2(@babel/core@7.24.7)(@babel/preset-env@7.24.7(@babel/core@7.24.7))(@types/react@18.3.3)(bufferutil@4.0.8)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(rollup@4.18.0)(typescript@5.5.4)(utf-8-validate@5.0.10)(viem@2.19.4(bufferutil@4.0.8)(typescript@5.5.4)(utf-8-validate@5.0.10)(zod@3.23.8))(zod@3.23.8): dependencies: '@tanstack/react-query': 5.51.21(react@18.3.1) @@ -14349,11 +13070,6 @@ snapshots: bufferutil: 4.0.8 utf-8-validate: 5.0.10 - ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.8 - utf-8-validate: 5.0.10 - xmlhttprequest-ssl@2.0.0: {} xtend@4.0.2: {} @@ -14364,8 +13080,6 @@ snapshots: yallist@3.1.1: {} - yaml@1.10.2: {} - yaml@2.5.0: {} yargs-parser@18.1.3: diff --git a/public/images/icons/farm_med.svg b/public/images/icons/farm_med.svg old mode 100755 new mode 100644 index 7193b438..34eaa9d0 --- a/public/images/icons/farm_med.svg +++ b/public/images/icons/farm_med.svg @@ -1 +1,14 @@ - \ No newline at end of file + + + + + + + + + + + diff --git a/public/images/icons/farm_thin.svg b/public/images/icons/farm_thin.svg old mode 100755 new mode 100644 index 73e40df9..39285002 --- a/public/images/icons/farm_thin.svg +++ b/public/images/icons/farm_thin.svg @@ -1 +1,14 @@ - \ No newline at end of file + + + + + + + + + + + diff --git a/public/images/icons/transmuter_med.svg b/public/images/icons/transmuter_med.svg old mode 100755 new mode 100644 index c78ab7ed..b17edba1 --- a/public/images/icons/transmuter_med.svg +++ b/public/images/icons/transmuter_med.svg @@ -1 +1,15 @@ - \ No newline at end of file + + + + + + + + + + + diff --git a/public/images/icons/transmuter_thin.svg b/public/images/icons/transmuter_thin.svg old mode 100755 new mode 100644 index 72d1fc2d..74a8fdb0 --- a/public/images/icons/transmuter_thin.svg +++ b/public/images/icons/transmuter_thin.svg @@ -1 +1,15 @@ - \ No newline at end of file + + + + + + + + + + + diff --git a/public/images/icons/vault_med.svg b/public/images/icons/vault_med.svg deleted file mode 100755 index f0206fdb..00000000 --- a/public/images/icons/vault_med.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/icons/vault_thin.svg b/public/images/icons/vault_thin.svg deleted file mode 100755 index 62ea39bd..00000000 --- a/public/images/icons/vault_thin.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/icons/vaults_med.svg b/public/images/icons/vaults_med.svg new file mode 100644 index 00000000..15ed735a --- /dev/null +++ b/public/images/icons/vaults_med.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/images/icons/vaults_thin.svg b/public/images/icons/vaults_thin.svg new file mode 100644 index 00000000..ad98c06f --- /dev/null +++ b/public/images/icons/vaults_thin.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/abi/staticTokenAdapter.ts b/src/abi/staticTokenAdapter.ts new file mode 100644 index 00000000..6beb5510 --- /dev/null +++ b/src/abi/staticTokenAdapter.ts @@ -0,0 +1,426 @@ +export const staticTokenAdapterAbi = [ + { + inputs: [ + { internalType: "address", name: "lendingPool", type: "address" }, + { internalType: "address", name: "rewardsController", type: "address" }, + { internalType: "address", name: "aToken", type: "address" }, + { internalType: "address", name: "_rewardCollector", type: "address" }, + { internalType: "string", name: "wrappedTokenName", type: "string" }, + { internalType: "string", name: "wrappedTokenSymbol", type: "string" }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [ + { internalType: "address", name: "target", type: "address" }, + { internalType: "bool", name: "success", type: "bool" }, + { internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "ERC20CallFailed", + type: "error", + }, + { inputs: [], name: "Unauthorized", 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: 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: "ASSET", + outputs: [{ internalType: "contract IERC20", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "ATOKEN", + outputs: [{ internalType: "contract IERC20", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "EIP712_REVISION", + outputs: [{ internalType: "bytes", name: "", type: "bytes" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "LENDING_POOL", + outputs: [ + { internalType: "contract ILendingPool", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "METADEPOSIT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "METAWITHDRAWAL_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "PERMIT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "REWARDS_CONTROLLER", + outputs: [ + { + internalType: "contract IRewardsController", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "_nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "acceptAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "admin", + outputs: [{ internalType: "address", 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: [], + name: "claimRewards", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "subtractedValue", type: "uint256" }, + ], + name: "decreaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "uint16", name: "referralCode", type: "uint16" }, + { internalType: "bool", name: "fromUnderlying", type: "bool" }, + ], + name: "deposit", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "dynamicBalanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], + name: "dynamicToStaticAmount", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "chainId", type: "uint256" }], + name: "getDomainSeparator", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "addedValue", type: "uint256" }, + ], + name: "increaseAllowance", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "depositor", type: "address" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "value", type: "uint256" }, + { internalType: "uint16", name: "referralCode", type: "uint16" }, + { internalType: "bool", name: "fromUnderlying", type: "bool" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + internalType: "struct StaticATokenV3.SignatureParams", + name: "sigParams", + type: "tuple", + }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + ], + name: "metaDeposit", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "staticAmount", type: "uint256" }, + { internalType: "uint256", name: "dynamicAmount", type: "uint256" }, + { internalType: "bool", name: "toUnderlying", type: "bool" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + { + components: [ + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + internalType: "struct StaticATokenV3.SignatureParams", + name: "sigParams", + type: "tuple", + }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + ], + name: "metaWithdraw", + outputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pendingAdmin", + outputs: [{ internalType: "address", name: "", type: "address" }], + 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" }, + { internalType: "uint256", name: "chainId", type: "uint256" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "rate", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "rewardCollector", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newAdmin", type: "address" }], + name: "setPendingAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_rewardCollector", type: "address" }, + ], + name: "setRewardCollector", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], + name: "staticToDynamicAmount", + 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: "amount", type: "uint256" }, + { internalType: "bool", name: "toUnderlying", type: "bool" }, + ], + name: "withdraw", + outputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "recipient", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + { internalType: "bool", name: "toUnderlying", type: "bool" }, + ], + name: "withdrawDynamicAmount", + outputs: [ + { internalType: "uint256", name: "", type: "uint256" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + stateMutability: "nonpayable", + type: "function", + }, +] as const; diff --git a/src/assets/logos/react.svg b/src/assets/logos/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/src/assets/logos/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/bridge/Bridge.tsx b/src/components/bridge/Bridge.tsx new file mode 100644 index 00000000..0a274bfc --- /dev/null +++ b/src/components/bridge/Bridge.tsx @@ -0,0 +1,9 @@ +import { ConnextBridge } from "./connext/ConnextBridge"; + +export const Bridge = () => { + return ( +
+ +
+ ); +}; diff --git a/src/components/bridge/BridgeWidget.tsx b/src/components/bridge/BridgeWidget.tsx deleted file mode 100644 index c609ff9f..00000000 --- a/src/components/bridge/BridgeWidget.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import type { WidgetConfig } from "@lifi/widget"; -import { arbitrum, mainnet, optimism } from "viem/chains"; -import { useConnectModal } from "@rainbow-me/rainbowkit"; -import { Suspense, lazy, useMemo } from "react"; -import { useTheme } from "../providers/ThemeProvider"; -import { BridgeFallback } from "./BridgeFallback"; - -const LiFiWidget = lazy(() => - import("@lifi/widget").then((module) => ({ default: module.LiFiWidget })), -); - -const widgetConfig = { - integrator: "Alchemix", - variant: "wide", - - // Bridge configuration - fromChain: mainnet.id, - toChain: arbitrum.id, - chains: { - allow: [mainnet.id, arbitrum.id, optimism.id], - }, - fromToken: "0xbc6da0fe9ad5f3b0d58160288917aa56653660e9", - toToken: "0xcb8fa9a76b8e203d8c3797bf438d8fb81ea3326a", - tokens: { - featured: [ - { - address: "0xBC6DA0FE9aD5f3b0d58160288917AA56653660E9", - chainId: mainnet.id, - decimals: 18, - name: "Alchemix USD", - symbol: "alUSD", - // lifi has wrong logoURI for alUSD - logoURI: - "https://assets.coingecko.com/coins/images/14114/standard/Alchemix_USD.png", - }, - { - address: "0xCB8FA9a76b8e203D8C3797bF438d8FB81Ea3326A", - chainId: arbitrum.id, - decimals: 18, - name: "Alchemix USD", - symbol: "alUSD", - }, - { - address: "0xCB8FA9a76b8e203D8C3797bF438d8FB81Ea3326A", - chainId: optimism.id, - decimals: 18, - name: "Alchemix USD", - symbol: "alUSD", - }, - { - address: "0xdBdb4d16EdA451D0503b854CF79D55697F90c8DF", - chainId: mainnet.id, - decimals: 18, - name: "Alchemix", - symbol: "ALCX", - }, - { - address: "0x27b58D226fe8f792730a795764945Cf146815AA7", - chainId: arbitrum.id, - decimals: 18, - name: "Alchemix", - symbol: "ALCX", - // lifi doesnt have logoURI for ALCX on arbitrum - logoURI: - "https://assets.coingecko.com/coins/images/14113/standard/Alchemix.png", - }, - ], - }, -} satisfies WidgetConfig; - -export const BridgeWidget = () => { - const { darkMode } = useTheme(); - - const { openConnectModal } = useConnectModal(); - - const config = useMemo(() => { - return { - ...widgetConfig, - appearance: darkMode ? "dark" : "light", - theme: { - typography: { - fontFamily: "Montserrat, sans-serif", - }, - container: { - border: darkMode ? "1px solid #20242C" : "1px solid #DEDBD3", - borderRadius: "8px", - }, - palette: { - background: { - default: darkMode ? "#171B24" : "#E8E4DB", - paper: darkMode ? "#20242C" : "#DEDBD3", - }, - text: { - primary: darkMode ? "#f5f5f5" : "#0A0A0A", - secondary: "#979BA2", - }, - }, - }, - walletConfig: { - onConnect: openConnectModal, - }, - } satisfies WidgetConfig; - }, [darkMode, openConnectModal]); - - return ( - }> - - - ); -}; diff --git a/src/components/bridge/connext/ConnextBridge.tsx b/src/components/bridge/connext/ConnextBridge.tsx new file mode 100644 index 00000000..75c4f5a0 --- /dev/null +++ b/src/components/bridge/connext/ConnextBridge.tsx @@ -0,0 +1,52 @@ +import { Button } from "@/components/ui/button"; +import { accordionVariants, accordionTransition } from "@/lib/motion/motion"; +import { AnimatePresence, m } from "framer-motion"; +import { EyeIcon, EyeOffIcon } from "lucide-react"; +import { Suspense, lazy, useState } from "react"; +import { BridgeFallback } from "../BridgeFallback"; + +const ConnextBridgeWidget = lazy(() => + import("./ConnextBridgeWidget").then((module) => ({ + default: module.ConnextBridgeWidget, + })), +); + +export const ConnextBridge = () => { + const [open, setOpen] = useState(false); + const handleOpen = () => setOpen(!open); + return ( +
+
+

Connext Bridge

+ +
+ + {open && ( + +
+ }> + + +
+
+ )} +
+
+ ); +}; diff --git a/src/components/bridge/connext/ConnextBridgeWidget.tsx b/src/components/bridge/connext/ConnextBridgeWidget.tsx new file mode 100644 index 00000000..d3749d58 --- /dev/null +++ b/src/components/bridge/connext/ConnextBridgeWidget.tsx @@ -0,0 +1,328 @@ +import { useSwitchChain } from "wagmi"; +import { useCallback, useEffect, useState } from "react"; +import { zeroAddress } from "viem"; + +import { useTokensQuery } from "@/lib/queries/useTokensQuery"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem, +} from "@/components/ui/select"; +import { Input } from "@/components/ui/input"; +import { TokenInput } from "@/components/common/input/TokenInput"; +import { SlippageInput } from "@/components/common/input/SlippageInput"; +import { Button } from "@/components/ui/button"; +import { isInputZero } from "@/utils/inputNotZero"; +import { useChain } from "@/hooks/useChain"; +import { useAllowance } from "@/hooks/useAllowance"; +import { formatNumber } from "@/utils/number"; +import { + useConnextRelayerFee, + useConnextAmountOut, + chainIdToDomainMapping, + bridgeChains, + chainToAvailableTokensMapping, + SupportedBridgeChainIds, + useConnextWriteBridge, +} from "./lib/connext"; +import { + getInitialOriginTokenAddresses, + getIsConnectedChainNotSupportedForBridge, + getOriginDomain, + getSpender, +} from "./lib/utils"; +import { StatusBox } from "./StatusBox"; + +export const ConnextBridgeWidget = () => { + const chain = useChain(); + const { switchChain } = useSwitchChain(); + + const [originChainId, setOriginChainId] = useState(chain.id); + const originDomain = getOriginDomain(originChainId); + const originChain = bridgeChains.find((c) => c.id === originChainId); + + const [destinationChainId, setDestinationChainId] = useState( + bridgeChains.find((c) => c.id !== originChainId)!.id, + ); + const destinationDomain = chainIdToDomainMapping[destinationChainId]; + const destinationChain = bridgeChains.find( + (c) => c.id === destinationChainId, + ); + + useEffect(() => { + const isConnectedChainNotSupportedForBridge = + getIsConnectedChainNotSupportedForBridge(chain.id); + if (isConnectedChainNotSupportedForBridge) { + switchChain({ + chainId: bridgeChains[0].id, + }); + setOriginChainId(bridgeChains[0].id); + const newChainTokenAddress = + chainToAvailableTokensMapping[bridgeChains[0].id][0]; + setOriginTokenAddress(newChainTokenAddress); + const newDestinationChainId = bridgeChains.find( + (c) => c.id !== bridgeChains[0].id, + )?.id; + if (newDestinationChainId) { + setDestinationChainId(newDestinationChainId); + } + } else if (chain.id !== originChainId) { + setOriginChainId(chain.id); + const newChainTokenAddress = + chainToAvailableTokensMapping[chain.id as SupportedBridgeChainIds][0]; + setOriginTokenAddress(newChainTokenAddress); + const newDestinationChainId = bridgeChains.find( + (c) => c.id !== chain.id, + )?.id; + if (newDestinationChainId) { + setDestinationChainId(newDestinationChainId); + } + } + }, [chain.id, originChainId, switchChain]); + + const { data: tokens } = useTokensQuery(); + const [originTokenAddress, setOriginTokenAddress] = useState( + getInitialOriginTokenAddresses(originChainId)[0], + ); + const token = tokens?.find( + (t) => t.address.toLowerCase() === originTokenAddress.toLowerCase(), + ); + const selection = tokens?.filter((t) => + getInitialOriginTokenAddresses(originChainId).includes(t.address), + ); + + const [amount, setAmount] = useState(""); + const [slippage, setSlippage] = useState("0.5"); + + const { data: relayerFee } = useConnextRelayerFee({ + originDomain, + destinationDomain, + }); + + const { + data: amountOut, + isFetching: isFetchingAmountOut, + isError, + } = useConnextAmountOut({ + originDomain, + destinationDomain, + originTokenAddress, + amount, + }); + + const { isApprovalNeeded, approveConfig, approve } = useAllowance({ + amount, + tokenAddress: originTokenAddress, + spender: getSpender({ originChainId }), + decimals: token?.decimals, + }); + + const { + mutate: writeBridge, + data: transactionHash, + isPending: isWritingBridge, + } = useConnextWriteBridge(); + + const handleOriginChainSelect = useCallback( + (chainId: string) => { + const newChainId = Number(chainId) as SupportedBridgeChainIds; + + setOriginChainId(newChainId); + const newChainTokenAddress = chainToAvailableTokensMapping[newChainId][0]; + setOriginTokenAddress(newChainTokenAddress); + setAmount(""); + if (newChainId === destinationChainId) { + const newDestinationChainId = bridgeChains.find( + (c) => c.id !== newChainId, + )?.id; + if (newDestinationChainId) { + setDestinationChainId(newDestinationChainId); + } + } + switchChain({ + chainId: newChainId, + }); + }, + [destinationChainId, switchChain], + ); + + const handleDestinationChainSelect = useCallback( + (chainId: string) => { + const newChainId = Number(chainId) as SupportedBridgeChainIds; + + setDestinationChainId(newChainId); + setAmount(""); + if (newChainId === originChainId) { + const newOriginChainId = bridgeChains.find( + (c) => c.id !== newChainId, + )?.id; + if (newOriginChainId) { + setOriginChainId(newOriginChainId); + switchChain({ + chainId: newOriginChainId, + }); + const newChainTokenAddress = + chainToAvailableTokensMapping[newOriginChainId][0]; + setOriginTokenAddress(newChainTokenAddress); + } + } + }, + [originChainId, switchChain], + ); + + const onCtaClick = () => { + if (isApprovalNeeded) { + approveConfig?.request && approve(approveConfig.request); + return; + } + + writeBridge( + { + amount, + destinationDomain, + originDomain, + originChainId, + originTokenAddress, + slippage, + relayerFee, + }, + { onSuccess: () => setAmount("") }, + ); + }; + + return ( +
+
+
+

Origin chain:

+ +
+
+

Target chain:

+ +
+
+

Router fee:

+ +
+
+

Relayer fee:

+ +
+
+

You receive:

+ +
+
+
+ + +
+
+ + +
+ +
+ ); +}; diff --git a/src/components/bridge/connext/StatusBox.tsx b/src/components/bridge/connext/StatusBox.tsx new file mode 100644 index 00000000..35bde3be --- /dev/null +++ b/src/components/bridge/connext/StatusBox.tsx @@ -0,0 +1,21 @@ +export const StatusBox = ({ + transactionHash, +}: { + transactionHash: `0x${string}` | undefined; +}) => { + return transactionHash ? ( +
+

Transaction has been submitted, check Connext Explorer for status.

+ {!!transactionHash && ( + + Connext Explorer + + )} +
+ ) : null; +}; diff --git a/src/components/bridge/connext/lib/connext.ts b/src/components/bridge/connext/lib/connext.ts new file mode 100644 index 00000000..a8cc1fa7 --- /dev/null +++ b/src/components/bridge/connext/lib/connext.ts @@ -0,0 +1,338 @@ +import { useAccount, usePublicClient, useWalletClient } from "wagmi"; +import { toast } from "sonner"; +import { + encodeAbiParameters, + encodeFunctionData, + formatEther, + parseAbi, + parseAbiParameters, + parseEther, + parseUnits, + toHex, + TransactionNotFoundError, + WaitForTransactionReceiptTimeoutError, +} from "viem"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { arbitrum, mainnet, optimism } from "viem/chains"; +import { BigNumber } from "@ethersproject/bignumber"; +import { useAddRecentTransaction } from "@rainbow-me/rainbowkit"; + +import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { SYNTH_ASSETS_ADDRESSES } from "@/lib/config/synths"; +import { isInputZero } from "@/utils/inputNotZero"; +import { + ALCX_ARBITRUM_ADDRESS, + ALCX_MAINNET_ADDRESS, + ALCX_OPTIMISM_ADDRESS, +} from "@/lib/constants"; +import { useChain } from "@/hooks/useChain"; +import { getSpender } from "./utils"; +import { SupportedChainId } from "@/lib/wagmi/wagmiConfig"; + +type AvailableTokensMapping = Record; +type TargetMapping = Record; +interface XCallParams { + origin: string; + destination: string; + asset: `0x${string}`; + amount: bigint; + slippage: bigint; + relayerFee: bigint; + + to?: `0x${string}`; + callData?: `0x${string}`; +} + +export const bridgeChains = [mainnet, optimism, arbitrum]; +export type SupportedBridgeChainIds = (typeof bridgeChains)[number]["id"]; + +export const chainIdToDomainMapping = { + [mainnet.id]: "6648936", + [optimism.id]: "1869640809", + [arbitrum.id]: "1634886255", +} as const; + +export const chainToAvailableTokensMapping: AvailableTokensMapping = { + [mainnet.id]: [ + SYNTH_ASSETS_ADDRESSES[mainnet.id].alUSD, + SYNTH_ASSETS_ADDRESSES[mainnet.id].alETH, + ALCX_MAINNET_ADDRESS, + ], + + [optimism.id]: [ + SYNTH_ASSETS_ADDRESSES[optimism.id].alUSD, + SYNTH_ASSETS_ADDRESSES[optimism.id].alETH, + ALCX_OPTIMISM_ADDRESS, + ], + + [arbitrum.id]: [ + SYNTH_ASSETS_ADDRESSES[arbitrum.id].alUSD, + SYNTH_ASSETS_ADDRESSES[arbitrum.id].alETH, + ALCX_ARBITRUM_ADDRESS, + ], +}; + +export const targetMapping: TargetMapping = { + [mainnet.id]: "0x45BF3c737e57B059a5855280CA1ADb8e9606AC68", + [optimism.id]: "0x8f7492DE823025b4CfaAB1D34c58963F2af5DEDA", + [arbitrum.id]: "0xEE9deC2712cCE65174B561151701Bf54b99C24C8", +}; + +const CONNEXT_BASE_URI = "https://sdk-server.mainnet.connext.ninja"; + +export const useConnextRelayerFee = ({ + originDomain, + destinationDomain, +}: { + originDomain: string; + destinationDomain: string; +}) => { + return useQuery({ + queryKey: [ + QueryKeys.ConnextSdk("relayerFee"), + originDomain, + destinationDomain, + ], + queryFn: async () => { + const response = await fetch(`${CONNEXT_BASE_URI}/estimateRelayerFee`, { + method: "POST", + body: JSON.stringify({ + originDomain, + destinationDomain, + }), + headers: { + "Content-Type": "application/json", + }, + }); + if (!response.ok) { + throw new Error( + `Error calling estimateRelayerFee: ${response.status} ${response.statusText}`, + ); + } + + const result = (await response.json()) as BigNumber; + const relayerFee = formatEther(BigInt(BigNumber.from(result).toString())); + + return relayerFee; + }, + staleTime: Infinity, + }); +}; + +export const useConnextAmountOut = ({ + originDomain, + destinationDomain, + originTokenAddress, + amount, +}: { + originDomain: string; + destinationDomain: string; + originTokenAddress: string; + amount: string; +}) => { + return useQuery({ + queryKey: [ + QueryKeys.ConnextSdk("amountOut"), + originDomain, + destinationDomain, + originTokenAddress, + amount, + ], + queryFn: async () => { + const response = await fetch( + `${CONNEXT_BASE_URI}/calculateAmountReceived`, + { + method: "POST", + body: JSON.stringify({ + originDomain, + destinationDomain, + originTokenAddress, + amount: parseEther(amount).toString(), + }), + headers: { + "Content-Type": "application/json", + }, + }, + ); + if (!response.ok) { + throw new Error( + `Error calling estimateRelayerFee: ${response.status} ${response.statusText}`, + ); + } + + const result = (await response.json()) as { + amountReceived: BigNumber; + originSlippage: BigNumber; + routerFee: BigNumber; + destinationSlippage: BigNumber; + isFastPath: boolean; + }; + + const formattedResult = { + amountReceived: formatEther( + BigInt(BigNumber.from(result.amountReceived).toString()), + ), + originSlippage: formatEther( + BigInt(BigNumber.from(result.originSlippage).toString()), + ), + routerFee: formatEther( + BigInt(BigNumber.from(result.routerFee).toString()), + ), + destinationSlippage: formatEther( + BigInt(BigNumber.from(result.destinationSlippage).toString()), + ), + isFastPath: result.isFastPath, + }; + + return formattedResult; + }, + enabled: !isInputZero(amount), + }); +}; + +export const useConnextWriteBridge = () => { + const addRecentTransaction = useAddRecentTransaction(); + const chain = useChain(); + const { address } = useAccount(); + const publicClient = usePublicClient({ + chainId: chain.id, + }); + const { data: walletClient } = useWalletClient({ + chainId: chain.id, + }); + return useMutation({ + mutationFn: async ({ + originDomain, + destinationDomain, + originChainId, + originTokenAddress, + amount, + slippage, + relayerFee, + }: { + originDomain: string; + destinationDomain: string; + originChainId: SupportedChainId; + originTokenAddress: `0x${string}`; + amount: string; // uint256 in string + slippage: string; // in % + relayerFee: string | undefined; // in wei + }) => { + if (!publicClient) throw new Error("Public client not ready"); + if (!address) throw new Error("Not connected"); + if (!walletClient) throw new Error("Wallet not ready"); + if (!relayerFee) throw new Error("Relayer fee not ready"); + + const bridgeConfig: XCallParams = { + origin: originDomain, + destination: destinationDomain, + asset: originTokenAddress, + amount: parseEther(amount), + relayerFee: parseEther(relayerFee), + slippage: parseUnits(slippage, 2), // BPS + }; + + const isFromEth = originDomain === chainIdToDomainMapping[mainnet.id]; + const isToEth = destinationDomain === chainIdToDomainMapping[mainnet.id]; + + if (isFromEth) { + bridgeConfig.to = address; + bridgeConfig.callData = toHex(""); + } else if (isToEth) { + // if we bridge ALCX to ETH we use alchemix lockbox adapter, for alusd and aleth we use connext lockbox adapter + const isBridgingAlcx = + originTokenAddress.toLowerCase() === + ALCX_OPTIMISM_ADDRESS.toLowerCase() || + originTokenAddress.toLowerCase() === + ALCX_ARBITRUM_ADDRESS.toLowerCase(); + if (isBridgingAlcx) { + // alcx lockbox adapter + bridgeConfig.to = "0xcfe063a764EA04A9A1Dc6cf8B8978955f779fc9F"; + } else { + // connext lockbox adapter "0xcfe063a764EA04A9A1Dc6cf8B8978955f779fc9F" + bridgeConfig.to = "0x45BF3c737e57B059a5855280CA1ADb8e9606AC68"; + } + bridgeConfig.callData = encodeAbiParameters( + parseAbiParameters("address"), + [address], + ); + } else { + // L2 to L2 + bridgeConfig.to = address; + bridgeConfig.callData = toHex(""); + } + + const xCallData = encodeFunctionData({ + abi: parseAbi([ + "function xcall(uint32 _destination, address _to, address _asset, address _delegate, uint256 _amount, uint256 _slippage, bytes calldata _callData) external payable returns (bytes32)", + ]), + args: [ + parseInt(bridgeConfig.destination), + bridgeConfig.to, + bridgeConfig.asset, + bridgeConfig.to, // delegate is the same as to https://github.com/connext/monorepo/blob/main/packages/agents/sdk/src/sdkBase.ts#L191 + bridgeConfig.amount, + bridgeConfig.slippage, + bridgeConfig.callData, + ], + }); + + const request = await publicClient.prepareTransactionRequest({ + account: address, + to: getSpender({ originChainId }), + data: xCallData, + value: bridgeConfig.relayerFee, + chainId: originChainId, + }); + + const hash = await walletClient.sendTransaction(request); + + return hash; + }, + onSuccess: (hash) => { + addRecentTransaction({ + hash, + description: "Bridge", + }); + const executionPromise = () => + new Promise((resolve, reject) => { + if (!publicClient) + return reject(new Error("Public client not ready")); + publicClient + .waitForTransactionReceipt({ + hash, + }) + .then((receipt) => + receipt.status === "success" + ? resolve(receipt) + : reject(new Error("Transaction reverted")), + ); + }); + toast.promise(executionPromise, { + loading: `Pending Bridge...`, + success: `Bridge confirmed`, + error: (e) => { + if ( + e instanceof WaitForTransactionReceiptTimeoutError || + e instanceof TransactionNotFoundError + ) { + return `We could not confirm your bridge. Please check your wallet.`; + } + + if (e instanceof Error) { + return `Bridge failed: ${e.message}`; + } + + return `Bridge failed`; + }, + }); + }, + onError: (error) => { + toast.error(`Bridge failed`, { + description: error.message.includes("User rejected the request") + ? "Transaction rejected by user" + : error.message, + }); + }, + }); +}; diff --git a/src/components/bridge/connext/lib/utils.ts b/src/components/bridge/connext/lib/utils.ts new file mode 100644 index 00000000..08289c97 --- /dev/null +++ b/src/components/bridge/connext/lib/utils.ts @@ -0,0 +1,29 @@ +import { + bridgeChains, + chainIdToDomainMapping, + chainToAvailableTokensMapping, + SupportedBridgeChainIds, + targetMapping, +} from "./connext"; + +export const getIsConnectedChainNotSupportedForBridge = (chainId: number) => { + return !bridgeChains.some((c) => c.id === chainId); +}; + +export const getOriginDomain = (chainId: number) => { + return getIsConnectedChainNotSupportedForBridge(chainId) + ? chainIdToDomainMapping[bridgeChains[0].id] + : chainIdToDomainMapping[chainId as SupportedBridgeChainIds]; +}; + +export const getInitialOriginTokenAddresses = (chainId: number) => { + return getIsConnectedChainNotSupportedForBridge(chainId) + ? chainToAvailableTokensMapping[bridgeChains[0].id] + : chainToAvailableTokensMapping[chainId as SupportedBridgeChainIds]; +}; + +export const getSpender = ({ originChainId }: { originChainId: number }) => { + return getIsConnectedChainNotSupportedForBridge(originChainId) + ? targetMapping[bridgeChains[0].id] + : targetMapping[originChainId as SupportedBridgeChainIds]; +}; diff --git a/src/components/common/CtaButton.tsx b/src/components/common/CtaButton.tsx new file mode 100644 index 00000000..ec39193b --- /dev/null +++ b/src/components/common/CtaButton.tsx @@ -0,0 +1,21 @@ +import { useAccount } from "wagmi"; +import { Button } from "../ui/button"; +import { useConnectModal } from "@rainbow-me/rainbowkit"; +import { ComponentPropsWithRef } from "react"; + +/** + * Button that opens connect modal if the user is not connected. + */ +export const CtaButton = (props: ComponentPropsWithRef) => { + const { address } = useAccount(); + const { openConnectModal } = useConnectModal(); + return ( + + ); +}; diff --git a/src/components/common/input/BorrowInput.tsx b/src/components/common/input/BorrowInput.tsx index a0223938..30e8bf63 100644 --- a/src/components/common/input/BorrowInput.tsx +++ b/src/components/common/input/BorrowInput.tsx @@ -6,6 +6,7 @@ import { useAccount, useReadContract } from "wagmi"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { useChain } from "@/hooks/useChain"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const BorrowInput = ({ amount, @@ -27,26 +28,25 @@ export const BorrowInput = ({ const { address } = useAccount(); - const { - data: totalValueOfCollateralInDebtTokens, - queryKey: totalValueQueryKey, - } = useReadContract({ + const { data: totalValueOfCollateralInDebtTokens } = useReadContract({ address: vaultForAlchemist?.alchemist.address, abi: alchemistV2Abi, chainId: chain.id, functionName: "totalValue", args: [address!], + scopeKey: ScopeKeys.BorrowInput, query: { enabled: !!vaultForAlchemist && !!address, }, }); - const { data: debt, queryKey: accountsQueryKey } = useReadContract({ + const { data: debt } = useReadContract({ address: vaultForAlchemist?.alchemist.address, abi: alchemistV2Abi, chainId: chain.id, functionName: "accounts", args: [address!], + scopeKey: ScopeKeys.BorrowInput, query: { enabled: !!vaultForAlchemist && !!address, select: ([debt]) => debt, @@ -69,7 +69,7 @@ export const BorrowInput = ({ ); useWatchQuery({ - queryKeys: [totalValueQueryKey, accountsQueryKey], + scopeKey: ScopeKeys.BorrowInput, }); return ( diff --git a/src/components/common/input/LiquidateInput.tsx b/src/components/common/input/LiquidateInput.tsx index 60353cb3..6abfb01b 100644 --- a/src/components/common/input/LiquidateInput.tsx +++ b/src/components/common/input/LiquidateInput.tsx @@ -5,6 +5,7 @@ import { Vault } from "@/lib/types"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { TokenInput } from "./TokenInput"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const LiquidateTokenInput = ({ amount, @@ -45,17 +46,17 @@ export const LiquidateTokenInput = ({ }, }); - const { data: maximumShares, queryKey: maximumSharesQueryKey } = - useReadContract({ - address: vault.alchemist.address, - abi: alchemistV2Abi, - chainId: chain.id, - functionName: "convertUnderlyingTokensToShares", - args: [vault.yieldToken, normalizedDebtToUnderlying ?? 0n], - query: { - enabled: normalizedDebtToUnderlying !== undefined, - }, - }); + const { data: maximumShares } = useReadContract({ + address: vault.alchemist.address, + abi: alchemistV2Abi, + chainId: chain.id, + functionName: "convertUnderlyingTokensToShares", + args: [vault.yieldToken, normalizedDebtToUnderlying ?? 0n], + scopeKey: ScopeKeys.LiquidateInput, + query: { + enabled: normalizedDebtToUnderlying !== undefined, + }, + }); const { data: debtInYield } = useReadContract({ address: vault.alchemist.address, @@ -70,25 +71,26 @@ export const LiquidateTokenInput = ({ }, }); - const { data: sharesBalance, queryKey: sharesBalanceQueryKey } = - useReadContract({ - address: vault.alchemist.address, - chainId: chain.id, - abi: alchemistV2Abi, - functionName: "positions", - args: [address ?? zeroAddress, vault.yieldToken], - query: { - enabled: !!address, - select: ([shares]) => shares, - }, - }); + const { data: sharesBalance } = useReadContract({ + address: vault.alchemist.address, + chainId: chain.id, + abi: alchemistV2Abi, + functionName: "positions", + args: [address ?? zeroAddress, vault.yieldToken], + scopeKey: ScopeKeys.LiquidateInput, + query: { + enabled: !!address, + select: ([shares]) => shares, + }, + }); - const { data: balance, queryKey: balanceQueryKey } = useReadContract({ + const { data: balance } = useReadContract({ address: vault.alchemist.address, chainId: chain.id, abi: alchemistV2Abi, functionName: "convertSharesToYieldTokens", args: [vault.yieldToken, sharesBalance ?? 0n], + scopeKey: ScopeKeys.LiquidateInput, query: { enabled: sharesBalance !== undefined, select: (balance) => @@ -98,12 +100,12 @@ export const LiquidateTokenInput = ({ /** * NOTE: Watch queries for changes in maximumShares, sharesBalance, and balance. - * maximumSharesQueryKey - because underlying tokens to shares uses price which changes each block; - * sharesBalanceQueryKey - if user deposited or withdrawed from vault for yield token; - * balanceQueryKey - because shares to yield token uses price which changes each block. + * maximumShares - because underlying tokens to shares uses price which changes each block; + * sharesBalance - if user deposited or withdrawed from vault for yield token; + * balance - because shares to yield token uses price which changes each block. */ useWatchQuery({ - queryKeys: [maximumSharesQueryKey, sharesBalanceQueryKey, balanceQueryKey], + scopeKey: ScopeKeys.LiquidateInput, }); const externalMaximumAmount = diff --git a/src/components/common/input/MigrateTokenInput.tsx b/src/components/common/input/MigrateTokenInput.tsx index 5e0c7111..a1939600 100644 --- a/src/components/common/input/MigrateTokenInput.tsx +++ b/src/components/common/input/MigrateTokenInput.tsx @@ -5,6 +5,7 @@ import { Vault } from "@/lib/types"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { TokenInput } from "./TokenInput"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const MigrateTokenInput = ({ amount, @@ -18,22 +19,22 @@ export const MigrateTokenInput = ({ const chain = useChain(); const { address } = useAccount(); - const { data: sharesBalance, queryKey: sharesBalanceQueryKey } = - useReadContract({ - address: vault.alchemist.address, - chainId: chain.id, - abi: alchemistV2Abi, - functionName: "positions", - args: [address!, vault.yieldToken], - query: { - enabled: !!address, - select: ([shares]) => - formatUnits(shares, vault.yieldTokenParams.decimals), - }, - }); + const { data: sharesBalance } = useReadContract({ + address: vault.alchemist.address, + chainId: chain.id, + abi: alchemistV2Abi, + functionName: "positions", + args: [address!, vault.yieldToken], + scopeKey: ScopeKeys.MigrateInput, + query: { + enabled: !!address, + select: ([shares]) => + formatUnits(shares, vault.yieldTokenParams.decimals), + }, + }); useWatchQuery({ - queryKey: sharesBalanceQueryKey, + scopeKey: ScopeKeys.MigrateInput, }); return ( diff --git a/src/components/common/input/RepayInput.tsx b/src/components/common/input/RepayInput.tsx index 3412adbf..6a18637c 100644 --- a/src/components/common/input/RepayInput.tsx +++ b/src/components/common/input/RepayInput.tsx @@ -10,6 +10,7 @@ import { TokenInput } from "./TokenInput"; import { useAccount, useReadContract } from "wagmi"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useWatchQuery } from "@/hooks/useWatchQuery"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const RepayInput = ({ amount, @@ -26,24 +27,23 @@ export const RepayInput = ({ }) => { const { address = zeroAddress } = useAccount(); - const { - data: repaymentTokenBalance, - queryKey: repaymentTokenBalanceQueryKey, - } = useReadContract({ + const { data: repaymentTokenBalance } = useReadContract({ address: repaymentToken.address, abi: erc20Abi, functionName: "balanceOf", args: [address], + scopeKey: ScopeKeys.RepayInput, query: { select: (balance) => formatUnits(balance, repaymentToken.decimals), }, }); - const { data: debtBalance, queryKey: debtQueryKey } = useReadContract({ + const { data: debtBalance } = useReadContract({ address: alchemistAddress, abi: alchemistV2Abi, functionName: "accounts", args: [address], + scopeKey: ScopeKeys.RepayInput, query: { select: (account) => (account[0] < 0n ? "0" : formatEther(account[0])), }, @@ -62,7 +62,7 @@ export const RepayInput = ({ }); useWatchQuery({ - queryKeys: [repaymentTokenBalanceQueryKey, debtQueryKey], + scopeKey: ScopeKeys.RepayInput, }); const debt = isSelectedSynthAsset ? debtBalance : debtInUnderlying; diff --git a/src/components/common/input/TokenInput.tsx b/src/components/common/input/TokenInput.tsx index 6073f859..e018a2b8 100644 --- a/src/components/common/input/TokenInput.tsx +++ b/src/components/common/input/TokenInput.tsx @@ -8,6 +8,7 @@ import { GAS_ADDRESS } from "@/lib/constants"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { Button } from "@/components/ui/button"; import { decimalNumberValidationRegex } from "@/utils/inputValidation"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const TokenInput = ({ amount, @@ -33,33 +34,34 @@ export const TokenInput = ({ const chain = useChain(); const { address } = useAccount(); - const { data: gasBalance, queryKey: gasBalanceQueryKey } = useBalance({ + const { data: gasBalance } = useBalance({ address, chainId: chain.id, + scopeKey: ScopeKeys.TokenInput, query: { enabled: !overrideBalance && tokenAddress === GAS_ADDRESS, select: (balance) => formatEther(balance.value), }, }); - const { data: tokenBalance, queryKey: tokenBalanceQueryKey } = - useReadContract({ - address: tokenAddress, - chainId: chain.id, - abi: erc20Abi, - functionName: "balanceOf", - args: [address!], - query: { - enabled: - !!address && - !overrideBalance && - tokenAddress !== GAS_ADDRESS && - tokenAddress !== zeroAddress, - select: (balance) => formatUnits(balance, tokenDecimals), - }, - }); + const { data: tokenBalance } = useReadContract({ + address: tokenAddress, + chainId: chain.id, + abi: erc20Abi, + functionName: "balanceOf", + args: [address!], + scopeKey: ScopeKeys.TokenInput, + query: { + enabled: + !!address && + !overrideBalance && + tokenAddress !== GAS_ADDRESS && + tokenAddress !== zeroAddress, + select: (balance) => formatUnits(balance, tokenDecimals), + }, + }); useWatchQuery({ - queryKeys: [gasBalanceQueryKey, tokenBalanceQueryKey], + scopeKey: ScopeKeys.TokenInput, }); const onChange = (e: React.ChangeEvent) => { diff --git a/src/components/common/input/TransmuterInput.tsx b/src/components/common/input/TransmuterInput.tsx index 9feca89a..048dfce0 100644 --- a/src/components/common/input/TransmuterInput.tsx +++ b/src/components/common/input/TransmuterInput.tsx @@ -8,6 +8,7 @@ import { formatInput, formatNumber, sanitizeNumber } from "@/utils/number"; import { cn } from "@/utils/cn"; import { Button } from "@/components/ui/button"; import { decimalNumberValidationRegex } from "@/utils/inputValidation"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const TransmuterInput = ({ amount, @@ -29,51 +30,51 @@ export const TransmuterInput = ({ const chain = useChain(); const { address } = useAccount(); - const { data: tokenBalance, queryKey: tokenBalanceQueryKey } = - useReadContract({ - address: tokenAddress, - chainId: chain.id, - abi: erc20Abi, - functionName: "balanceOf", - args: [address!], - query: { - enabled: !!address && type === "Balance", - select: (balance) => formatUnits(balance, tokenDecimals), - }, - }); + const { data: tokenBalance } = useReadContract({ + address: tokenAddress, + chainId: chain.id, + abi: erc20Abi, + functionName: "balanceOf", + args: [address!], + scopeKey: ScopeKeys.TransmuterInput, + query: { + enabled: !!address && type === "Balance", + select: (balance) => formatUnits(balance, tokenDecimals), + }, + }); - const { data: transmuterBalance, queryKey: transmuterBalanceQueryKey } = - useReadContracts({ - allowFailure: false, - contracts: [ - { - address: transmuterAddress, - abi: transmuterV2Abi, - functionName: "getUnexchangedBalance", - args: [address!], - chainId: chain.id, - }, - { - address: transmuterAddress, - abi: transmuterV2Abi, - functionName: "getClaimableBalance", - args: [address!], - chainId: chain.id, - }, - ], - query: { - enabled: !!address && type !== "Balance", - select: ([unexchangedBalance, claimableBalance]) => - [ - formatEther(unexchangedBalance), - formatUnits(claimableBalance, tokenDecimals), - ] as const, + const { data: transmuterBalance } = useReadContracts({ + allowFailure: false, + contracts: [ + { + address: transmuterAddress, + abi: transmuterV2Abi, + functionName: "getUnexchangedBalance", + args: [address!], + chainId: chain.id, }, - }); + { + address: transmuterAddress, + abi: transmuterV2Abi, + functionName: "getClaimableBalance", + args: [address!], + chainId: chain.id, + }, + ], + scopeKey: ScopeKeys.TransmuterInput, + query: { + enabled: !!address && type !== "Balance", + select: ([unexchangedBalance, claimableBalance]) => + [ + formatEther(unexchangedBalance), + formatUnits(claimableBalance, tokenDecimals), + ] as const, + }, + }); const [unexchangedBalance, claimableBalance] = transmuterBalance ?? []; useWatchQuery({ - queryKeys: [tokenBalanceQueryKey, transmuterBalanceQueryKey], + scopeKey: ScopeKeys.TransmuterInput, }); const balance = diff --git a/src/components/common/input/VaultWithdrawTokenInput.tsx b/src/components/common/input/VaultWithdrawTokenInput.tsx index d45fc1fc..2cc8b059 100644 --- a/src/components/common/input/VaultWithdrawTokenInput.tsx +++ b/src/components/common/input/VaultWithdrawTokenInput.tsx @@ -4,8 +4,9 @@ import { Vault } from "@/lib/types"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { formatEther, formatUnits, parseUnits, zeroAddress } from "viem"; import { useWatchQuery } from "@/hooks/useWatchQuery"; -import { useMemo } from "react"; import { TokenInput } from "./TokenInput"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; +import { useStaticTokenAdapterWithdraw } from "@/hooks/useStaticTokenAdapterWithdraw"; export const VaultWithdrawTokenInput = ({ amount, @@ -25,18 +26,18 @@ export const VaultWithdrawTokenInput = ({ const chain = useChain(); const { address } = useAccount(); - const { data: sharesBalance, queryKey: sharesBalanceQueryKey } = - useReadContract({ - address: vault.alchemist.address, - chainId: chain.id, - abi: alchemistV2Abi, - functionName: "positions", - args: [address!, vault.yieldToken], - query: { - enabled: !!address, - select: ([shares]) => shares, - }, - }); + const { data: sharesBalance } = useReadContract({ + address: vault.alchemist.address, + chainId: chain.id, + abi: alchemistV2Abi, + functionName: "positions", + args: [address!, vault.yieldToken], + scopeKey: ScopeKeys.VaultWithdrawInput, + query: { + enabled: !!address, + select: ([shares]) => shares, + }, + }); const { data: underlyingTokenCollateral } = useReadContract({ address: vault.alchemist.address, @@ -60,30 +61,19 @@ export const VaultWithdrawTokenInput = ({ }, }); - const { - data: totalCollateralInDebtToken, - queryKey: totalCollateralInDebtTokenQueryKey, - } = useReadContract({ + const { data: totalCollateralInDebtToken } = useReadContract({ address: vault.alchemist.address, chainId: chain.id, abi: alchemistV2Abi, functionName: "totalValue", args: [address!], + scopeKey: ScopeKeys.VaultWithdrawInput, query: { enabled: !!address, }, }); - useWatchQuery({ - queryKeys: [sharesBalanceQueryKey, totalCollateralInDebtTokenQueryKey], - }); - - const otherCoverInDebt = - totalCollateralInDebtToken !== undefined && - collateralInDebtToken !== undefined - ? totalCollateralInDebtToken - collateralInDebtToken - : 0n; - const balanceInDebt = useMemo(() => { + const balanceInDebt = (() => { if (collateralInDebtToken === undefined) { return 0n; } @@ -93,12 +83,18 @@ export const VaultWithdrawTokenInput = ({ const maxWithdrawAmount = collateralInDebtToken - requiredCoverInDebt; + const otherCoverInDebt = + totalCollateralInDebtToken !== undefined && + collateralInDebtToken !== undefined + ? totalCollateralInDebtToken - collateralInDebtToken + : 0n; + if (otherCoverInDebt >= requiredCoverInDebt) { return collateralInDebtToken; } else { return maxWithdrawAmount; } - }, [collateralInDebtToken, otherCoverInDebt, vault]); + })(); const { data: balanceForUnderlying } = useReadContract({ address: vault.alchemist.address, @@ -124,6 +120,7 @@ export const VaultWithdrawTokenInput = ({ vault.underlyingTokensParams.decimals, ), ], + scopeKey: ScopeKeys.VaultWithdrawInput, query: { enabled: balanceForUnderlying !== undefined, select: (balance) => @@ -131,8 +128,28 @@ export const VaultWithdrawTokenInput = ({ }, }); + const { balanceForYieldTokenAdapter } = useStaticTokenAdapterWithdraw({ + typeGuard: "withdrawInput", + balanceForYieldToken, + isSelectedTokenYieldToken, + vault, + }); + + /** + * NOTE: Watch queries for changes in sharesBalance, totalCollateral, and balanceForYieldToken. + * sharesBalance - if user deposited or withdrawed from vault for yield token; + * totalCollateralInDebtToken - if user deposited or withdrawed from vault for yield token; + * balanceForYieldToken - because shares to yield token uses price which changes each block. + */ + useWatchQuery({ + scopeKey: ScopeKeys.VaultWithdrawInput, + }); + const balance = isSelectedTokenYieldToken - ? balanceForYieldToken + ? vault.metadata.api.provider === "aave" && + vault.metadata.yieldTokenOverride + ? balanceForYieldTokenAdapter + : balanceForYieldToken : balanceForUnderlying; return ( diff --git a/src/components/farms/GAlcxWrapper.tsx b/src/components/farms/GAlcxWrapper.tsx index 7e818ab7..095ceec0 100644 --- a/src/components/farms/GAlcxWrapper.tsx +++ b/src/components/farms/GAlcxWrapper.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { Switch } from "../ui/switch"; import { Button } from "../ui/button"; import { @@ -122,7 +122,7 @@ export const GAlcsWrapper = () => { setAmount(""); }; - const onWrap = useCallback(() => { + const onWrap = () => { if (isApprovalNeeded) { approveConfig && approve(approveConfig.request); return; @@ -145,9 +145,9 @@ export const GAlcsWrapper = () => { description: "Unexpected error. Please contact Alchemix team.", }); } - }, [approve, approveConfig, isApprovalNeeded, wrap, wrapConfig, wrapError]); + }; - const onUnwrap = useCallback(() => { + const onUnwrap = () => { if (unwrapError) { toast.error("Error unwrapping ALCX", { description: @@ -165,7 +165,7 @@ export const GAlcsWrapper = () => { description: "Unexpected error. Please contact Alchemix team.", }); } - }, [unwrap, unwrapConfig, unwrapError]); + }; const handleOpen = () => { setOpen((prev) => !prev); diff --git a/src/components/farms/StaticExternalFarms.tsx b/src/components/farms/StaticExternalFarms.tsx index 1e49d24a..9765d2ab 100644 --- a/src/components/farms/StaticExternalFarms.tsx +++ b/src/components/farms/StaticExternalFarms.tsx @@ -23,7 +23,7 @@ export const StaticExternalFarms = () => { {externalFarms.length > 0 ? ( externalFarms.map((farm) => (
diff --git a/src/components/farms/row/CurveFarmContent.tsx b/src/components/farms/row/CurveFarmContent.tsx index 89e93cf7..6214e97c 100644 --- a/src/components/farms/row/CurveFarmContent.tsx +++ b/src/components/farms/row/CurveFarmContent.tsx @@ -1,7 +1,7 @@ import { useAllowance } from "@/hooks/useAllowance"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { CURVE } from "@/lib/config/farms"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Farm } from "@/lib/types"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; @@ -18,6 +18,7 @@ import { curveGaugeAbi } from "@/abi/curveGauge"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { useChain } from "@/hooks/useChain"; import { FarmContent } from "./FarmContent"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const CurveFarmContent = ({ farm }: { farm: Farm }) => { const chain = useChain(); @@ -27,6 +28,13 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("curve")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.CurveFarmContent, + }), + }); }, [queryClient]); const [depositAmount, setDepositAmount] = useState(""); @@ -34,18 +42,19 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { const { address = zeroAddress } = useAccount(); - const { data: withdrawBalance, queryKey: balanceQueryKey } = useReadContract({ + const { data: withdrawBalance } = useReadContract({ address: CURVE.gauge, abi: curveGaugeAbi, chainId: chain.id, functionName: "balanceOf", args: [address], + scopeKey: ScopeKeys.CurveFarmContent, query: { select: (data) => formatEther(data), }, }); useWatchQuery({ - queryKey: balanceQueryKey, + scopeKey: ScopeKeys.CurveFarmContent, }); //-- Deposit --// @@ -79,6 +88,7 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (depositReceipt) { + setDepositAmount(""); receiptCallback(); } }, [depositReceipt, queryClient, receiptCallback]); @@ -115,6 +125,7 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (withdrawReceipt) { + setWithdrawAmount(""); receiptCallback(); } }, [withdrawReceipt, queryClient, receiptCallback]); @@ -133,7 +144,11 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { args: [], }); - const { writeContract: claim, data: claimHash } = useWriteContract({ + const { + writeContract: claim, + data: claimHash, + reset: resetClaim, + } = useWriteContract({ mutation: mutationCallback({ action: "Claim", }), @@ -145,9 +160,10 @@ export const CurveFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (claimReceipt) { + resetClaim(); receiptCallback(); } - }, [claimReceipt, queryClient, receiptCallback]); + }, [claimReceipt, queryClient, receiptCallback, resetClaim]); const onClaim = () => { claimConfig && claim(claimConfig.request); diff --git a/src/components/farms/row/ExitButton.tsx b/src/components/farms/row/ExitButton.tsx index 8b7d199e..66bba24d 100644 --- a/src/components/farms/row/ExitButton.tsx +++ b/src/components/farms/row/ExitButton.tsx @@ -5,8 +5,9 @@ import { Button } from "@/components/ui/button"; import { useChain } from "@/hooks/useChain"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { CURVE, STAKING_POOL_ADDRESSES, SUSHI } from "@/lib/config/farms"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Farm } from "@/lib/types"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect } from "react"; import { toast } from "sonner"; @@ -38,12 +39,15 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { enabled: farm.type === "internal", }, }); - const { writeContract: exitInternal, data: internalExitHash } = - useWriteContract({ - mutation: mutationCallback({ - action: "Exit", - }), - }); + const { + writeContract: exitInternal, + data: internalExitHash, + reset: resetExitInternal, + } = useWriteContract({ + mutation: mutationCallback({ + action: "Exit", + }), + }); const { data: internalExitReceipt } = useWaitForTransactionReceipt({ hash: internalExitHash, }); @@ -52,8 +56,16 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("internal")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.InternalFarmContent, + }), + }); + resetExitInternal(); } - }, [internalExitReceipt, queryClient]); + }, [internalExitReceipt, queryClient, resetExitInternal]); //-- Sushi --// const { data: sushiExitConfig, error: sushiError } = useSimulateContract({ @@ -66,7 +78,11 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { enabled: !!address && farm.type === "external-sushi", }, }); - const { writeContract: exitSushi, data: sushiExitHash } = useWriteContract({ + const { + writeContract: exitSushi, + data: sushiExitHash, + reset: resetExitSushi, + } = useWriteContract({ mutation: mutationCallback({ action: "Exit", }), @@ -79,8 +95,16 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("sushi")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.SushiFarmContent, + }), + }); + resetExitSushi(); } - }, [sushiExitReceipt, queryClient]); + }, [sushiExitReceipt, queryClient, resetExitSushi]); //-- Curve --// const { data: curveExitConfig, error: curveError } = useSimulateContract({ @@ -93,7 +117,11 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { enabled: farm.type === "external-curve" && +farm.staked.amount > 0, }, }); - const { writeContract: exitCurve, data: curveExitHash } = useWriteContract({ + const { + writeContract: exitCurve, + data: curveExitHash, + reset: resetExitCurve, + } = useWriteContract({ mutation: mutationCallback({ action: "Exit", }), @@ -106,8 +134,16 @@ export const ExitButton = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("curve")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.CurveFarmContent, + }), + }); + resetExitCurve(); } - }, [curveExitReceipt, queryClient]); + }, [curveExitReceipt, queryClient, resetExitCurve]); const onExitFarm = useCallback(() => { if (farm.type === "internal") { diff --git a/src/components/farms/row/FarmContent.tsx b/src/components/farms/row/FarmContent.tsx index 7575279e..f11b1188 100644 --- a/src/components/farms/row/FarmContent.tsx +++ b/src/components/farms/row/FarmContent.tsx @@ -2,6 +2,7 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useChain } from "@/hooks/useChain"; import { useWatchQuery } from "@/hooks/useWatchQuery"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; import { cn } from "@/utils/cn"; import { isInputZero } from "@/utils/inputNotZero"; import { decimalNumberValidationRegex } from "@/utils/inputValidation"; @@ -42,12 +43,13 @@ export const FarmContent = ({ }: FarmProps) => { const chain = useChain(); const { address } = useAccount(); - const { data: balance, queryKey: balanceQueryKey } = useReadContract({ + const { data: balance } = useReadContract({ address: poolTokenAddress, chainId: chain.id, abi: erc20Abi, functionName: "balanceOf", args: [address!], + scopeKey: ScopeKeys.FarmContent, query: { enabled: !!address, select: (balance) => formatEther(balance), @@ -55,7 +57,7 @@ export const FarmContent = ({ }); useWatchQuery({ - queryKey: balanceQueryKey, + scopeKey: ScopeKeys.FarmContent, }); const onDepositChange = (e: React.ChangeEvent) => { diff --git a/src/components/farms/row/InternalFarmContent.tsx b/src/components/farms/row/InternalFarmContent.tsx index 02d14c51..f7736c12 100644 --- a/src/components/farms/row/InternalFarmContent.tsx +++ b/src/components/farms/row/InternalFarmContent.tsx @@ -3,7 +3,7 @@ import { useAllowance } from "@/hooks/useAllowance"; import { useChain } from "@/hooks/useChain"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { STAKING_POOL_ADDRESSES } from "@/lib/config/farms"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Farm } from "@/lib/types"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; @@ -19,6 +19,7 @@ import { } from "wagmi"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { FarmContent } from "./FarmContent"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const InternalFarmContent = ({ farm }: { farm: Farm }) => { const chain = useChain(); @@ -28,6 +29,13 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("internal")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.InternalFarmContent, + }), + }); }, [queryClient]); const [depositAmount, setDepositAmount] = useState(""); @@ -35,18 +43,19 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { const { address = zeroAddress } = useAccount(); - const { data: withdrawBalance, queryKey: balanceQueryKey } = useReadContract({ + const { data: withdrawBalance } = useReadContract({ address: STAKING_POOL_ADDRESSES[mainnet.id], abi: stakingPoolsAbi, chainId: chain.id, functionName: "getStakeTotalDeposited", args: [address, BigInt(farm.poolId)], + scopeKey: ScopeKeys.InternalFarmContent, query: { select: (data) => formatEther(data), }, }); useWatchQuery({ - queryKey: balanceQueryKey, + scopeKey: ScopeKeys.InternalFarmContent, }); //-- Deposit --// @@ -80,6 +89,7 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (depositReceipt) { + setDepositAmount(""); receiptCallback(); } }, [depositReceipt, queryClient, receiptCallback]); @@ -116,6 +126,7 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (withdrawReceipt) { + setWithdrawAmount(""); receiptCallback(); } }, [withdrawReceipt, queryClient, receiptCallback]); @@ -133,7 +144,11 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { args: [BigInt(farm.poolId)], }); - const { writeContract: claim, data: claimHash } = useWriteContract({ + const { + writeContract: claim, + data: claimHash, + reset: resetClaim, + } = useWriteContract({ mutation: mutationCallback({ action: "Claim", }), @@ -145,9 +160,10 @@ export const InternalFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (claimReceipt) { + resetClaim(); receiptCallback(); } - }, [claimReceipt, queryClient, receiptCallback]); + }, [claimReceipt, queryClient, receiptCallback, resetClaim]); const onClaim = () => { claimConfig && claim(claimConfig.request); diff --git a/src/components/farms/row/SushiFarmContent.tsx b/src/components/farms/row/SushiFarmContent.tsx index ae5c6009..20d72e29 100644 --- a/src/components/farms/row/SushiFarmContent.tsx +++ b/src/components/farms/row/SushiFarmContent.tsx @@ -2,7 +2,7 @@ import { useAllowance } from "@/hooks/useAllowance"; import { useChain } from "@/hooks/useChain"; import { useWatchQuery } from "@/hooks/useWatchQuery"; import { SUSHI } from "@/lib/config/farms"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Farm } from "@/lib/types"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; @@ -18,6 +18,7 @@ import { import { sushiMasterchefAbi } from "@/abi/sushiMasterchef"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { FarmContent } from "./FarmContent"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const SushiFarmContent = ({ farm }: { farm: Farm }) => { const chain = useChain(); @@ -27,6 +28,13 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Farms("curve")], }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.SushiFarmContent, + }), + }); }, [queryClient]); const [depositAmount, setDepositAmount] = useState(""); @@ -34,18 +42,19 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { const { address = zeroAddress } = useAccount(); - const { data: withdrawBalance, queryKey: balanceQueryKey } = useReadContract({ + const { data: withdrawBalance } = useReadContract({ address: SUSHI.masterchef, abi: sushiMasterchefAbi, chainId: chain.id, functionName: "userInfo", args: [0n, address], + scopeKey: ScopeKeys.SushiFarmContent, query: { select: ([balance]) => formatEther(balance), }, }); useWatchQuery({ - queryKey: balanceQueryKey, + scopeKey: ScopeKeys.SushiFarmContent, }); //-- Deposit --// @@ -79,6 +88,7 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (depositReceipt) { + setDepositAmount(""); receiptCallback(); } }, [depositReceipt, queryClient, receiptCallback]); @@ -115,6 +125,7 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (withdrawReceipt) { + setWithdrawAmount(""); receiptCallback(); } }, [withdrawReceipt, queryClient, receiptCallback]); @@ -132,7 +143,11 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { args: [0n, address], }); - const { writeContract: claim, data: claimHash } = useWriteContract({ + const { + writeContract: claim, + data: claimHash, + reset: resetClaim, + } = useWriteContract({ mutation: mutationCallback({ action: "Claim", }), @@ -144,9 +159,10 @@ export const SushiFarmContent = ({ farm }: { farm: Farm }) => { useEffect(() => { if (claimReceipt) { + resetClaim(); receiptCallback(); } - }, [claimReceipt, queryClient, receiptCallback]); + }, [claimReceipt, queryClient, receiptCallback, resetClaim]); const onClaim = () => { claimConfig && claim(claimConfig.request); diff --git a/src/components/governance/row/ProposalAccordionRow.tsx b/src/components/governance/row/ProposalAccordionRow.tsx index 3fd25733..707b2ff8 100644 --- a/src/components/governance/row/ProposalAccordionRow.tsx +++ b/src/components/governance/row/ProposalAccordionRow.tsx @@ -1,5 +1,5 @@ import { getAddress } from "viem"; -import { Fragment, useMemo, useState } from "react"; +import { Fragment, useState } from "react"; import { useAccount, useWalletClient } from "wagmi"; import { toast } from "sonner"; import { @@ -68,24 +68,21 @@ export const ProposalsAccordionRow = ({ proposal }: { proposal: Proposal }) => { const isSupported = supportedTypes.indexOf(proposal.type) !== -1; - const message = useMemo(() => { - const choice = proposal.choices.indexOf(selectedChoice) + 1; - return { - choice, - proposal: proposal.id, - app: "alchemix", - space: "alchemixstakers.eth", - type: proposal.type, - metadata: "{}", - reason: "", - }; - }, [proposal, selectedChoice]); - const { mutate: writeVote, isPending } = useMutation({ mutationFn: async () => { if (!address) throw new Error("Not connected."); if (!walletClient) throw new Error("No wallet."); + const message = { + choice: proposal.choices.indexOf(selectedChoice) + 1, + proposal: proposal.id, + app: "alchemix", + space: "alchemixstakers.eth", + type: proposal.type, + metadata: "{}", + reason: "", + }; + const type2 = message.proposal.startsWith("0x"); const types = type2 ? { diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 20e3a539..3cb381bb 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -4,7 +4,7 @@ import { ToOptions } from "@tanstack/react-router"; import { IS_TENDERLY_FORK } from "@/lib/wagmi/tenderly"; export const routeTitleToPathMapping = { - Vaults: { to: "/vaults", icon: "/images/icons/yield_med.svg" }, + Vaults: { to: "/vaults", icon: "/images/icons/vaults_med.svg" }, Transmuters: { to: "/transmuters", icon: "/images/icons/transmuter_med.svg" }, Bridge: { to: "/bridge", icon: "/images/icons/swap_med.svg" }, Farms: { to: "/farms", icon: "/images/icons/farm_med.svg" }, @@ -16,7 +16,7 @@ export type RouteTitle = keyof typeof routeTitleToPathMapping; export function Header() { return ( -
+
@@ -23,9 +26,16 @@ export function LeftBlock() { )} + diff --git a/src/components/providers/QueryProvider.tsx b/src/components/providers/QueryProvider.tsx index d83ec8d8..47a1e5bf 100644 --- a/src/components/providers/QueryProvider.tsx +++ b/src/components/providers/QueryProvider.tsx @@ -6,7 +6,7 @@ import { import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { ContractFunctionExecutionError } from "viem"; -const queryClient = new QueryClient({ +export const queryClient = new QueryClient({ queryCache: new QueryCache({ onError: (e, q) => { if (import.meta.env.PROD) return; diff --git a/src/components/providers/SettingsProvider.tsx b/src/components/providers/SettingsProvider.tsx new file mode 100644 index 00000000..025e274c --- /dev/null +++ b/src/components/providers/SettingsProvider.tsx @@ -0,0 +1,47 @@ +import { createContext, useCallback, useContext, useState } from "react"; + +import { lsService } from "@/lib/localStorage"; +import { SupportedCurrency } from "@/lib/types"; + +interface SettingsStore { + currency: SupportedCurrency; + handleCurrencyChange: () => void; +} + +const defaultValue: SettingsStore = { + currency: "USD", + handleCurrencyChange: () => {}, +}; + +const SettingsContext = createContext(defaultValue); + +export const useSettings = () => { + return useContext(SettingsContext); +}; + +export const SettingsProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + const initialCurrency = lsService.getItem(0, "currency"); + const [currency, setCurrency] = useState( + initialCurrency ?? defaultValue.currency, + ); + + const handleCurrencyChange = useCallback(() => { + if (currency === "USD") { + setCurrency("ETH"); + lsService.setItem(0, "currency", "ETH"); + return; + } + setCurrency("USD"); + lsService.setItem(0, "currency", "USD"); + }, [currency]); + + return ( + + {children} + + ); +}; diff --git a/src/components/sentinel/Sentinel.tsx b/src/components/sentinel/Sentinel.tsx index 92b21a48..8937e868 100644 --- a/src/components/sentinel/Sentinel.tsx +++ b/src/components/sentinel/Sentinel.tsx @@ -86,7 +86,11 @@ export const Sentinel = () => { isPendingVaults || isPendingTransmuters; - const { writeContract, data: hash } = useWriteContract({ + const { + writeContract, + data: hash, + reset: resetSentinelTx, + } = useWriteContract({ mutation: mutationCallback({ action: "Sentinel", }), @@ -107,8 +111,9 @@ export const Sentinel = () => { queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults], }); + resetSentinelTx(); } - }, [pausedQueryKey, queryClient, receipt]); + }, [pausedQueryKey, queryClient, receipt, resetSentinelTx]); const toggleAlTokenState = ({ address, diff --git a/src/components/transmuters/row/Claim.tsx b/src/components/transmuters/row/Claim.tsx index 60b2cf1f..89116f36 100644 --- a/src/components/transmuters/row/Claim.tsx +++ b/src/components/transmuters/row/Claim.tsx @@ -1,13 +1,14 @@ import { transmuterV2Abi } from "@/abi/transmuterV2"; +import { CtaButton } from "@/components/common/CtaButton"; import { TransmuterInput } from "@/components/common/input/TransmuterInput"; -import { Button } from "@/components/ui/button"; import { useChain } from "@/hooks/useChain"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Token, Transmuter } from "@/lib/types"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { toast } from "sonner"; import { parseUnits } from "viem"; import { @@ -34,7 +35,7 @@ export const Claim = ({ const { data: claimConfig, - isFetching, + isPending, error: claimConfigError, } = useSimulateContract({ address: transmuter.address, @@ -61,10 +62,17 @@ export const Claim = ({ if (claimReceipt) { setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Transmuters] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.TransmuterInput, + }), + }); } }, [claimReceipt, queryClient]); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (claimConfigError) { toast.error("Claim failed", { description: @@ -81,7 +89,7 @@ export const Claim = ({ description: "Unknown error occurred. Please contact Alchemix team.", }); } - }, [claim, claimConfig, claimConfigError]); + }; return ( <> @@ -95,13 +103,13 @@ export const Claim = ({ tokenDecimals={underlyingToken.decimals} /> - + ); }; diff --git a/src/components/transmuters/row/Deposit.tsx b/src/components/transmuters/row/Deposit.tsx index 872f4037..6ab3cd2d 100644 --- a/src/components/transmuters/row/Deposit.tsx +++ b/src/components/transmuters/row/Deposit.tsx @@ -1,14 +1,15 @@ import { transmuterV2Abi } from "@/abi/transmuterV2"; +import { CtaButton } from "@/components/common/CtaButton"; import { TransmuterInput } from "@/components/common/input/TransmuterInput"; -import { Button } from "@/components/ui/button"; import { useAllowance } from "@/hooks/useAllowance"; import { useChain } from "@/hooks/useChain"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Token, Transmuter } from "@/lib/types"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { toast } from "sonner"; import { parseEther } from "viem"; import { @@ -33,7 +34,13 @@ export const Deposit = ({ const [depositAmount, setDepositAmount] = useState(""); - const { isApprovalNeeded, approve, approveConfig } = useAllowance({ + const { + isApprovalNeeded, + approve, + approveConfig, + isPending: isPendingAllowance, + isFetching: isFetchingAllowance, + } = useAllowance({ tokenAddress: syntheticToken.address, spender: transmuter.address, amount: depositAmount, @@ -42,7 +49,7 @@ export const Deposit = ({ const { data: depositConfig, - isFetching, + isPending: isPendingDepositConfig, error: depositConfigError, } = useSimulateContract({ address: transmuter.address, @@ -70,10 +77,17 @@ export const Deposit = ({ if (depositReceipt) { setDepositAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Transmuters] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.TransmuterInput, + }), + }); } }, [depositReceipt, queryClient]); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (isApprovalNeeded === true) { approveConfig && approve(approveConfig.request); return; @@ -96,14 +110,12 @@ export const Deposit = ({ description: "Unkown error. Please contact Alchemix team.", }); } - }, [ - isApprovalNeeded, - depositConfigError, - depositConfig, - approveConfig, - approve, - deposit, - ]); + }; + + const isPending = + isApprovalNeeded === false + ? isPendingDepositConfig + : isPendingAllowance || isFetchingAllowance; return ( <> @@ -116,13 +128,14 @@ export const Deposit = ({ type="Balance" transmuterAddress={transmuter.address} /> - + ); }; diff --git a/src/components/transmuters/row/TransmuterAccordionRow.tsx b/src/components/transmuters/row/TransmuterAccordionRow.tsx index b44e733e..828260d9 100644 --- a/src/components/transmuters/row/TransmuterAccordionRow.tsx +++ b/src/components/transmuters/row/TransmuterAccordionRow.tsx @@ -10,7 +10,7 @@ import { Transmuter } from "@/lib/types"; import { Deposit } from "./Deposit"; import { Withdraw } from "./Withdraw"; import { Claim } from "./Claim"; -import { TransmuterApy } from "./TransmuterApy"; +import { TransmuterApr } from "./TransmuterApr"; export const TransmuterAccordionRow = ({ transmuter, @@ -90,7 +90,7 @@ export const TransmuterAccordionRow = ({ )}
- +
diff --git a/src/components/transmuters/row/TransmuterApr.tsx b/src/components/transmuters/row/TransmuterApr.tsx new file mode 100644 index 00000000..104e9d83 --- /dev/null +++ b/src/components/transmuters/row/TransmuterApr.tsx @@ -0,0 +1,135 @@ +import { useQuery } from "@tanstack/react-query"; +import { InfoIcon } from "lucide-react"; + +import { dayjs } from "@/lib/dayjs"; +import { Transmuter } from "@/lib/types"; +import { formatNumber } from "@/utils/number"; +import { QueryKeys } from "@/lib/queries/queriesSchema"; + +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { ONE_DAY_IN_MS } from "@/lib/constants"; + +interface TransmuterAprDuneQueryResponse { + execution_id: string; + query_id: number; + is_execution_finished: boolean; + state: string; + submitted_at: string; + expires_at: string; + execution_started_at: string; + execution_ended_at: string; + result: { + rows: [ + { + projected_yield_rate: number; + time_to_transmute: number; + }, + ]; + metadata: { + column_names: string[]; + column_types: string[]; + row_count: number; + result_set_bytes: number; + total_row_count: number; + total_result_set_bytes: number; + datapoint_count: number; + pending_time_millis: number; + execution_time_millis: number; + }; + }; +} + +const DUNE_API_ENDPOINT = "https://api.dune.com/api/v1/query"; +const API_KEY = import.meta.env.VITE_DUNE_API_KEY; + +export const TransmuterApr = ({ transmuter }: { transmuter: Transmuter }) => { + const { data, isError, isPending } = useQuery({ + queryKey: [ + QueryKeys.TransmuterApr, + transmuter.address, + transmuter.metadata.aprQueryUri, + ], + queryFn: async () => { + const response = await fetch( + `${DUNE_API_ENDPOINT}/${transmuter.metadata.aprQueryUri}/results?api_key=${API_KEY}`, + ); + const data = (await response.json()) as TransmuterAprDuneQueryResponse; + + const apr = data.result.rows[0].projected_yield_rate; + const timeToTransmute = data.result.rows[0].time_to_transmute; + + if (apr === undefined || timeToTransmute === undefined) { + throw new Error("APR fetch failed."); + } + + return { + apr, + timeToTransmute, + }; + }, + enabled: !!transmuter.metadata.aprQueryUri, + staleTime: ONE_DAY_IN_MS, + retry: false, + }); + return ( +
+
+

APR

+ +
+
+

+ {isError || !transmuter.metadata.aprQueryUri + ? "N/A" + : isPending + ? "..." + : `${formatNumber(data.apr, { allowNegative: false })}%`} +

+ {!!data?.timeToTransmute && ( +

+ {formatNumber( + dayjs.duration({ years: data.timeToTransmute }).asDays(), + )}{" "} + days +

+ )} +
+
+ ); +}; + +const TransmuterAprPopover = () => { + return ( + + + + + e.stopPropagation()}> +

+ Users are credited with corresponding assets based on the deposited + alAsset amount. +
+ The alAsset is burned when user claims the transmuted token. +
+
+ This APR assumes open-market alAsset buy and 1:1 transmute. +

+
+
+ Learn more. + + + + ); +}; diff --git a/src/components/transmuters/row/TransmuterApy.tsx b/src/components/transmuters/row/TransmuterApy.tsx deleted file mode 100644 index af6621b7..00000000 --- a/src/components/transmuters/row/TransmuterApy.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { useQuery } from "@tanstack/react-query"; -import { InfoIcon } from "lucide-react"; - -import { dayjs } from "@/lib/dayjs"; -import { Transmuter } from "@/lib/types"; -import { formatNumber } from "@/utils/number"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; - -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { ONE_DAY_IN_MS } from "@/lib/constants"; - -interface TransmuterApyDuneQueryResponse { - execution_id: string; - query_id: number; - is_execution_finished: boolean; - state: string; - submitted_at: string; - expires_at: string; - execution_started_at: string; - execution_ended_at: string; - result: { - rows: [ - { - projected_yield_rate: number; - time_to_transmute: number; - }, - ]; - metadata: { - column_names: string[]; - column_types: string[]; - row_count: number; - result_set_bytes: number; - total_row_count: number; - total_result_set_bytes: number; - datapoint_count: number; - pending_time_millis: number; - execution_time_millis: number; - }; - }; -} - -const DUNE_API_ENDPOINT = "https://api.dune.com/api/v1/query"; -const API_KEY = import.meta.env.VITE_DUNE_API_KEY; - -export const TransmuterApy = ({ transmuter }: { transmuter: Transmuter }) => { - const { data, isError, isPending } = useQuery({ - queryKey: [ - QueryKeys.TransmuterApy, - transmuter.address, - transmuter.metadata.apyQueryUri, - ], - queryFn: async () => { - const response = await fetch( - `${DUNE_API_ENDPOINT}/${transmuter.metadata.apyQueryUri}/results?api_key=${API_KEY}`, - ); - const data = (await response.json()) as TransmuterApyDuneQueryResponse; - - const apy = data.result.rows[0].projected_yield_rate; - const timeToTransmute = data.result.rows[0].time_to_transmute; - - if (!apy) { - throw new Error("APY is not available."); - } - - return { - apy, - timeToTransmute, - }; - }, - enabled: !!transmuter.metadata.apyQueryUri, - staleTime: ONE_DAY_IN_MS, - retry: false, - }); - return ( -
-

APY

- {isError || !transmuter.metadata.apyQueryUri ? ( -
-

N/A

- -
- ) : isPending ? ( -

...

- ) : ( -
-

{formatNumber(data.apy, { allowNegative: false })}%

- -
- )} -
- ); -}; - -const TransmuterApyPopover = ({ - timeToTransmute, -}: { - timeToTransmute: number; -}) => { - return ( - - - - - - {timeToTransmute > 0 && ( -

- It will take approximately{" "} - - {formatNumber( - dayjs.duration({ years: timeToTransmute }).asDays(), - )}{" "} - days - {" "} - to transmute your deposit. -

- )} -

- Yield will increase, if more people deposit to - Alchemix, or liquidate/repay their loans. Yield will{" "} - decrease, if more people deposit alTOKEN in the - Transmuter. -

-
-
- ); -}; - -const NAPopover = ({ isError }: { isError: boolean }) => { - return ( - - - - - -

{isError ? "Error. Report to Alchemix" : "Coming soon!"}

-
-
- ); -}; diff --git a/src/components/transmuters/row/Withdraw.tsx b/src/components/transmuters/row/Withdraw.tsx index 6a231d0b..bf6bb017 100644 --- a/src/components/transmuters/row/Withdraw.tsx +++ b/src/components/transmuters/row/Withdraw.tsx @@ -1,13 +1,14 @@ import { transmuterV2Abi } from "@/abi/transmuterV2"; +import { CtaButton } from "@/components/common/CtaButton"; import { TransmuterInput } from "@/components/common/input/TransmuterInput"; -import { Button } from "@/components/ui/button"; import { useChain } from "@/hooks/useChain"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { Token, Transmuter } from "@/lib/types"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; import { isInputZero } from "@/utils/inputNotZero"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { toast } from "sonner"; import { parseEther } from "viem"; import { @@ -34,7 +35,7 @@ export const Withdraw = ({ const { data: withdrawConfig, - isFetching, + isPending, error: withdrawConfigError, } = useSimulateContract({ address: transmuter.address, @@ -61,10 +62,17 @@ export const Withdraw = ({ if (withdrawReceipt) { setWithdrawAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Transmuters] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.TransmuterInput, + }), + }); } }, [withdrawReceipt, queryClient]); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (withdrawConfigError) { toast.error("Withdraw failed", { description: @@ -81,7 +89,7 @@ export const Withdraw = ({ description: "Unknown error occurred. Please contact Alchemix team.", }); } - }, [withdraw, withdrawConfig, withdrawConfigError]); + }; return ( <> @@ -95,13 +103,13 @@ export const Withdraw = ({ tokenDecimals={syntheticToken.decimals} /> - + ); }; diff --git a/src/components/vaults/common_actions/Borrow.tsx b/src/components/vaults/common_actions/Borrow.tsx index 30160725..b7be9671 100644 --- a/src/components/vaults/common_actions/Borrow.tsx +++ b/src/components/vaults/common_actions/Borrow.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { BorrowInput } from "@/components/common/input/BorrowInput"; import { Select, @@ -23,12 +23,14 @@ import { useChain } from "@/hooks/useChain"; import { useQueryClient } from "@tanstack/react-query"; import { ALCHEMISTS_METADATA, SYNTH_ASSETS } from "@/lib/config/alchemists"; import { isInputZero } from "@/utils/inputNotZero"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { Switch } from "@/components/ui/switch"; import { AnimatePresence, m } from "framer-motion"; import { Input } from "@/components/ui/input"; import { accordionTransition, accordionVariants } from "@/lib/motion/motion"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; +import { CtaButton } from "@/components/common/CtaButton"; export const Borrow = () => { const queryClient = useQueryClient(); @@ -76,7 +78,7 @@ export const Borrow = () => { const { data: borrowConfig, error: borrowError, - isFetching, + isPending, } = useSimulateContract({ address: alchemistForDebtTokenAddress, abi: alchemistV2Abi, @@ -103,6 +105,13 @@ export const Borrow = () => { setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.BorrowInput, + }), + }); } }, [borrowReceipt, queryClient]); @@ -123,7 +132,7 @@ export const Borrow = () => { setConfirmedDifferentAddress(checked); }; - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (borrowError) { toast.error("Borrow failed", { description: @@ -141,7 +150,7 @@ export const Borrow = () => { "Borrow failed. Unexpected. Please contract Alchemix team.", }); } - }, [borrow, borrowConfig, borrowError]); + }; return (
@@ -239,19 +248,19 @@ export const Borrow = () => { )}
- + )}
diff --git a/src/components/vaults/common_actions/DebtSelection.tsx b/src/components/vaults/common_actions/DebtSelection.tsx index d34fdb5a..928f0cd9 100644 --- a/src/components/vaults/common_actions/DebtSelection.tsx +++ b/src/components/vaults/common_actions/DebtSelection.tsx @@ -7,6 +7,7 @@ import { useWatchQuery } from "@/hooks/useWatchQuery"; import { useChain } from "@/hooks/useChain"; import { formatNumber } from "@/utils/number"; import { cn } from "@/utils/cn"; +import { ScopeKeys } from "@/lib/queries/queriesSchema"; export const DebtSelection = ({ selectedSynthAsset, @@ -20,7 +21,7 @@ export const DebtSelection = ({ const chain = useChain(); const { address } = useAccount(); - const { data: debts, queryKey: debtsQueryKey } = useReadContracts({ + const { data: debts } = useReadContracts({ allowFailure: false, contracts: availableSynthAssets.map( (synthAsset) => @@ -32,6 +33,7 @@ export const DebtSelection = ({ args: [address!], }) as const, ), + scopeKey: ScopeKeys.DebtSelection, query: { select: (accounts) => accounts.map(([debt]) => debt), enabled: !!address, @@ -39,7 +41,7 @@ export const DebtSelection = ({ }); useWatchQuery({ - queryKey: debtsQueryKey, + scopeKey: ScopeKeys.DebtSelection, }); return ( diff --git a/src/components/vaults/common_actions/Liquidate.tsx b/src/components/vaults/common_actions/Liquidate.tsx index 51636506..c5d44306 100644 --- a/src/components/vaults/common_actions/Liquidate.tsx +++ b/src/components/vaults/common_actions/Liquidate.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Select, SelectTrigger, @@ -7,7 +7,6 @@ import { SelectItem, } from "@/components/ui/select"; import { useTokensQuery } from "@/lib/queries/useTokensQuery"; -import { Button } from "@/components/ui/button"; import { useReadContract, useSimulateContract, @@ -25,12 +24,14 @@ import { DebtSelection } from "@/components/vaults/common_actions/DebtSelection" import { calculateMinimumOut } from "@/utils/helpers/minAmountWithSlippage"; import { useVaults } from "@/lib/queries/useVaults"; import { isInputZero } from "@/utils/inputNotZero"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { LiquidateTokenInput } from "@/components/common/input/LiquidateInput"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { Switch } from "@/components/ui/switch"; import { SlippageInput } from "@/components/common/input/SlippageInput"; import { MAX_UINT256_BN } from "@/lib/constants"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; +import { CtaButton } from "@/components/common/CtaButton"; export const Liquidate = () => { const queryClient = useQueryClient(); @@ -120,7 +121,7 @@ export const Liquidate = () => { const { data: liquidateConfig, - isFetching, + isPending, error: liquidateError, } = useSimulateContract({ address: ALCHEMISTS_METADATA[chain.id][selectedSynthAsset], @@ -156,6 +157,13 @@ export const Liquidate = () => { setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.LiquidateInput, + }), + }); } }, [liquidateReceipt, queryClient, chain.id]); @@ -186,7 +194,7 @@ export const Liquidate = () => { setConfirmedLiquidation(checked); }; - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (liquidateError) { toast.error("Liquidate failed", { description: @@ -204,7 +212,7 @@ export const Liquidate = () => { description: "Unknown error. Please contact Alchemix team.", }); } - }, [liquidate, liquidateConfig, liquidateError]); + }; return (
@@ -270,16 +278,14 @@ export const Liquidate = () => { repay the outstanding debt
- + Liquidate + )}
diff --git a/src/components/vaults/common_actions/Repay.tsx b/src/components/vaults/common_actions/Repay.tsx index 748e4e0b..70a0163d 100644 --- a/src/components/vaults/common_actions/Repay.tsx +++ b/src/components/vaults/common_actions/Repay.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Select, SelectTrigger, @@ -7,7 +7,6 @@ import { SelectItem, } from "@/components/ui/select"; import { useTokensQuery } from "@/lib/queries/useTokensQuery"; -import { Button } from "@/components/ui/button"; import { useAccount, useSimulateContract, @@ -25,9 +24,11 @@ import { useAlchemists } from "@/lib/queries/useAlchemists"; import { useAllowance } from "@/hooks/useAllowance"; import { DebtSelection } from "@/components/vaults/common_actions/DebtSelection"; import { isInputZero } from "@/utils/inputNotZero"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { RepayInput } from "@/components/common/input/RepayInput"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; +import { CtaButton } from "@/components/common/CtaButton"; export const Repay = () => { const queryClient = useQueryClient(); @@ -74,17 +75,23 @@ export const Repay = () => { (token) => token.address === repaymentTokenAddress, ); - const { isApprovalNeeded, approve, approveConfig, approveUsdtEthConfig } = - useAllowance({ - tokenAddress: repaymentToken?.address, - spender: ALCHEMISTS_METADATA[chain.id][selectedSynthAsset], - amount, - decimals: repaymentToken?.decimals, - }); + const { + isApprovalNeeded, + approve, + approveConfig, + approveUsdtEthConfig, + isPending: isPendingAllowance, + isFetching: isFetchingAllowance, + } = useAllowance({ + tokenAddress: repaymentToken?.address, + spender: ALCHEMISTS_METADATA[chain.id][selectedSynthAsset], + amount, + decimals: repaymentToken?.decimals, + }); const { data: burnConfig, - isFetching: isFetchingBurnConfig, + isPending: isPendingBurnConfig, error: burnConfigError, } = useSimulateContract({ address: ALCHEMISTS_METADATA[chain.id][selectedSynthAsset], @@ -105,7 +112,7 @@ export const Repay = () => { const { data: repayConfig, - isFetching: isFetchingRepayConfig, + isPending: isPendingRepayConfig, error: repayConfigError, } = useSimulateContract({ address: ALCHEMISTS_METADATA[chain.id][selectedSynthAsset], @@ -144,6 +151,13 @@ export const Repay = () => { setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.RepayInput, + }), + }); } }, [repayReceipt, queryClient]); @@ -161,7 +175,7 @@ export const Repay = () => { setSelectedSynthAsset(newSynthAsset); }; - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (isApprovalNeeded) { if (approveUsdtEthConfig?.request) { approve(approveUsdtEthConfig.request); @@ -211,24 +225,15 @@ export const Repay = () => { "Repay failed. Unknown error. Please contact Alchemix team.", }); } - }, [ - approve, - approveConfig?.request, - approveUsdtEthConfig?.request, - burnConfig, - burnConfigError, - isApprovalNeeded, - repay, - repayConfig, - repayConfigError, - repaymentToken?.symbol, - selectedSynthAsset, - ]); + }; - const isFetching = - repaymentToken?.symbol.toLowerCase() === selectedSynthAsset.toLowerCase() - ? isFetchingBurnConfig - : isFetchingRepayConfig; + const isPending = + isApprovalNeeded === false + ? repaymentToken?.symbol.toLowerCase() === + selectedSynthAsset.toLowerCase() + ? isPendingBurnConfig + : isPendingRepayConfig + : isPendingAllowance || isFetchingAllowance; return (
@@ -283,16 +288,16 @@ export const Repay = () => { } />
- + )}
diff --git a/src/components/vaults/row/Deposit.tsx b/src/components/vaults/row/Deposit.tsx index 9e527940..2c01aaf8 100644 --- a/src/components/vaults/row/Deposit.tsx +++ b/src/components/vaults/row/Deposit.tsx @@ -1,7 +1,6 @@ import { Token, Vault } from "@/lib/types"; import { TokenInput } from "@/components/common/input/TokenInput"; -import { Button } from "@/components/ui/button"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { Select, SelectTrigger, @@ -19,6 +18,7 @@ import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useChain } from "@/hooks/useChain"; import { SlippageInput } from "@/components/common/input/SlippageInput"; import { VaultActionMotionDiv } from "./motion"; +import { CtaButton } from "@/components/common/CtaButton"; export const Deposit = ({ vault, @@ -80,7 +80,7 @@ export const Deposit = ({ const isSelectedTokenYieldToken = token.address.toLowerCase() === yieldTokenData.address.toLowerCase(); - const { isApprovalNeeded, writeApprove, writeDeposit, isFetching } = + const { isApprovalNeeded, writeApprove, writeDeposit, isPending } = useDeposit({ vault, selectedToken: token, @@ -90,13 +90,13 @@ export const Deposit = ({ setAmount, }); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (token.address !== GAS_ADDRESS && isApprovalNeeded === true) { writeApprove(); } else { writeDeposit(); } - }, [token, isApprovalNeeded, writeApprove, writeDeposit]); + }; return ( @@ -139,20 +139,20 @@ export const Deposit = ({ {!isSelectedTokenYieldToken && ( )} - +
); diff --git a/src/components/vaults/row/Migrate.tsx b/src/components/vaults/row/Migrate.tsx index 5d6c12de..8f94baeb 100644 --- a/src/components/vaults/row/Migrate.tsx +++ b/src/components/vaults/row/Migrate.tsx @@ -6,13 +6,13 @@ import { SelectContent, SelectItem, } from "@/components/ui/select"; -import { Button } from "@/components/ui/button"; -import { useCallback, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { useMigrate } from "@/lib/mutations/useMigrate"; import { MigrateTokenInput } from "@/components/common/input/MigrateTokenInput"; import { isInputZero } from "@/utils/inputNotZero"; import { useTokensQuery } from "@/lib/queries/useTokensQuery"; import { VaultActionMotionDiv } from "./motion"; +import { CtaButton } from "@/components/common/CtaButton"; export const Migrate = ({ vault, @@ -45,7 +45,7 @@ export const Migrate = ({ writeWithdrawApprove, writeMintApprove, writeMigrate, - isFetching, + isPending, } = useMigrate({ currentVault: vault, amount, @@ -53,7 +53,7 @@ export const Migrate = ({ selectedVault, }); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (isApprovalNeededWithdraw === true) { writeWithdrawApprove(); return; @@ -63,13 +63,7 @@ export const Migrate = ({ return; } writeMigrate(); - }, [ - isApprovalNeededMint, - isApprovalNeededWithdraw, - writeMigrate, - writeMintApprove, - writeWithdrawApprove, - ]); + }; return ( @@ -120,20 +114,20 @@ export const Migrate = ({ vault={vault} /> - + ); diff --git a/src/components/vaults/row/VaultAccordionRow.tsx b/src/components/vaults/row/VaultAccordionRow.tsx index 6c27bb5f..3b19f7ca 100644 --- a/src/components/vaults/row/VaultAccordionRow.tsx +++ b/src/components/vaults/row/VaultAccordionRow.tsx @@ -30,6 +30,7 @@ import { QueryKeys } from "@/lib/queries/queriesSchema"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import { Progress } from "@/components/ui/progress"; +import { useSettings } from "@/components/providers/SettingsProvider"; type ContentAction = "deposit" | "withdraw" | "migrate" | "info"; @@ -279,26 +280,29 @@ export const CurrencyCell = ({ tokenDecimals: number | undefined; tokenSymbol: string | undefined; }) => { + const { currency } = useSettings(); + const tokenAmountFormated = formatUnits(tokenAmount, tokenDecimals); const { data: tokenPrice } = useGetTokenPrice(tokenAddress); const isDust = !greaterThan([tokenAmount, tokenDecimals], [5n, 18]); - const amountInUsd = + const amountInCurrency = tokenPrice && !isDust ? toString(multiply(tokenPrice, [tokenAmount, tokenDecimals])) : 0; return ( -
+

{formatNumber(tokenAmountFormated, { dustToZero: true, tokenDecimals })}{" "} {tokenSymbol}

{tokenPrice && (

- {formatNumber(amountInUsd, { + {formatNumber(amountInCurrency, { decimals: 2, isCurrency: true, + currency, dustToZero: true, tokenDecimals, })} diff --git a/src/components/vaults/row/VaultsMetrics.tsx b/src/components/vaults/row/VaultsMetrics.tsx index f6fbe95e..47239eb4 100644 --- a/src/components/vaults/row/VaultsMetrics.tsx +++ b/src/components/vaults/row/VaultsMetrics.tsx @@ -10,11 +10,14 @@ import { useTokensQuery } from "@/lib/queries/useTokensQuery"; import { useVaults } from "@/lib/queries/useVaults"; import { Token, Vault } from "@/lib/types"; import { formatNumber } from "@/utils/number"; +import { useSettings } from "@/components/providers/SettingsProvider"; export const VaultsMetrics = () => { + const { currency } = useSettings(); + const { data: alchemists } = useAlchemists(); const { data: vaults } = useVaults(); - // TODO: DefiLlama has missing price for alETH on Arb. Possible somewhere else too. So we take underlying price. Which is more than real value, but better than 0. + const debtTokenPrices = useGetMultipleTokenPrices( alchemists?.map((alchemist) => alchemist.underlyingTokens[0]), ); @@ -53,7 +56,11 @@ export const VaultsMetrics = () => {

- {formatNumber(totalDeposit, { decimals: 2, isCurrency: true })} + {formatNumber(totalDeposit, { + decimals: 2, + isCurrency: true, + currency, + })}
@@ -67,6 +74,7 @@ export const VaultsMetrics = () => { decimals: 2, isCurrency: true, allowNegative: false, + currency, })} @@ -81,6 +89,7 @@ export const VaultsMetrics = () => { decimals: 2, isCurrency: true, allowNegative: false, + currency, })} @@ -91,7 +100,11 @@ export const VaultsMetrics = () => {
- {formatNumber(globalTVL, { decimals: 2, isCurrency: true })} + {formatNumber(globalTVL, { + decimals: 2, + isCurrency: true, + currency, + })}
diff --git a/src/components/vaults/row/Withdraw.tsx b/src/components/vaults/row/Withdraw.tsx index 7982d3b0..e4333d21 100644 --- a/src/components/vaults/row/Withdraw.tsx +++ b/src/components/vaults/row/Withdraw.tsx @@ -1,6 +1,5 @@ import { Token, Vault } from "@/lib/types"; -import { Button } from "@/components/ui/button"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { Select, SelectTrigger, @@ -17,6 +16,7 @@ import { formatNumber } from "@/utils/number"; import { formatEther } from "viem"; import { SlippageInput } from "@/components/common/input/SlippageInput"; import { VaultActionMotionDiv } from "./motion"; +import { CtaButton } from "@/components/common/CtaButton"; export const Withdraw = ({ vault, @@ -47,7 +47,7 @@ export const Withdraw = ({ const isSelectedTokenYieldToken = token.address.toLowerCase() === yieldTokenData.address.toLowerCase(); - const { isApprovalNeeded, writeApprove, writeWithdraw, isFetching } = + const { isApprovalNeeded, writeApprove, writeWithdraw, isPending } = useWithdraw({ vault, selectedToken: token, @@ -55,15 +55,16 @@ export const Withdraw = ({ slippage, yieldToken: yieldTokenData, setAmount, + isSelectedTokenYieldToken, }); - const onCtaClick = useCallback(() => { + const onCtaClick = () => { if (isApprovalNeeded === true) { writeApprove(); } else { writeWithdraw(); } - }, [isApprovalNeeded, writeApprove, writeWithdraw]); + }; const onSelectChange = (value: string) => { setAmount(""); @@ -121,18 +122,18 @@ export const Withdraw = ({ )}{" "} {vault.alchemist.synthType}

- + ); diff --git a/src/hooks/useAllowance.ts b/src/hooks/useAllowance.ts index b26fca0b..f779bef2 100644 --- a/src/hooks/useAllowance.ts +++ b/src/hooks/useAllowance.ts @@ -38,7 +38,8 @@ export const useAllowance = ({ const { data: allowanceData, queryKey: isApprovalNeededQueryKey, - isFetching, + isPending: isPendingAllowance, + isFetching: isFetchingAllowance, } = useReadContract({ address: tokenAddress, abi: erc20Abi, @@ -57,29 +58,33 @@ export const useAllowance = ({ const { isApprovalNeeded, allowance } = allowanceData ?? {}; - const { data: approveConfig } = useSimulateContract({ - address: tokenAddress, - abi: erc20Abi, - functionName: "approve", - chainId: chain.id, - args: [ - spender, - isInfiniteApproval ? MAX_UINT256_BN : parseUnits(amount, decimals), - ], - query: { - enabled: - !isInputZero(amount) && - !!address && - isApprovalNeeded === true && - tokenAddress !== GAS_ADDRESS && - tokenAddress?.toLowerCase() !== USDT_MAINNET_ADDRESS.toLowerCase(), - }, - }); + const { data: approveConfig, isPending: isPendingApproveConfigToken } = + useSimulateContract({ + address: tokenAddress, + abi: erc20Abi, + functionName: "approve", + chainId: chain.id, + args: [ + spender, + isInfiniteApproval ? MAX_UINT256_BN : parseUnits(amount, decimals), + ], + query: { + enabled: + !isInputZero(amount) && + !!address && + isApprovalNeeded === true && + tokenAddress !== GAS_ADDRESS && + tokenAddress?.toLowerCase() !== USDT_MAINNET_ADDRESS.toLowerCase(), + }, + }); /** USDT on Ethereum doesn't follow ERC20 standard. * https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code#L199 */ - const { data: approveUsdtEthConfig } = useSimulateContract({ + const { + data: approveUsdtEthConfig, + isPending: isPendingApproveConfigUsdtEth, + } = useSimulateContract({ address: tokenAddress, abi: parseAbi(["function approve(address _spender, uint _value) public"]), functionName: "approve", @@ -116,11 +121,21 @@ export const useAllowance = ({ } }, [approvalReceipt, isApprovalNeededQueryKey, resetApprove, queryClient]); + const isPending = (() => { + if (isApprovalNeeded) { + if (tokenAddress?.toLowerCase() === USDT_MAINNET_ADDRESS.toLowerCase()) { + return isPendingApproveConfigUsdtEth || isPendingAllowance; + } + return isPendingApproveConfigToken || isPendingAllowance; + } else return isPendingAllowance; + })(); + return { isApprovalNeeded, approve, approveConfig, approveUsdtEthConfig, - isFetching, + isPending, + isFetching: isFetchingAllowance, }; }; diff --git a/src/hooks/useStaticTokenAdapterWithdraw.ts b/src/hooks/useStaticTokenAdapterWithdraw.ts new file mode 100644 index 00000000..93c6e018 --- /dev/null +++ b/src/hooks/useStaticTokenAdapterWithdraw.ts @@ -0,0 +1,97 @@ +import { keepPreviousData } from "@tanstack/react-query"; +import { useReadContract } from "wagmi"; +import { formatUnits, parseUnits } from "viem"; + +import { staticTokenAdapterAbi } from "@/abi/staticTokenAdapter"; +import { Token, Vault } from "@/lib/types"; +import { isInputZero } from "@/utils/inputNotZero"; +import { useChain } from "./useChain"; + +interface UseStaticTokenAdapterWithdrawAmountArgs { + typeGuard: "withdrawInput"; + + balanceForYieldToken: string | undefined; + isSelectedTokenYieldToken: boolean; + vault: Vault; + + amount?: never; + selectedToken?: never; +} + +interface UseStaticTokenAdapterAdjustedAmountArgs { + typeGuard: "adjustedAmount"; + + amount: string; + selectedToken: Token; + vault: Vault; + isSelectedTokenYieldToken: boolean; + + balanceForYieldToken?: never; +} + +type UseStaticTokenAdapterWithdrawArgs = + | UseStaticTokenAdapterWithdrawAmountArgs + | UseStaticTokenAdapterAdjustedAmountArgs; + +/** + * Adjusted for Aave static token adapter. + * Aim is to get the exact amount of yield token user wants to withdraw. + * We use it in withdraw input to adjust available balance to dynamic aave yield tokens. + * We use it in useWithdraw to adjust amount back to static amount for static token adapter. + * @dev It is safe to assume that static adapter has same decimals as yield token (it inherits from it). + */ +export const useStaticTokenAdapterWithdraw = ({ + typeGuard, + balanceForYieldToken, + isSelectedTokenYieldToken, + vault, + amount, + selectedToken, +}: UseStaticTokenAdapterWithdrawArgs) => { + const chain = useChain(); + + const { data: balanceForYieldTokenAdapter } = useReadContract({ + address: vault.yieldToken, + chainId: chain.id, + abi: staticTokenAdapterAbi, + functionName: "staticToDynamicAmount", + args: [ + parseUnits(balanceForYieldToken ?? "0", vault.yieldTokenParams.decimals), + ], + query: { + enabled: + vault.metadata.api.provider === "aave" && + typeGuard === "withdrawInput" && + balanceForYieldToken !== undefined && + isSelectedTokenYieldToken && + !!vault.metadata.yieldTokenOverride, + select: (balance) => + formatUnits(balance, vault.yieldTokenParams.decimals), + placeholderData: keepPreviousData, + }, + }); + + const { data: aaveAdjustedAmount } = useReadContract({ + address: vault.yieldToken, + abi: staticTokenAdapterAbi, + functionName: "dynamicToStaticAmount", + args: [ + typeGuard === "adjustedAmount" + ? parseUnits(amount, selectedToken.decimals) + : 0n, + ], + query: { + enabled: + vault.metadata.api.provider === "aave" && + typeGuard === "adjustedAmount" && + !isInputZero(amount) && + isSelectedTokenYieldToken && + !!vault.metadata.yieldTokenOverride, + }, + }); + + return { + balanceForYieldTokenAdapter, + aaveAdjustedAmount, + }; +}; diff --git a/src/hooks/useWatchQuery.ts b/src/hooks/useWatchQuery.ts index a5cff824..1947f0cf 100644 --- a/src/hooks/useWatchQuery.ts +++ b/src/hooks/useWatchQuery.ts @@ -1,19 +1,16 @@ import { useEffect } from "react"; -import { QueryKey, useQueryClient } from "@tanstack/react-query"; +import { useQueryClient } from "@tanstack/react-query"; import { useBlockNumber } from "wagmi"; + import { useChain } from "./useChain"; +import { ScopeKey } from "@/lib/queries/queriesSchema"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; -export type UseWatchQueryArgs = - | { - queryKey: QueryKey; - queryKeys?: never; - } - | { - queryKeys: QueryKey[]; - queryKey?: never; - }; +interface UseWatchQueryArgs { + scopeKey: ScopeKey; +} -export const useWatchQuery = ({ queryKey, queryKeys }: UseWatchQueryArgs) => { +export const useWatchQuery = ({ scopeKey }: UseWatchQueryArgs) => { const queryClient = useQueryClient(); const chain = useChain(); const { data: blockNumber } = useBlockNumber({ @@ -21,14 +18,11 @@ export const useWatchQuery = ({ queryKey, queryKeys }: UseWatchQueryArgs) => { watch: true, }); useEffect(() => { - if (blockNumber) { - if (queryKey) { - queryClient.invalidateQueries({ queryKey }); - return; - } - queryKeys.forEach((key) => { - queryClient.invalidateQueries({ queryKey: key }); + if (document.visibilityState === "visible") { + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ query, scopeKey }), }); } - }, [blockNumber, chain.id, queryClient, queryKey, queryKeys]); + }, [blockNumber, chain.id, queryClient, scopeKey]); }; diff --git a/src/lib/config/metadataTypes.ts b/src/lib/config/metadataTypes.ts index d42956f6..785f494d 100644 --- a/src/lib/config/metadataTypes.ts +++ b/src/lib/config/metadataTypes.ts @@ -9,7 +9,7 @@ export interface TransmuterMetadata { address: Address; label: string; synthAsset: SynthAsset; - apyQueryUri: string; + aprQueryUri: string; } export type TransmutersMetadata = { @@ -47,6 +47,15 @@ export type VaultMessage = { learnMoreUrl?: string; }; +type ApiProvider = + | "meltedRewards" + | "aave" + | "yearn" + | "frax" + | "rocket" + | "vesper" + | "lido"; + export interface VaultMetadata { label: string; synthAssetType: SynthAsset; @@ -56,13 +65,19 @@ export interface VaultMetadata { api: { apr: AprFn; yieldType: string; - cacheKey: string; + provider: ApiProvider; bonus: BonusFn; }; disabledDepositTokens: Address[]; wethGateway?: Address; gateway?: Address; migrator?: Address; + /** + * This is the address of the actual yield (bearing for aave) token, + * the regular yield token address in this case becomes a (static token adapter for aave or staking token for yearn), + * that we use for the vaults. + * If it exists, means the vault is using (static token adapter for aave or staking token for yearn). + */ yieldTokenOverride?: Address; strategy?: string; beta?: boolean; diff --git a/src/lib/config/synths.ts b/src/lib/config/synths.ts index bb3f2c2c..3dd1abe0 100644 --- a/src/lib/config/synths.ts +++ b/src/lib/config/synths.ts @@ -1,4 +1,5 @@ import { SynthAssetMetadata } from "@/lib/config/metadataTypes"; +import { arbitrum, mainnet, optimism } from "viem/chains"; export const SYNTH_ASSETS = { ALUSD: "alUSD", @@ -17,3 +18,18 @@ export const SYNTH_ASSETS_METADATA = { icon: "/images/icons/aleth_med.svg", }, } as const satisfies SynthAssetMetadata; + +export const SYNTH_ASSETS_ADDRESSES = { + [mainnet.id]: { + [SYNTH_ASSETS.ALUSD]: "0xBC6DA0FE9aD5f3b0d58160288917AA56653660E9", + [SYNTH_ASSETS.ALETH]: "0x0100546F2cD4C9D97f798fFC9755E47865FF7Ee6", + }, + [optimism.id]: { + [SYNTH_ASSETS.ALUSD]: "0xCB8FA9a76b8e203D8C3797bF438d8FB81Ea3326A", + [SYNTH_ASSETS.ALETH]: "0x3E29D3A9316dAB217754d13b28646B76607c5f04", + }, + [arbitrum.id]: { + [SYNTH_ASSETS.ALUSD]: "0xCB8FA9a76b8e203D8C3797bF438d8FB81Ea3326A", + [SYNTH_ASSETS.ALETH]: "0x17573150d67d820542EFb24210371545a4868B03", + }, +} as const; diff --git a/src/lib/config/transmuters.ts b/src/lib/config/transmuters.ts index 48a34784..6eb0b079 100644 --- a/src/lib/config/transmuters.ts +++ b/src/lib/config/transmuters.ts @@ -9,35 +9,35 @@ export const TRANSMUTERS = { address: "0xA840C73a004026710471F727252a9a2800a5197F", synthAsset: SYNTH_ASSETS.ALUSD, label: "Zosimos", - apyQueryUri: "3890313", + aprQueryUri: "3890313", }, //USDC { address: "0x49930AD9eBbbc0EB120CCF1a318c3aE5Bb24Df55", synthAsset: SYNTH_ASSETS.ALUSD, label: "Ge Hong", - apyQueryUri: "3861243", + aprQueryUri: "3861243", }, //USDT { address: "0xfC30820ba6d045b95D13a5B8dF4fB0E6B5bdF5b9", synthAsset: SYNTH_ASSETS.ALUSD, label: "Paracelsus", - apyQueryUri: "4026456", + aprQueryUri: "4026456", }, //FRAX { address: "0xE107Fa35D775C77924926C0292a9ec1FC14262b2", synthAsset: SYNTH_ASSETS.ALUSD, label: "Flamel", - apyQueryUri: "3989525", + aprQueryUri: "3989525", }, //WETH { address: "0x03323143a5f0D0679026C2a9fB6b0391e4D64811", synthAsset: SYNTH_ASSETS.ALETH, label: "Van Helmont", - apyQueryUri: "3849355", + aprQueryUri: "3849355", }, ], [fantom.id]: [ @@ -46,21 +46,21 @@ export const TRANSMUTERS = { address: "0x486FCC9385dCd16fE9ac21a959B072dcB58912e0", synthAsset: SYNTH_ASSETS.ALUSD, label: "Zosimos", - apyQueryUri: "", + aprQueryUri: "", }, //USDC { address: "0xaE653176d1AF6A68B5ce57481427a065E1baC49f", synthAsset: SYNTH_ASSETS.ALUSD, label: "Ge Hong", - apyQueryUri: "", + aprQueryUri: "", }, //USDT { address: "0x53F05426D48E667c6a131F17db1b6f7AC535aBC6", synthAsset: SYNTH_ASSETS.ALUSD, label: "Paracelsus", - apyQueryUri: "", + aprQueryUri: "", }, ], [optimism.id]: [ @@ -69,28 +69,28 @@ export const TRANSMUTERS = { address: "0xFCD619923456E20EAe298B35E3606277b391BBB4", synthAsset: SYNTH_ASSETS.ALUSD, label: "Zosimos", - apyQueryUri: "4026735", + aprQueryUri: "4026735", }, //USDC { address: "0xA7ea9ef9E2b5e15971040230F5d6b75C68Aab723", synthAsset: SYNTH_ASSETS.ALUSD, label: "Ge Hong", - apyQueryUri: "", + aprQueryUri: "", }, //USDT { address: "0x4e7d2115E4FeEcD802c96E77B8e03D98104415fa", synthAsset: SYNTH_ASSETS.ALUSD, label: "Paracelsus", - apyQueryUri: "", + aprQueryUri: "", }, //ETH { address: "0xb7C4250f83289ff3Ea9f21f01AAd0b02fb19491a", synthAsset: SYNTH_ASSETS.ALETH, label: "Van Helmont", - apyQueryUri: "3862748", + aprQueryUri: "3862748", }, ], [arbitrum.id]: [ @@ -99,28 +99,28 @@ export const TRANSMUTERS = { address: "0xD6a5577c2f6200591Fe077E45861B24AeeB408e9", synthAsset: SYNTH_ASSETS.ALUSD, label: "Zosimos", - apyQueryUri: "", + aprQueryUri: "", }, //USDC { address: "0xe7ec71B894583E9C1b07873fA86A7e81f3940eA8", synthAsset: SYNTH_ASSETS.ALUSD, label: "Ge Hong", - apyQueryUri: "3947029", + aprQueryUri: "3947029", }, //USDT { address: "0x2a8B5F365Fb29C3E1a40a5cd14AD7f89050755Ed", synthAsset: SYNTH_ASSETS.ALUSD, label: "Paracelsus", - apyQueryUri: "", + aprQueryUri: "", }, //ETH { address: "0x1EB7D78d7f6D73e5de67Fa62Fd8b55c54Aa9c0D4", synthAsset: SYNTH_ASSETS.ALETH, label: "Van Helmont", - apyQueryUri: "3888361", + aprQueryUri: "3888361", }, ], } as const satisfies TransmutersMetadata; diff --git a/src/lib/config/vaults.ts b/src/lib/config/vaults.ts index 47ee963b..3cb6a9f9 100644 --- a/src/lib/config/vaults.ts +++ b/src/lib/config/vaults.ts @@ -48,7 +48,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -63,7 +63,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -78,7 +78,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -94,7 +94,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getAaveBonusData, }, disabledDepositTokens: [], @@ -110,7 +110,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getAaveBonusData, }, disabledDepositTokens: [], @@ -126,7 +126,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getAaveBonusData, }, disabledDepositTokens: [], @@ -141,7 +141,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -156,7 +156,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getVesperApr, yieldType: "APR", - cacheKey: "vesper", + provider: "vesper", bonus: getVesperBonusData, }, disabledDepositTokens: [], @@ -171,7 +171,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getVesperApr, yieldType: "APR", - cacheKey: "vesper", + provider: "vesper", bonus: getVesperBonusData, }, disabledDepositTokens: [], @@ -186,7 +186,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getVesperApr, yieldType: "APR", - cacheKey: "vesper", + provider: "vesper", bonus: getVesperBonusData, }, disabledDepositTokens: [], @@ -202,7 +202,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getAaveBonusData, }, disabledDepositTokens: [], @@ -219,7 +219,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -236,7 +236,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getLidoApy, yieldType: "APR", - cacheKey: "lido", + provider: "lido", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -252,7 +252,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getRocketApr, yieldType: "APR", - cacheKey: "rocket", + provider: "rocket", bonus: getNoBonus, }, disabledDepositTokens: [GAS_ADDRESS, WETH_MAINNET_ADDRESS], @@ -269,7 +269,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getAaveBonusData, }, disabledDepositTokens: [], @@ -285,7 +285,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getVesperApr, yieldType: "APR", - cacheKey: "vesper", + provider: "vesper", bonus: getVesperBonusData, }, disabledDepositTokens: [], @@ -300,7 +300,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getFraxApy, yieldType: "APR", - cacheKey: "frax", + provider: "frax", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -317,7 +317,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -331,7 +331,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -345,7 +345,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -364,7 +364,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -381,7 +381,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], @@ -397,7 +397,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -420,7 +420,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "meltedRewards", + provider: "meltedRewards", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], @@ -443,7 +443,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "yearn", + provider: "yearn", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -462,7 +462,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getNoBonus, }, disabledDepositTokens: [], @@ -478,7 +478,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getLidoApy, yieldType: "APR", - cacheKey: "meltedRewards", + provider: "meltedRewards", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], @@ -502,7 +502,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getYearnApy, yieldType: "APY", - cacheKey: "meltedRewards", + provider: "meltedRewards", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], @@ -521,7 +521,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getAaveApr, yieldType: "APR", - cacheKey: "aave", + provider: "aave", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], @@ -537,7 +537,7 @@ export const VAULTS: VaultsConfig = { api: { apr: getLidoApy, yieldType: "APR", - cacheKey: "lido", + provider: "lido", bonus: getMeltedRewardsBonusData, }, disabledDepositTokens: [], diff --git a/src/lib/constants.ts b/src/lib/constants.ts index acdc6fc4..09ee0d08 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -4,15 +4,19 @@ export const GAS_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; // Time constants export const ONE_MINUTE_IN_MS = 60 * 1000; export const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000; +export const FIVE_MIN_IN_MS = 300000; -// Addresses used in the app. These are the addresses of the contracts on the Ethereum mainnet, -// so we do not create chain mappings for them. +// Addresses used in the app export const DELEGATE_REGISTRY_ADDRESS = "0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446"; export const WETH_MAINNET_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; export const ALCX_MAINNET_ADDRESS = "0xdBdb4d16EdA451D0503b854CF79D55697F90c8DF"; +export const ALCX_ARBITRUM_ADDRESS = + "0x27b58D226fe8f792730a795764945Cf146815AA7"; +export const ALCX_OPTIMISM_ADDRESS = + "0xE974B9b31dBFf4369b94a1bAB5e228f35ed44125"; export const G_ALCX_MAINNET_ADDRESS = "0x93Dede06AE3B5590aF1d4c111BC54C3f717E4b35"; export const SUSHI_MAINNET_ADDRESS = diff --git a/src/lib/localStorage.ts b/src/lib/localStorage.ts index 932b349e..b81c39c0 100644 --- a/src/lib/localStorage.ts +++ b/src/lib/localStorage.ts @@ -7,9 +7,13 @@ import { Token } from "@/lib/types"; interface LocalStorageSchema { tokenListCache: { tokens: Token[]; timestamp: number }; + tenderlyForkRpc: string; tenderlyForkChainId: number; + theme: "dark" | "light"; + + currency: "USD" | "ETH"; } /** diff --git a/src/lib/middleware/bonuses.ts b/src/lib/middleware/bonuses.ts index 2e906ea5..2150d02f 100644 --- a/src/lib/middleware/bonuses.ts +++ b/src/lib/middleware/bonuses.ts @@ -1,5 +1,4 @@ import { fantom, mainnet, optimism } from "viem/chains"; -import { getTokenPriceInEth } from "@/lib/queries/useTokenPrice"; import { formatEther, formatUnits } from "viem"; import { rewardRouterAbi } from "@/abi/rewardRouter"; import { @@ -12,6 +11,11 @@ import { getAaveReserves } from "./aave"; import { getVesperReserves } from "./vesper"; import { alchemistV2Abi } from "@/abi/alchemistV2"; import { dayjs } from "@/lib/dayjs"; +import { queryClient } from "@/components/providers/QueryProvider"; +import { + fetchPriceInEth, + useEthPriceQueryOptions, +} from "../queries/useTokenPrice"; const SPY = 31536000; @@ -29,14 +33,19 @@ export const getAaveBonusData: BonusFn = async ({ chainId, vault }) => { (reward) => reward.emissionsPerSecond !== "0", ), ); - const bonusYieldValue = await getTokenPriceInEth({ + + const ethPrice = await queryClient.ensureQueryData(useEthPriceQueryOptions); + + const bonusYieldValue = await fetchPriceInEth({ chainId, tokenAddress: "0x4200000000000000000000000000000000000042", + ethPrice, }); const bonusYieldTokenSymbol = "OP"; - const tokenPriceInEth = await getTokenPriceInEth({ + const tokenPriceInEth = await fetchPriceInEth({ chainId, tokenAddress: vault.underlyingToken, + ethPrice, }); const emissionsPerSecond = @@ -68,7 +77,7 @@ export const getVesperBonusData: BonusFn = async ({ vault }) => { (reserve) => reserve.address.toLowerCase() === vault.address.toLowerCase(), ); const bonusYieldTokenSymbol = "VSP"; - const bonusYieldRate = (vesperVault?.tokenDeltaRates?.["30"] ?? 0) * 100; + const bonusYieldRate = vesperVault?.tokenDeltaRates?.["30"] ?? 0; const hasBonus = true; return { hasBonus, @@ -107,13 +116,17 @@ export const getMeltedRewardsBonusData: BonusFn = async ({ const distributionTimeUnit = distributionTimeAmount > 1 ? "days" : "day"; - const bonusYieldValue = await getTokenPriceInEth({ + const ethPrice = await queryClient.ensureQueryData(useEthPriceQueryOptions); + + const bonusYieldValue = await fetchPriceInEth({ chainId, tokenAddress: REWARD_TOKENS[chainId].rewardTokenAddress, + ethPrice, }); - const tokenPriceInEth = await getTokenPriceInEth({ + const tokenPriceInEth = await fetchPriceInEth({ chainId, tokenAddress: vault.underlyingToken, + ethPrice, }); let bonusYieldRate = 0; diff --git a/src/lib/mutations/useDeposit.ts b/src/lib/mutations/useDeposit.ts index 34a2ad1a..c460b6e5 100644 --- a/src/lib/mutations/useDeposit.ts +++ b/src/lib/mutations/useDeposit.ts @@ -5,7 +5,7 @@ import { useAllowance } from "@/hooks/useAllowance"; import { useChain } from "@/hooks/useChain"; import { Token, Vault } from "@/lib/types"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect } from "react"; import { toast } from "sonner"; import { parseUnits } from "viem"; import { @@ -17,9 +17,10 @@ import { } from "wagmi"; import { GAS_ADDRESS, MAX_UINT256_BN } from "@/lib/constants"; import { calculateMinimumOut } from "@/utils/helpers/minAmountWithSlippage"; -import { QueryKeys } from "../queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "../queries/queriesSchema"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; import { isInputZero } from "@/utils/inputNotZero"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const useDeposit = ({ vault, @@ -42,6 +43,13 @@ export const useDeposit = ({ setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.TokenInput, + }), + }); }, [queryClient, setAmount]); const { address } = useAccount(); @@ -73,6 +81,7 @@ export const useDeposit = ({ approveConfig, isApprovalNeeded, approveUsdtEthConfig, + isPending: isPendingAllowance, isFetching: isFetchingAllowance, } = useAllowance({ amount, @@ -84,7 +93,7 @@ export const useDeposit = ({ const { data: depositGatewayConfig, error: depositGatewayError, - isFetching: isDepositGatewayConfigFetching, + isPending: isDepositGatewayConfigPending, } = useSimulateContract({ address: vault.metadata.gateway, abi: aaveTokenGatewayAbi, @@ -126,7 +135,7 @@ export const useDeposit = ({ const { data: depositAlchemistConfig, error: depositAlchemistError, - isFetching: isDepositAlchemistConfigFetching, + isPending: isDepositAlchemistConfigPending, } = useSimulateContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -164,7 +173,7 @@ export const useDeposit = ({ const { data: depositGasConfig, error: depositGasError, - isFetching: isDepositGasConfigFetching, + isPending: isDepositGasConfigPending, } = useSimulateContract({ address: vault.metadata.wethGateway, abi: wethGatewayAbi, @@ -206,7 +215,7 @@ export const useDeposit = ({ const { data: depositUnderlyingConfig, error: depositUnderlyingError, - isFetching: isDepositUnderlyingConfigFetching, + isPending: isDepositUnderlyingConfigPending, } = useSimulateContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -374,7 +383,7 @@ export const useDeposit = ({ approveConfig?.request && approve(approveConfig.request); }, [approve, approveConfig, approveUsdtEthConfig]); - const isFetching = useMemo(() => { + const isPending = (() => { if (!amount) return; // deposit gateway if ( @@ -383,7 +392,9 @@ export const useDeposit = ({ !!vault.metadata.gateway && !!vault.metadata.yieldTokenOverride ) { - return isDepositGatewayConfigFetching || isFetchingAllowance; + if (isApprovalNeeded === false) { + return isDepositGatewayConfigPending; + } else return isPendingAllowance || isFetchingAllowance; } // deposit alchemist @@ -393,12 +404,14 @@ export const useDeposit = ({ !vault.metadata.gateway && !vault.metadata.yieldTokenOverride ) { - return isDepositAlchemistConfigFetching; + if (isApprovalNeeded === false) { + return isDepositAlchemistConfigPending; + } else return isPendingAllowance || isFetchingAllowance; } // deposit gas if (selectedToken.address === GAS_ADDRESS) { - return isDepositGasConfigFetching; + return isDepositGasConfigPending; } // if depositUnderlyingConfig is available, deposit using alchemist @@ -406,20 +419,11 @@ export const useDeposit = ({ selectedToken.address !== GAS_ADDRESS && selectedToken.address.toLowerCase() !== yieldToken.address.toLowerCase() ) { - return isDepositUnderlyingConfigFetching; + if (isApprovalNeeded === false) { + return isDepositUnderlyingConfigPending; + } else return isPendingAllowance || isFetchingAllowance; } - }, [ - amount, - isDepositAlchemistConfigFetching, - isDepositGasConfigFetching, - isDepositGatewayConfigFetching, - isDepositUnderlyingConfigFetching, - isFetchingAllowance, - selectedToken.address, - vault.metadata.gateway, - vault.metadata.yieldTokenOverride, - yieldToken.address, - ]); + })(); - return { writeDeposit, writeApprove, isApprovalNeeded, isFetching }; + return { writeDeposit, writeApprove, isApprovalNeeded, isPending }; }; diff --git a/src/lib/mutations/useMigrate.ts b/src/lib/mutations/useMigrate.ts index 2fda8ddf..78e21036 100644 --- a/src/lib/mutations/useMigrate.ts +++ b/src/lib/mutations/useMigrate.ts @@ -16,9 +16,10 @@ import { useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect } from "react"; import { toast } from "sonner"; import { SYNTH_ASSETS } from "../config/synths"; -import { QueryKeys } from "../queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "../queries/queriesSchema"; import { isInputZero } from "@/utils/inputNotZero"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const useMigrate = ({ currentVault, @@ -92,6 +93,8 @@ export const useMigrate = ({ const { data: isApprovalNeededWithdraw, + isPending: isPendingApprovalWithdraw, + isFetching: isFetchingApprovalWithdraw, queryKey: isApprovalNeededWithdrawQueryKey, } = useReadContract({ address: currentVault.alchemist.address, @@ -106,20 +109,24 @@ export const useMigrate = ({ }, }); - const { data: isApprovalNeededMint, queryKey: isApprovalNeededMintQueryKey } = - useReadContract({ - address: currentVault.alchemist.address, - abi: alchemistV2Abi, - chainId: chain.id, - functionName: "mintAllowance", - args: [address!, migratorToolAddress], - query: { - enabled: !!address, - select: (allowance) => - allowance === 0n || - (underlyingInDebt !== undefined && allowance < underlyingInDebt), - }, - }); + const { + data: isApprovalNeededMint, + isPending: isPendingApprovalMint, + isFetching: isFetchingApprovalMint, + queryKey: isApprovalNeededMintQueryKey, + } = useReadContract({ + address: currentVault.alchemist.address, + abi: alchemistV2Abi, + chainId: chain.id, + functionName: "mintAllowance", + args: [address!, migratorToolAddress], + query: { + enabled: !!address, + select: (allowance) => + allowance === 0n || + (underlyingInDebt !== undefined && allowance < underlyingInDebt), + }, + }); const { data: approveWithdrawConfig } = useSimulateContract({ address: currentVault.alchemist.address, @@ -138,6 +145,7 @@ export const useMigrate = ({ const { writeContract: writeWithdrawApprovePrepared, data: approveWithdrawHash, + reset: resetApproveWithdraw, } = useWriteContract({ mutation: mutationCallback({ action: "Approve withdraw", @@ -153,8 +161,14 @@ export const useMigrate = ({ queryClient.invalidateQueries({ queryKey: isApprovalNeededWithdrawQueryKey, }); + resetApproveWithdraw(); } - }, [approveWithdrawReceipt, isApprovalNeededWithdrawQueryKey, queryClient]); + }, [ + queryClient, + resetApproveWithdraw, + approveWithdrawReceipt, + isApprovalNeededWithdrawQueryKey, + ]); const { data: approveMintConfig } = useSimulateContract({ address: currentVault.alchemist.address, @@ -166,12 +180,15 @@ export const useMigrate = ({ }, }); - const { writeContract: writeMintApprovePrepared, data: approveMintHash } = - useWriteContract({ - mutation: mutationCallback({ - action: "Approve mint", - }), - }); + const { + writeContract: writeMintApprovePrepared, + data: approveMintHash, + reset: resetApproveMint, + } = useWriteContract({ + mutation: mutationCallback({ + action: "Approve mint", + }), + }); const { data: approveMintReceipt } = useWaitForTransactionReceipt({ hash: approveMintHash, @@ -182,12 +199,18 @@ export const useMigrate = ({ queryClient.invalidateQueries({ queryKey: isApprovalNeededMintQueryKey, }); + resetApproveMint(); } - }, [approveMintReceipt, isApprovalNeededMintQueryKey, queryClient]); + }, [ + resetApproveMint, + approveMintReceipt, + isApprovalNeededMintQueryKey, + queryClient, + ]); const { data: migrateConfig, - isFetching, + isPending: isPendingConfig, error: migrateConfigError, } = useSimulateContract({ address: migratorToolAddress, @@ -225,6 +248,13 @@ export const useMigrate = ({ setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.MigrateInput, + }), + }); } }, [migrateReceipt, chain.id, queryClient, setAmount]); @@ -271,12 +301,25 @@ export const useMigrate = ({ writeMigratePrepared, ]); + const isPending = (() => { + if (!amount) return; + if (isApprovalNeededWithdraw === false && isApprovalNeededMint === false) { + return isPendingConfig; + } + return ( + isPendingApprovalMint || + isPendingApprovalWithdraw || + isFetchingApprovalMint || + isFetchingApprovalWithdraw + ); + })(); + return { isApprovalNeededWithdraw, isApprovalNeededMint, writeWithdrawApprove, writeMintApprove, writeMigrate, - isFetching, + isPending, }; }; diff --git a/src/lib/mutations/useWithdraw.ts b/src/lib/mutations/useWithdraw.ts index f117f94e..05812f9b 100644 --- a/src/lib/mutations/useWithdraw.ts +++ b/src/lib/mutations/useWithdraw.ts @@ -3,7 +3,7 @@ import { alchemistV2Abi } from "@/abi/alchemistV2"; import { useChain } from "@/hooks/useChain"; import { Token, Vault } from "@/lib/types"; import { useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useEffect } from "react"; import { toast } from "sonner"; import { parseUnits } from "viem"; import { @@ -16,8 +16,11 @@ import { import { GAS_ADDRESS, MAX_UINT256_BN } from "@/lib/constants"; import { wethGatewayAbi } from "@/abi/wethGateway"; import { calculateMinimumOut } from "@/utils/helpers/minAmountWithSlippage"; -import { QueryKeys } from "@/lib/queries/queriesSchema"; +import { QueryKeys, ScopeKeys } from "@/lib/queries/queriesSchema"; import { useWriteContractMutationCallback } from "@/hooks/useWriteContractMutationCallback"; +import { isInputZero } from "@/utils/inputNotZero"; +import { useStaticTokenAdapterWithdraw } from "@/hooks/useStaticTokenAdapterWithdraw"; +import { invalidateWagmiUseQueryPredicate } from "@/utils/helpers/invalidateWagmiUseQueryPredicate"; export const useWithdraw = ({ vault, @@ -26,6 +29,7 @@ export const useWithdraw = ({ slippage, yieldToken, setAmount, + isSelectedTokenYieldToken, }: { amount: string; slippage: string; @@ -33,6 +37,7 @@ export const useWithdraw = ({ selectedToken: Token; yieldToken: Token; setAmount: (amount: string) => void; + isSelectedTokenYieldToken: boolean; }) => { const chain = useChain(); const queryClient = useQueryClient(); @@ -40,22 +45,41 @@ export const useWithdraw = ({ setAmount(""); queryClient.invalidateQueries({ queryKey: [QueryKeys.Alchemists] }); queryClient.invalidateQueries({ queryKey: [QueryKeys.Vaults] }); + queryClient.invalidateQueries({ + predicate: (query) => + invalidateWagmiUseQueryPredicate({ + query, + scopeKey: ScopeKeys.VaultWithdrawInput, + }), + }); }, [queryClient, setAmount]); const mutationCallback = useWriteContractMutationCallback(); const { address } = useAccount(); - const isSelectedTokenYieldToken = - selectedToken.address.toLowerCase() === yieldToken.address.toLowerCase(); + const { aaveAdjustedAmount } = useStaticTokenAdapterWithdraw({ + typeGuard: "adjustedAmount", + amount, + selectedToken, + vault, + isSelectedTokenYieldToken, + }); + + const withdrawAmount = + vault.metadata.api.provider === "aave" && + isSelectedTokenYieldToken && + !!vault.metadata.yieldTokenOverride + ? aaveAdjustedAmount + : parseUnits(amount, selectedToken.decimals); const { data: sharesFromYieldToken } = useReadContract({ address: vault.alchemist.address, abi: alchemistV2Abi, chainId: chain.id, functionName: "convertYieldTokensToShares", - args: [vault.yieldToken, parseUnits(amount, selectedToken.decimals)], + args: [vault.yieldToken, withdrawAmount ?? 0n], query: { - enabled: isSelectedTokenYieldToken, + enabled: isSelectedTokenYieldToken && !isInputZero(amount), }, }); @@ -66,7 +90,7 @@ export const useWithdraw = ({ functionName: "convertUnderlyingTokensToShares", args: [vault.yieldToken, parseUnits(amount, selectedToken.decimals)], query: { - enabled: !isSelectedTokenYieldToken, + enabled: !isSelectedTokenYieldToken && !isInputZero(amount), }, }); @@ -84,7 +108,8 @@ export const useWithdraw = ({ const { data: isApprovalNeededAaveGateway, queryKey: isApprovalNeededAaveGatewayQueryKey, - isFetching: isApprovalNeededAaveGatewayFetching, + isPending: isPendingApprovalAaveGateway, + isFetching: isFetchingApprovalAaveGateway, } = useReadContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -106,7 +131,8 @@ export const useWithdraw = ({ const { data: isApprovalNeededWethGateway, queryKey: isApprovalNeededWethGatewayQueryKey, - isFetching: isApprovalNeededWethGatewayFetching, + isPending: isPendingApprovalWethGateway, + isFetching: isFetchingApprovalWethGateway, } = useReadContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -185,7 +211,7 @@ export const useWithdraw = ({ const { data: withdrawGatewayConfig, error: withdrawGatewayError, - isFetching: isWithdrawGatewayConfigFetching, + isPending: isWithdrawGatewayConfigPending, } = useSimulateContract({ address: vault.metadata.gateway, abi: aaveTokenGatewayAbi, @@ -224,7 +250,7 @@ export const useWithdraw = ({ const { data: withdrawAlchemistConfig, error: withdrawAlchemistError, - isFetching: isWithdrawAlchemistConfigFetching, + isPending: isWithdrawAlchemistConfigPending, } = useSimulateContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -262,7 +288,7 @@ export const useWithdraw = ({ const { data: withdrawGasConfig, error: withdrawGasError, - isFetching: isWithdrawGasConfigFetching, + isPending: isWithdrawGasConfigPending, } = useSimulateContract({ address: vault.metadata.wethGateway, abi: wethGatewayAbi, @@ -306,7 +332,7 @@ export const useWithdraw = ({ const { data: withdrawUnderlyingConfig, error: withdrawUnderlyingError, - isFetching: isWithdrawUnderlyingConfigFetching, + isPending: isWithdrawUnderlyingConfigPending, } = useSimulateContract({ address: vault.alchemist.address, abi: alchemistV2Abi, @@ -480,7 +506,7 @@ export const useWithdraw = ({ yieldToken.address, ]); - const isFetching = useMemo(() => { + const isPending = (() => { if (!amount) return; // withdraw gateway if ( @@ -489,9 +515,10 @@ export const useWithdraw = ({ !!vault.metadata.gateway && !!vault.metadata.yieldTokenOverride ) { - return ( - isWithdrawGatewayConfigFetching || isApprovalNeededAaveGatewayFetching - ); + if (isApprovalNeededAaveGateway === false) { + return isWithdrawGatewayConfigPending; + } else + return isPendingApprovalAaveGateway || isFetchingApprovalAaveGateway; } // withdraw alchemist @@ -501,14 +528,15 @@ export const useWithdraw = ({ !vault.metadata.gateway && !vault.metadata.yieldTokenOverride ) { - return ( - isWithdrawAlchemistConfigFetching || isApprovalNeededWethGatewayFetching - ); + return isWithdrawAlchemistConfigPending; } // withdraw gas if (selectedToken.address === GAS_ADDRESS) { - return isWithdrawGasConfigFetching; + if (isApprovalNeededWethGateway === false) { + return isWithdrawGasConfigPending; + } else + return isPendingApprovalWethGateway || isFetchingApprovalWethGateway; } // withdraw underlying @@ -516,26 +544,14 @@ export const useWithdraw = ({ selectedToken.address !== GAS_ADDRESS && selectedToken.address.toLowerCase() !== yieldToken.address.toLowerCase() ) { - return isWithdrawUnderlyingConfigFetching; + return isWithdrawUnderlyingConfigPending; } - }, [ - amount, - isWithdrawAlchemistConfigFetching, - isWithdrawGasConfigFetching, - isWithdrawGatewayConfigFetching, - isWithdrawUnderlyingConfigFetching, - isApprovalNeededAaveGatewayFetching, - isApprovalNeededWethGatewayFetching, - selectedToken.address, - vault.metadata.gateway, - vault.metadata.yieldTokenOverride, - yieldToken.address, - ]); + })(); return { isApprovalNeeded, writeApprove, writeWithdraw, - isFetching, + isPending, }; }; diff --git a/src/lib/queries/queriesSchema.ts b/src/lib/queries/queriesSchema.ts index e6526b94..a7e8a6ef 100644 --- a/src/lib/queries/queriesSchema.ts +++ b/src/lib/queries/queriesSchema.ts @@ -13,12 +13,43 @@ export const QueryKeys = { Delegate: "delegate", TokenPrice: "tokenPrice", Transmuters: "transmuters", - TransmuterApy: "transmuter-apy", + TransmuterApr: "transmuter-apr", Apr: "apr", Migration: (v: string) => `migrate-${v}`, VotesForAddress: "votesForAddress", Farms: (type: "internal" | "sushi" | "curve") => `farms-${type}`, + ConnextSdk: ( + type: + | "relayerFee" + | "amountOut" + | "approval" + | "originTxSubgraph" + | "destinationTxSubgraph", + ) => `connextSdk-${type}`, } as const; +/** + * @name ScopeKeys + * @description This is the schema for wagmi hooks queries scope keys. + * @dev Wagmi will set `scopeKey` field of the params object (queryKey[1]) of the query key. + * We use this for watching the queries. + * This is a workaround because wagmi returns unstable query keys. + */ +export const ScopeKeys = { + TokenInput: "token-input", + BorrowInput: "borrow-input", + LiquidateInput: "liquidate-input", + MigrateInput: "migrate-input", + RepayInput: "repay-input", + TransmuterInput: "transmuter-input", + VaultWithdrawInput: "vault-withdraw-input", + DebtSelection: "debt-selection", + FarmContent: "farm-content", + CurveFarmContent: "curve-farm-content", + SushiFarmContent: "sushi-farm-content", + InternalFarmContent: "internal-farm-content", +} as const; +export type ScopeKey = (typeof ScopeKeys)[keyof typeof ScopeKeys]; + // TODO: We can split alchemists, vaults, tokens, transmuters etc into separate queries // With that we can fetch all using useQueries and invalidate exact instances when mutation happens. diff --git a/src/lib/queries/useTokenPrice.ts b/src/lib/queries/useTokenPrice.ts index 697c7010..cbcef951 100644 --- a/src/lib/queries/useTokenPrice.ts +++ b/src/lib/queries/useTokenPrice.ts @@ -1,10 +1,19 @@ +import { queryOptions, useQueries, useQuery } from "@tanstack/react-query"; +import { arbitrum, fantom, mainnet, optimism } from "viem/chains"; + import { SupportedChainId } from "@/lib/wagmi/wagmiConfig"; import { useChain } from "@/hooks/useChain"; -import { useQueries, useQuery } from "@tanstack/react-query"; -import { arbitrum, fantom, mainnet, optimism } from "viem/chains"; +import { useSettings } from "@/components/providers/SettingsProvider"; import { QueryKeys } from "./queriesSchema"; +import { SupportedCurrency } from "../types"; +import { FIVE_MIN_IN_MS, GAS_ADDRESS } from "../constants"; -const FIVE_MIN_IN_MS = 300000; +interface FetchPriceArgs { + chainId: SupportedChainId; + tokenAddress: `0x${string}` | undefined; + currency: SupportedCurrency; + ethPrice: number | undefined; +} const LLAMA_API_URL = "https://coins.llama.fi/prices/current/"; @@ -15,49 +24,80 @@ const chainIdToLlamaChainNameMapping = { [optimism.id]: "optimism", }; -const fetchPrice = async ( - chainId: SupportedChainId, - tokenAddress: `0x${string}` | undefined, -) => { - if (!tokenAddress) - throw new Error("UNEXPECTED: tokenAddress is undefined in fetchPrice"); - const chainToken = `${chainIdToLlamaChainNameMapping[chainId]}:${tokenAddress}`; - const response = await fetch(`${LLAMA_API_URL}${chainToken}`); - const data = (await response.json()) as { - coins: { - [key: string]: { - decimals: number; - symbol: string; - price: number; - timestamp: number; - confidence: number; +const wethMapping = { + [mainnet.id]: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + [arbitrum.id]: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", + [optimism.id]: "0x4200000000000000000000000000000000000006", +}; + +export const useEthPriceQueryOptions = queryOptions({ + queryKey: [QueryKeys.TokenPrice, LLAMA_API_URL], + queryFn: async () => { + const ethPriceRes = await fetch(`${LLAMA_API_URL}coingecko:ethereum`); + const ethPriceData = (await ethPriceRes.json()) as { + coins: { + [key: string]: { + decimals: number; + symbol: string; + price: number; + timestamp: number; + confidence: number; + }; }; }; - }; - return data.coins[chainToken].price; + const ethPrice = ethPriceData.coins["coingecko:ethereum"].price; + + return ethPrice; + }, + refetchInterval: FIVE_MIN_IN_MS, + staleTime: FIVE_MIN_IN_MS, +}); + +const useEthPrice = () => { + return useQuery(useEthPriceQueryOptions); }; export const useGetTokenPrice = (tokenAddress: `0x${string}` | undefined) => { + const { currency } = useSettings(); const chain = useChain(); + const { data: ethPrice } = useEthPrice(); + return useQuery({ - queryKey: [QueryKeys.TokenPrice, chain.id, tokenAddress], - queryFn: () => fetchPrice(chain.id, tokenAddress), - enabled: !!tokenAddress, + queryKey: [ + QueryKeys.TokenPrice, + currency, + chain.id, + ethPrice, + tokenAddress, + ], + queryFn: () => + fetchPrice({ chainId: chain.id, tokenAddress, currency, ethPrice }), + enabled: !!tokenAddress && !(ethPrice === undefined && currency === "ETH"), refetchInterval: FIVE_MIN_IN_MS, staleTime: FIVE_MIN_IN_MS, }); }; export const useGetMultipleTokenPrices = (addresses: `0x${string}`[] = []) => { + const { currency } = useSettings(); const chain = useChain(); + const { data: ethPrice } = useEthPrice(); + return useQueries({ queries: addresses.map((tokenAddress) => { return { - queryKey: [QueryKeys.TokenPrice, chain.id, tokenAddress], - queryFn: () => fetchPrice(chain.id, tokenAddress), - enabled: !!tokenAddress, + queryKey: [ + QueryKeys.TokenPrice, + currency, + ethPrice, + chain.id, + tokenAddress, + ], + queryFn: () => + fetchPrice({ chainId: chain.id, tokenAddress, currency, ethPrice }), + enabled: !!tokenAddress && ethPrice !== undefined, refetchInterval: FIVE_MIN_IN_MS, staleTime: FIVE_MIN_IN_MS, refetchOnWindowFocus: false, @@ -66,16 +106,39 @@ export const useGetMultipleTokenPrices = (addresses: `0x${string}`[] = []) => { }); }; -export const getTokenPriceInEth = async ({ +const fetchPrice = async ({ + chainId, + tokenAddress, + currency, + ethPrice, +}: FetchPriceArgs) => { + if (currency === "USD") { + return fetchPriceInUsd({ chainId, tokenAddress, ethPrice }); + } + return fetchPriceInEth({ chainId, tokenAddress, ethPrice }); +}; + +const fetchPriceInUsd = async ({ chainId, tokenAddress, + ethPrice, }: { chainId: SupportedChainId; - tokenAddress: `0x${string}`; + tokenAddress: `0x${string}` | undefined; + ethPrice: number | undefined; }) => { - const price = await fetchPrice(chainId, tokenAddress); - const ethPriceRes = await fetch(`${LLAMA_API_URL}coingecko:ethereum`); - const ethPriceData = (await ethPriceRes.json()) as { + if (!tokenAddress) + throw new Error("UNEXPECTED: tokenAddress is undefined in fetchPrice"); + if (ethPrice === undefined) + throw new Error("UNEXPECTED: ethPrice is undefined in fetchPrice"); + + if (isTokenIsEthOrWeth({ chainId, tokenAddress })) { + return ethPrice; + } + + const chainToken = `${chainIdToLlamaChainNameMapping[chainId]}:${tokenAddress}`; + const response = await fetch(`${LLAMA_API_URL}${chainToken}`); + const data = (await response.json()) as { coins: { [key: string]: { decimals: number; @@ -86,6 +149,47 @@ export const getTokenPriceInEth = async ({ }; }; }; - const ethPrice = ethPriceData.coins["coingecko:ethereum"].price; + return data.coins[chainToken].price; +}; + +export const fetchPriceInEth = async ({ + chainId, + tokenAddress, + ethPrice, +}: { + chainId: SupportedChainId; + tokenAddress: `0x${string}` | undefined; + ethPrice: number | undefined; +}) => { + if (!tokenAddress) + throw new Error("UNEXPECTED: tokenAddress is undefined in fetchPriceInEth"); + if (ethPrice === undefined) { + throw new Error("UNEXPECTED: ethPrice is undefined in fetchPriceInEth"); + } + + if (isTokenIsEthOrWeth({ chainId, tokenAddress })) { + return 1; + } + + const price = await fetchPriceInUsd({ chainId, tokenAddress, ethPrice }); return price / ethPrice; }; + +/** + * Check if token is ETH or WETH. + * In supported chains only fantom uses another native token (FTM) as gas. + * And we hardcode WETH to ETH. + */ +const isTokenIsEthOrWeth = ({ + tokenAddress, + chainId, +}: { + tokenAddress: `0x${string}`; + chainId: SupportedChainId; +}) => { + return ( + chainId !== fantom.id && + (tokenAddress === GAS_ADDRESS || + tokenAddress.toLowerCase() === wethMapping[chainId].toLowerCase()) + ); +}; diff --git a/src/lib/queries/useTokensQuery.ts b/src/lib/queries/useTokensQuery.ts index 86476e5f..3b7fc9b0 100644 --- a/src/lib/queries/useTokensQuery.ts +++ b/src/lib/queries/useTokensQuery.ts @@ -3,16 +3,21 @@ import { useQuery } from "@tanstack/react-query"; import { lsService } from "@/lib/localStorage"; import { useAlchemists } from "./useAlchemists"; import { VAULTS } from "@/lib/config/vaults"; -import { mainnet } from "viem/chains"; +import { arbitrum, mainnet, optimism } from "viem/chains"; import { erc20Abi, zeroAddress } from "viem"; import { useAccount, usePublicClient } from "wagmi"; import { Token } from "@/lib/types"; -import { GAS_ADDRESS, ONE_DAY_IN_MS } from "@/lib/constants"; +import { + ALCX_ARBITRUM_ADDRESS, + ALCX_MAINNET_ADDRESS, + ALCX_OPTIMISM_ADDRESS, + GAS_ADDRESS, + G_ALCX_MAINNET_ADDRESS, + ONE_DAY_IN_MS, +} from "@/lib/constants"; import { wagmiConfig } from "@/lib/wagmi/wagmiConfig"; import { QueryKeys } from "./queriesSchema"; -const gALCXAddress = "0x93Dede06AE3B5590aF1d4c111BC54C3f717E4b35"; - export const useTokensQuery = () => { const { address: userAddress = zeroAddress } = useAccount(); const chain = useChain(); @@ -43,7 +48,14 @@ export const useTokensQuery = () => { .filter((token) => token !== undefined) as `0x${string}`[]; tokensAddresses.push(...tokensAddressesFromVaultOverries); if (chain.id === mainnet.id) { - tokensAddresses.push(gALCXAddress); + tokensAddresses.push(G_ALCX_MAINNET_ADDRESS); + tokensAddresses.push(ALCX_MAINNET_ADDRESS); + } + if (chain.id === arbitrum.id) { + tokensAddresses.push(ALCX_ARBITRUM_ADDRESS); + } + if (chain.id === optimism.id) { + tokensAddresses.push(ALCX_OPTIMISM_ADDRESS); } const calls = tokensAddresses.flatMap( diff --git a/src/lib/types.ts b/src/lib/types.ts index 63e3981c..5ee2bd78 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -7,6 +7,8 @@ export type Mutable = { -readonly [P in keyof T]: T[P]; }; +export type SupportedCurrency = "USD" | "ETH"; + export type TokenAdapter = { price: bigint; underlyingToken: Address; diff --git a/src/main.tsx b/src/main.tsx index be28728e..77487fb0 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -6,6 +6,7 @@ import { Web3Provider } from "@/components/providers/Web3Provider"; import { QueryProvider } from "@/components/providers/QueryProvider"; import { FramerMotionProvider } from "@/components/providers/FramerMotionProvider"; import { ThemeProvider } from "@/components/providers/ThemeProvider"; +import { SettingsProvider } from "@/components/providers/SettingsProvider"; // Import the generated route tree import { routeTree } from "@/routeTree.gen"; @@ -27,13 +28,15 @@ if (!rootElement.innerHTML) { root.render( - - - - - - - + + + + + + + + + , ); diff --git a/src/routes/bridge.lazy.tsx b/src/routes/bridge.lazy.tsx index 28703ea4..13b97800 100644 --- a/src/routes/bridge.lazy.tsx +++ b/src/routes/bridge.lazy.tsx @@ -1,7 +1,6 @@ import { createLazyFileRoute } from "@tanstack/react-router"; import { Page } from "@/components/common/Page"; -import { Button } from "@/components/ui/button"; -import { windowOpen } from "@/utils/windowOpen"; +import { Bridge } from "@/components/bridge/Bridge"; import { ErrorComponent } from "@/components/error/ErrorComponent"; export const Route = createLazyFileRoute("/bridge")({ @@ -16,42 +15,7 @@ function BridgeRoute() { description="Transfer your tokens to other chains" iconUri="/images/icons/swap_thin.svg" > -
-

We are integrating bridging into the Alchemix front end.

-

In the meantime, you may bridge directly through Connext:

-
- - - -
-
+ ); } diff --git a/src/routes/vaults.tsx b/src/routes/vaults.tsx index 72f69fd8..5d2048d1 100644 --- a/src/routes/vaults.tsx +++ b/src/routes/vaults.tsx @@ -15,7 +15,7 @@ function VaultsRoute() { diff --git a/src/utils/helpers/invalidateWagmiUseQueryPredicate.ts b/src/utils/helpers/invalidateWagmiUseQueryPredicate.ts new file mode 100644 index 00000000..ba5b7d02 --- /dev/null +++ b/src/utils/helpers/invalidateWagmiUseQueryPredicate.ts @@ -0,0 +1,20 @@ +import { ScopeKey } from "@/lib/queries/queriesSchema"; +import type { Query, QueryKey } from "@tanstack/react-query"; + +interface InvalidateWagmiUseQueryArgs { + query: Query; + scopeKey: ScopeKey; +} + +export const invalidateWagmiUseQueryPredicate = ({ + query, + scopeKey, +}: InvalidateWagmiUseQueryArgs) => { + const wagmiOptions = query.queryKey[1]; + return ( + typeof wagmiOptions === "object" && + !!wagmiOptions && + "scopeKey" in wagmiOptions && + wagmiOptions.scopeKey === scopeKey + ); +}; diff --git a/src/utils/number.test.ts b/src/utils/number.test.ts index 8b429084..3379e7e4 100644 --- a/src/utils/number.test.ts +++ b/src/utils/number.test.ts @@ -100,11 +100,24 @@ describe("Format number", () => { }); describe("Currency", () => { - it("Should format number with currency symbol", () => { + it("Should format number with $ symbol, if currency unset", () => { const amount = "1000"; const formatted = formatNumber(amount, { isCurrency: true }); expect(formatted).toBe("$1,000.00"); }); + it("Should format number with $ symbol, if currency set to USD", () => { + const amount = "1000"; + const formatted = formatNumber(amount, { isCurrency: true }); + expect(formatted).toBe("$1,000.00"); + }); + it("Should format number with currency name, if currency set to ETH", () => { + const amount = "1000"; + const formatted = formatNumber(amount, { + isCurrency: true, + currency: "ETH", + }); + expect(formatted).toBe("1,000.00 ETH"); + }); }); describe("Decimals", () => { diff --git a/src/utils/number.ts b/src/utils/number.ts index 319e0998..c786c2cb 100644 --- a/src/utils/number.ts +++ b/src/utils/number.ts @@ -1,6 +1,8 @@ import { from, toString, lessThan, equal, type Numberish } from "dnum"; import { parseUnits } from "viem"; +import { SupportedCurrency } from "@/lib/types"; + const subscriptMap: Record = { "0": "₀", "1": "₁", @@ -43,6 +45,7 @@ const enforceToDecimalString = (value: Numberish) => toString(from(value)); interface BaseFormatNumberOptions { decimals?: number; isCurrency?: boolean; + currency?: SupportedCurrency; allowNegative?: boolean; dustToZero?: boolean; tokenDecimals?: number; @@ -70,12 +73,17 @@ export function formatNumber( dustToZero = false, tokenDecimals = 18, compact = false, + currency = "USD", }: FormatNumberOptions = {}, ) { + const getManualFormat = (comparator?: string) => { + return `${isCurrency && currency === "USD" ? "$" : ""}${comparator ?? "0.00"}${isCurrency && currency === "ETH" ? " ETH" : ""}`; + }; + if (amount !== undefined && amount !== null && !!amount && !isNaN(+amount)) { // Negative numbers check if (!allowNegative && lessThan(amount, 0)) { - return `${isCurrency ? "$" : ""}0.00`; + return getManualFormat(); } // Dust to zero check @@ -86,7 +94,7 @@ export function formatNumber( tokenDecimals, ); if (lessThan(amountBigInt, 5n) || equal(amountBigInt, 5n)) { - return `${isCurrency ? "$" : ""}0.00`; + return getManualFormat(); } } catch (e) { console.error("Error parsing units", e); @@ -107,7 +115,6 @@ export function formatNumber( // Currency if (isCurrency) { - const currency = "USD"; intlOptions.style = "currency"; intlOptions.currency = currency; intlOptions.currencyDisplay = getDisplayCurrency(currency); @@ -121,7 +128,7 @@ export function formatNumber( // Small numbers if (+amount > 0 && +amount < comparator) { - const lessThanComparatorRepresentation = `< ${isCurrency ? "$" : ""}${comparator.toFixed(decimals)}`; + const lessThanComparatorRepresentation = `< ${getManualFormat(comparator.toFixed(decimals))}`; const numStr = enforceToDecimalString(amount); const match = numStr.match(/0\.0*(\d+)/); @@ -144,7 +151,7 @@ export function formatNumber( return formatter.format(+amount); } else { - return `${isCurrency ? "$" : ""}0.00`; + return getManualFormat(); } }